From a463721d88698be80c6282f28216002f15c43eab Mon Sep 17 00:00:00 2001 From: Sujal Bandhara Date: Fri, 18 May 2018 16:47:23 +0530 Subject: [PATCH 1/3] Wallofcoin Buying Wizard Added Wall of Coin Buying Wizard --- app/assets/countries.json | 172 +++++ app/build.gradle | 27 +- app/src/main/AndroidManifest.xml | 163 +++-- .../pivx/org/pivxwallet/PivxApplication.java | 2 + .../ui/base/BaseDrawerActivity.java | 67 +- .../ui/base/BaseRecyclerFragment.java | 17 + .../ui/qr_activity/MyAddressFragment.java | 8 +- .../TransactionsFragmentBase.java | 6 +- .../pivxwallet/wallofcoins/BuyDashPref.java | 134 ++++ .../pivxwallet/wallofcoins/CustomAdapter.java | 82 +++ .../pivxwallet/wallofcoins/WOCConstants.java | 60 ++ .../addressbook/AddressBookProvider.java | 246 +++++++ .../pivxwallet/wallofcoins/api/RestApi.java | 93 +++ .../wallofcoins/api/WallofCoins.java | 129 ++++ .../wallofcoins/binder/ImageBinder.java | 31 + .../buyingwizard/BuyDashBaseActivity.java | 275 ++++++++ .../buyingwizard/BuyDashBaseFragment.java | 302 ++++++++ .../adapters/BuyDashOffersAdapter.java | 281 ++++++++ .../adapters/OrderListAdapter.java | 269 +++++++ .../adapters/PhoneListAdapter.java | 68 ++ .../BuyDashLocationFragment.java | 516 ++++++++++++++ .../email_phone/EmailAndPhoneFragment.java | 657 ++++++++++++++++++ .../buyingwizard/models/AccountJson.java | 52 ++ .../buyingwizard/models/PhoneListVO.java | 31 + .../BuyDashOfferAmountFragment.java | 556 +++++++++++++++ .../order_history/OrderHistoryFragment.java | 617 ++++++++++++++++ .../BuyDashPaymentCenterFragment.java | 189 +++++ .../phone_list/PhoneListFragment.java | 152 ++++ .../utils/BuyDashAddressPref.java | 32 + .../utils/BuyDashPhoneListPref.java | 85 +++ .../buyingwizard/utils/FragmentUtils.java | 9 + .../buyingwizard/utils/ObjectSerializer.java | 52 ++ .../VerifycationOtpFragment.java | 238 +++++++ .../buyingwizard/zip/BuyDashZipFragment.java | 113 +++ .../response/BuyDashErrorResp.java | 10 + .../wallofcoins/response/CaptureHoldResp.java | 52 ++ .../wallofcoins/response/CheckAuthResp.java | 34 + .../response/ConfirmDepositResp.java | 204 ++++++ .../wallofcoins/response/CountryData.java | 33 + .../response/CreateDeviceResp.java | 38 + .../wallofcoins/response/CreateHoldResp.java | 38 + .../response/DiscoveryInputsResp.java | 45 ++ .../response/GetAuthTokenResp.java | 23 + .../wallofcoins/response/GetCurrencyResp.java | 16 + .../wallofcoins/response/GetHoldsResp.java | 19 + .../wallofcoins/response/GetOffersResp.java | 186 +++++ .../response/GetReceivingOptionsResp.java | 110 +++ .../wallofcoins/response/OrderListResp.java | 56 ++ .../response/PayFieldsDeserializer.java | 26 + .../selling_wizard/SellingBaseActivity.java | 127 ++++ .../selling_wizard/SellingBaseFragment.java | 171 +++++ .../adapters/AddressListAdapter.java | 54 ++ .../adapters/CountryAdapter.java | 82 +++ .../adapters/PhoneListAdapter.java | 69 ++ .../add_listing/AddressListingFragment.java | 112 +++ .../AdvanceOptionsFragment.java | 129 ++++ .../selling_wizard/api/RetrofitErrorUtil.java | 37 + .../selling_wizard/api/SellingAPIClient.java | 131 ++++ .../selling_wizard/api/SellingApi.java | 135 ++++ .../api/SellingApiConstants.java | 51 ++ .../cash_deposit/CashDepositFragment.java | 246 +++++++ .../selling_wizard/common/PhoneUtil.java | 81 +++ .../ContactDetailsFragment.java | 285 ++++++++ .../create_pass/CreatePasswordFragment.java | 81 +++ .../instruction/InstructionFragment.java | 142 ++++ .../models/AddressListRespVo.java | 170 +++++ .../selling_wizard/models/AddressVo.java | 281 ++++++++ .../selling_wizard/models/AuthVo.java | 84 +++ .../selling_wizard/models/CreateDeviceVo.java | 42 ++ .../models/GetReceivingOptionsResp.java | 110 +++ .../selling_wizard/models/MarketsVo.java | 113 +++ .../selling_wizard/models/PhoneListVO.java | 32 + .../models/SendVerificationRespVo.java | 12 + .../models/SignUpResponseVo.java | 73 ++ .../selling_wizard/models/VerifyAdResp.java | 13 + .../phone_list/PhoneListFragment.java | 367 ++++++++++ .../selling_wizard/price/PriceFragment.java | 273 ++++++++ .../selling_home/SellingHomeFragment.java | 175 +++++ .../sign_in/SignInFragment.java | 646 +++++++++++++++++ .../storage/SharedPreferenceUtil.java | 149 ++++ .../utils/BuyDashAddressPref.java | 32 + .../selling_wizard/utils/FragmentUtils.java | 9 + .../utils/ObjectSerializer.java | 52 ++ .../utils/SellingConstants.java | 18 + .../selling_wizard/utils/WOCLogUtil.java | 33 + .../VerifycationCodeFragment.java | 163 +++++ .../VerifySellingDetailsFragment.java | 249 +++++++ .../wallofcoins/ui/CurrencyAmountView.java | 363 ++++++++++ .../ui/CurrencySymbolDrawable.java | 67 ++ .../wallofcoins/ui/CurrencyTextView.java | 119 ++++ .../wallofcoins/ui/DividerItemDecoration.java | 96 +++ .../ui/ToolbarCurrencyTextView.java | 76 ++ .../wallofcoins/utils/Configuration.java | 301 ++++++++ .../wallofcoins/utils/Constants.java | 302 ++++++++ .../utils/CurrencyCalculatorLink.java | 209 ++++++ .../pivxwallet/wallofcoins/utils/Formats.java | 55 ++ .../wallofcoins/utils/GenericUtils.java | 38 + .../wallofcoins/utils/MonetarySpannable.java | 114 +++ .../wallofcoins/utils/NetworkUtil.java | 18 + app/src/main/res/anim/activity_back_out.xml | 7 + app/src/main/res/anim/activity_backin.xml | 7 + app/src/main/res/anim/activity_in.xml | 9 + app/src/main/res/anim/activity_out.xml | 7 + .../ic_account_balance_black_24dp.png | Bin 0 -> 216 bytes .../drawable-hdpi/ic_pin_drop_white_24dp.png | Bin 0 -> 435 bytes .../main/res/drawable-hdpi/wall_of_coins.png | Bin 0 -> 10780 bytes .../ic_account_balance_black_24dp.png | Bin 0 -> 156 bytes .../main/res/drawable-mdpi/wall_of_coins.png | Bin 0 -> 6795 bytes .../drawable-xhdpi/currency_symbol_btc.png | Bin 0 -> 3173 bytes .../drawable-xhdpi/currency_symbol_mbtc.png | Bin 0 -> 3422 bytes .../drawable-xhdpi/currency_symbol_ubtc.png | Bin 0 -> 728 bytes .../ic_account_balance_black_24dp.png | Bin 0 -> 235 bytes .../drawable-xhdpi/ic_pin_drop_white_24dp.png | Bin 0 -> 534 bytes .../main/res/drawable-xhdpi/wall_of_coins.png | Bin 0 -> 16707 bytes .../ic_account_balance_black_24dp.png | Bin 0 -> 290 bytes .../ic_pin_drop_white_24dp.png | Bin 0 -> 724 bytes .../res/drawable-xxhdpi/wall_of_coins.png | Bin 0 -> 26460 bytes .../ic_account_balance_black_24dp.png | Bin 0 -> 338 bytes .../res/drawable-xxxhdpi/wall_of_coins.png | Bin 0 -> 36571 bytes .../res/drawable/bg_selling_btn_selected.xml | 8 + .../drawable/bg_selling_btns_deselected.xml | 8 + .../res/drawable/border_selling_edttxt.xml | 8 + .../main/res/drawable/divider_currency.xml | 10 + app/src/main/res/drawable/download.png | Bin 0 -> 373 bytes app/src/main/res/drawable/flags.png | Bin 0 -> 77098 bytes .../main/res/drawable/ic_action_search.xml | 9 + .../res/drawable/ic_arrow_back_white_24dp.xml | 9 + .../res/drawable/ic_clear_grey600_24dp.xml | 9 + .../res/drawable/ic_dash_d_white_bottom.xml | 5 + .../main/res/drawable/ic_menu_sell_dash.xml | 89 +++ .../drawable/ic_more_vert_grey600_18dp.xml | 9 + app/src/main/res/drawable/ic_warning.xml | 9 + .../drawable/selectable_item_background.xml | 6 + .../main/res/drawable/selector_edit_btn.xml | 23 + .../res/drawable/selector_selling_btn.xml | 8 + .../drawable/stat_notify_received_24dp.xml | 8 + app/src/main/res/drawable/white_progress.xml | 23 + .../layout/activity_base_selling_wizard.xml | 17 + .../res/layout/activity_buy_dash_base.xml | 17 + .../main/res/layout/buy_dash_offers_item.xml | 177 +++++ .../layout/buy_dash_offers_item_double.xml | 109 +++ .../res/layout/dialog_selling_options.xml | 99 +++ app/src/main/res/layout/exchange_rate_row.xml | 114 +++ .../res/layout/exchange_rates_content.xml | 18 + .../res/layout/exchange_rates_fragment.xml | 34 + .../fragment_buy_dash_email_and_phone.xml | 158 +++++ .../res/layout/fragment_buy_dash_location.xml | 161 +++++ .../layout/fragment_buy_dash_offer_amount.xml | 155 +++++ .../fragment_buy_dash_order_history.xml | 135 ++++ .../fragment_buy_dash_payment_center.xml | 61 ++ .../layout/fragment_buy_dash_phone_list.xml | 51 ++ .../fragment_buy_dash_verification_otp.xml | 61 ++ .../main/res/layout/fragment_buy_dash_zip.xml | 67 ++ .../fragment_selling_address_listing.xml | 18 + .../layout/fragment_selling_cash_deposit.xml | 139 ++++ .../fragment_selling_contact_details.xml | 183 +++++ .../fragment_selling_create_password.xml | 85 +++ .../res/layout/fragment_selling_email.xml | 51 ++ .../main/res/layout/fragment_selling_home.xml | 121 ++++ .../layout/fragment_selling_instruction.xml | 336 +++++++++ .../res/layout/fragment_selling_mobile.xml | 43 ++ .../layout/fragment_selling_phone_list.xml | 54 ++ .../res/layout/fragment_selling_price.xml | 216 ++++++ .../res/layout/fragment_selling_signin.xml | 159 +++++ .../fragment_selling_verification_code.xml | 78 +++ .../fragment_selling_verify_details.xml | 138 ++++ app/src/main/res/layout/item_phone_list.xml | 14 + .../main/res/layout/item_selling_address.xml | 20 + .../main/res/layout/item_selling_country.xml | 28 + .../res/layout/item_selling_phone_list.xml | 13 + ...ut_authenticate_password_wallet_dialog.xml | 90 +++ .../res/layout/layout_item_order_list.xml | 266 +++++++ app/src/main/res/layout/my_address.xml | 29 +- .../main/res/layout/partial_buy_dash_top.xml | 125 ++++ .../res/layout/partial_selling_topbar.xml | 113 +++ .../main/res/layout/spinner_row_country.xml | 28 + .../main/res/menu/activity_main_drawer.xml | 11 +- .../main/res/menu/exchange_rates_context.xml | 12 + .../menu/exchange_rates_fragment_options.xml | 12 + app/src/main/res/values-hdpi/dimens.xml | 11 + app/src/main/res/values-xhdpi/dimens.xml | 11 + app/src/main/res/values/colors.xml | 22 + app/src/main/res/values/dimens.xml | 41 ++ app/src/main/res/values/strings-extra.xml | 287 ++++++++ app/src/main/res/values/styles.xml | 60 +- app/src/main/res/values/values.xml | 13 + 186 files changed, 17841 insertions(+), 99 deletions(-) create mode 100644 app/assets/countries.json create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/BuyDashPref.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/CustomAdapter.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/WOCConstants.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/addressbook/AddressBookProvider.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/api/RestApi.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/api/WallofCoins.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/binder/ImageBinder.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/BuyDashBaseActivity.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/BuyDashBaseFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/BuyDashOffersAdapter.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/OrderListAdapter.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/PhoneListAdapter.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/buy_dash_location/BuyDashLocationFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/email_phone/EmailAndPhoneFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/models/AccountJson.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/models/PhoneListVO.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/offer_amount/BuyDashOfferAmountFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/order_history/OrderHistoryFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/payment_center/BuyDashPaymentCenterFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/phone_list/PhoneListFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/BuyDashAddressPref.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/BuyDashPhoneListPref.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/FragmentUtils.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/ObjectSerializer.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/verification_otp/VerifycationOtpFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/zip/BuyDashZipFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/BuyDashErrorResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CaptureHoldResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CheckAuthResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/ConfirmDepositResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CountryData.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CreateDeviceResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CreateHoldResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/DiscoveryInputsResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetAuthTokenResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetCurrencyResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetHoldsResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetOffersResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetReceivingOptionsResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/OrderListResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/PayFieldsDeserializer.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/SellingBaseActivity.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/SellingBaseFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/AddressListAdapter.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/CountryAdapter.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/PhoneListAdapter.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/add_listing/AddressListingFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/advanced_options/AdvanceOptionsFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/RetrofitErrorUtil.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingAPIClient.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingApi.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingApiConstants.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/cash_deposit/CashDepositFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/common/PhoneUtil.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/contact_details/ContactDetailsFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/create_pass/CreatePasswordFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/instruction/InstructionFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AddressListRespVo.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AddressVo.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AuthVo.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/CreateDeviceVo.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/GetReceivingOptionsResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/MarketsVo.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/PhoneListVO.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/SendVerificationRespVo.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/SignUpResponseVo.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/VerifyAdResp.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/phone_list/PhoneListFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/price/PriceFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/selling_home/SellingHomeFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/sign_in/SignInFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/storage/SharedPreferenceUtil.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/BuyDashAddressPref.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/FragmentUtils.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/ObjectSerializer.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/SellingConstants.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/WOCLogUtil.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/verification_otp/VerifycationCodeFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/verify_details/VerifySellingDetailsFragment.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencyAmountView.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencySymbolDrawable.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencyTextView.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/DividerItemDecoration.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/ToolbarCurrencyTextView.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Configuration.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Constants.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/CurrencyCalculatorLink.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Formats.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/GenericUtils.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/MonetarySpannable.java create mode 100644 app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/NetworkUtil.java create mode 100644 app/src/main/res/anim/activity_back_out.xml create mode 100644 app/src/main/res/anim/activity_backin.xml create mode 100644 app/src/main/res/anim/activity_in.xml create mode 100644 app/src/main/res/anim/activity_out.xml create mode 100644 app/src/main/res/drawable-hdpi/ic_account_balance_black_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_pin_drop_white_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/wall_of_coins.png create mode 100644 app/src/main/res/drawable-mdpi/ic_account_balance_black_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/wall_of_coins.png create mode 100644 app/src/main/res/drawable-xhdpi/currency_symbol_btc.png create mode 100644 app/src/main/res/drawable-xhdpi/currency_symbol_mbtc.png create mode 100644 app/src/main/res/drawable-xhdpi/currency_symbol_ubtc.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_account_balance_black_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_pin_drop_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/wall_of_coins.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_account_balance_black_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_pin_drop_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/wall_of_coins.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_account_balance_black_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/wall_of_coins.png create mode 100644 app/src/main/res/drawable/bg_selling_btn_selected.xml create mode 100644 app/src/main/res/drawable/bg_selling_btns_deselected.xml create mode 100644 app/src/main/res/drawable/border_selling_edttxt.xml create mode 100644 app/src/main/res/drawable/divider_currency.xml create mode 100644 app/src/main/res/drawable/download.png create mode 100644 app/src/main/res/drawable/flags.png create mode 100644 app/src/main/res/drawable/ic_action_search.xml create mode 100644 app/src/main/res/drawable/ic_arrow_back_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_clear_grey600_24dp.xml create mode 100644 app/src/main/res/drawable/ic_dash_d_white_bottom.xml create mode 100644 app/src/main/res/drawable/ic_menu_sell_dash.xml create mode 100644 app/src/main/res/drawable/ic_more_vert_grey600_18dp.xml create mode 100644 app/src/main/res/drawable/ic_warning.xml create mode 100644 app/src/main/res/drawable/selectable_item_background.xml create mode 100644 app/src/main/res/drawable/selector_edit_btn.xml create mode 100644 app/src/main/res/drawable/selector_selling_btn.xml create mode 100644 app/src/main/res/drawable/stat_notify_received_24dp.xml create mode 100644 app/src/main/res/drawable/white_progress.xml create mode 100644 app/src/main/res/layout/activity_base_selling_wizard.xml create mode 100644 app/src/main/res/layout/activity_buy_dash_base.xml create mode 100644 app/src/main/res/layout/buy_dash_offers_item.xml create mode 100644 app/src/main/res/layout/buy_dash_offers_item_double.xml create mode 100644 app/src/main/res/layout/dialog_selling_options.xml create mode 100644 app/src/main/res/layout/exchange_rate_row.xml create mode 100644 app/src/main/res/layout/exchange_rates_content.xml create mode 100644 app/src/main/res/layout/exchange_rates_fragment.xml create mode 100644 app/src/main/res/layout/fragment_buy_dash_email_and_phone.xml create mode 100644 app/src/main/res/layout/fragment_buy_dash_location.xml create mode 100644 app/src/main/res/layout/fragment_buy_dash_offer_amount.xml create mode 100644 app/src/main/res/layout/fragment_buy_dash_order_history.xml create mode 100644 app/src/main/res/layout/fragment_buy_dash_payment_center.xml create mode 100644 app/src/main/res/layout/fragment_buy_dash_phone_list.xml create mode 100644 app/src/main/res/layout/fragment_buy_dash_verification_otp.xml create mode 100644 app/src/main/res/layout/fragment_buy_dash_zip.xml create mode 100644 app/src/main/res/layout/fragment_selling_address_listing.xml create mode 100644 app/src/main/res/layout/fragment_selling_cash_deposit.xml create mode 100644 app/src/main/res/layout/fragment_selling_contact_details.xml create mode 100644 app/src/main/res/layout/fragment_selling_create_password.xml create mode 100644 app/src/main/res/layout/fragment_selling_email.xml create mode 100644 app/src/main/res/layout/fragment_selling_home.xml create mode 100644 app/src/main/res/layout/fragment_selling_instruction.xml create mode 100644 app/src/main/res/layout/fragment_selling_mobile.xml create mode 100644 app/src/main/res/layout/fragment_selling_phone_list.xml create mode 100644 app/src/main/res/layout/fragment_selling_price.xml create mode 100644 app/src/main/res/layout/fragment_selling_signin.xml create mode 100644 app/src/main/res/layout/fragment_selling_verification_code.xml create mode 100644 app/src/main/res/layout/fragment_selling_verify_details.xml create mode 100644 app/src/main/res/layout/item_phone_list.xml create mode 100644 app/src/main/res/layout/item_selling_address.xml create mode 100644 app/src/main/res/layout/item_selling_country.xml create mode 100644 app/src/main/res/layout/item_selling_phone_list.xml create mode 100644 app/src/main/res/layout/layout_authenticate_password_wallet_dialog.xml create mode 100644 app/src/main/res/layout/layout_item_order_list.xml create mode 100644 app/src/main/res/layout/partial_buy_dash_top.xml create mode 100644 app/src/main/res/layout/partial_selling_topbar.xml create mode 100644 app/src/main/res/layout/spinner_row_country.xml create mode 100644 app/src/main/res/menu/exchange_rates_context.xml create mode 100644 app/src/main/res/menu/exchange_rates_fragment_options.xml create mode 100644 app/src/main/res/values-hdpi/dimens.xml create mode 100644 app/src/main/res/values-xhdpi/dimens.xml create mode 100644 app/src/main/res/values/strings-extra.xml create mode 100644 app/src/main/res/values/values.xml diff --git a/app/assets/countries.json b/app/assets/countries.json new file mode 100644 index 000000000..55f8b1e1d --- /dev/null +++ b/app/assets/countries.json @@ -0,0 +1,172 @@ +{ + "countries": [ + { + "name": "United States", + "code": "+1", + "currency": "USD", + "short": "us", + "top": 210, + "left": 210 + }, + { + "name": "United Kingdom", + "code": "+44", + "currency": "USD", + "short": "uk", + "top": 268, + "left": 132 + }, + { + "name": "Argentina", + "code": "+54", + "currency": "USD", + "short": "ar", + "top": 100, + "left": 194 + }, + { + "name": "Australia", + "code": "+61", + "currency": "USD", + "short": "au", + "top": 247, + "left": 33 + }, + { + "name": "Brazil", + "code": "+55", + "currency": "USD", + "short": "br", + "top": 63, + "left": 47 + }, + { + "name": "Canada", + "code": "+1", + "currency": "USD", + "short": "ca", + "top": 268, + "left": 55 + }, + { + "name": "China", + "code": "+86", + "currency": "USD", + "short": "cn", + "top": 105, + "left": 55 + }, + { + "name": "Germany", + "code": "+49", + "currency": "USD", + "short": "de", + "top": 42, + "left": 210 + }, + { + "name": "Ghana", + "code": "+233", + "currency": "USD", + "short": "gh", + "top": 105, + "left": 121 + }, + { + "name": "Hong Kong", + "code": "+852", + "currency": "USD", + "short": "hk", + "top": 147, + "left": 116 + }, + { + "name": "Latvia", + "code": "+371", + "currency": "USD", + "short": "lv", + "top": 147, + "left": 176 + }, + { + "name": "Malaysia", + "code": "+60", + "currency": "USD", + "short": "my", + "top": 268, + "left": 22 + }, + { + "name": "Mexico", + "code": "+52", + "currency": "USD", + "short": "mx", + "top": 268, + "left": 210 + }, + { + "name": "Nigeria", + "code": "+234", + "currency": "USD", + "short": "ng", + "top": 268, + "left": 110 + }, + { + "name": "Philippines", + "code": "+63", + "currency": "USD", + "short": "ph", + "top": 42, + "left": 234 + }, + { + "name": "Poland", + "code": "+48", + "currency": "USD", + "short": "pl", + "top": 142, + "left": 194 + }, + { + "name": "Portugal", + "code": "+351", + "currency": "USD", + "short": "pt", + "top": 147, + "left": 179 + }, + { + "name": "Romania", + "code": "+40", + "currency": "USD", + "short": "ro", + "top": 84, + "left": 179 + }, + { + "name": "Russia", + "code": "+7", + "currency": "USD", + "short": "ru", + "top": 189, + "left": 116 + }, + { + "name": "Singapore", + "code": "+65", + "currency": "USD", + "short": "sg", + "top": 168, + "left": 116 + }, + { + "name": "Spain", + "code": "+34", + "currency": "USD", + "short": "es", + "top": 123, + "left": 29 + } + ] +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index f2d5d59a9..9b6de08f4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,7 +18,9 @@ android { lintOptions { abortOnError false } - + dataBinding { + enabled = true + } dexOptions { javaMaxHeapSize "4g" } @@ -44,7 +46,14 @@ android { } + packagingOptions { + + exclude 'org/bitcoinj/crypto/mnemonic/wordlist/english.txt' + exclude 'org/bitcoinj/crypto/cacerts' + exclude 'org.bitcoin.production.checkpoints.txt' + exclude 'org.bitcoin.test.checkpoints.txt' + } } @@ -87,4 +96,20 @@ dependencies { testCompile 'org.json:json:20170516' testCompile 'org.apache.httpcomponents:httpclient:4.5.3' testCompile 'org.mockito:mockito-core:2.8.9' + + + //wall of coins + compile 'com.squareup.retrofit2:retrofit:2.0.2' + compile 'com.squareup.retrofit2:converter-gson:2.0.2' + compile 'com.squareup.okhttp3:logging-interceptor:3.3.1' + compile 'com.squareup.okhttp:logging-interceptor:2.7.5' + compile 'com.google.code.findbugs:jsr305:2.0.3' + compile 'org.dashj:dashj-core:0.14.4.3' + + + //selling dependencies + + compile 'com.github.joielechong:countrycodepicker:2.1.5' + } + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0c969e496..581aa4e8c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,95 +2,145 @@ - - - - - - - - + + + + + + + + - + android:theme="@style/AppTheme"> + - + - + android:screenOrientation="portrait"> - + - - - - - - - + + + + + + + - - - - - - + + + + + + - - + android:screenOrientation="portrait" /> + - + + + + + + + - - - - - - - + android:screenOrientation="portrait"> - - - + + + - - - + + + - @@ -106,6 +156,13 @@ android:resource="@xml/file_provider_paths" /> + + + diff --git a/app/src/main/java/pivx/org/pivxwallet/PivxApplication.java b/app/src/main/java/pivx/org/pivxwallet/PivxApplication.java index d3956fa4d..a919c2627 100644 --- a/app/src/main/java/pivx/org/pivxwallet/PivxApplication.java +++ b/app/src/main/java/pivx/org/pivxwallet/PivxApplication.java @@ -59,6 +59,7 @@ import static pivx.org.pivxwallet.service.IntentsConstants.ACTION_RESET_BLOCKCHAIN; import static pivx.org.pivxwallet.utils.AndroidUtils.shareText; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.storage.SharedPreferenceUtil; /** * Created by mati on 18/04/17. */ @@ -131,6 +132,7 @@ else if (logFileName.endsWith(".log")) public void onCreate() { super.onCreate(); instance = this; + SharedPreferenceUtil.init(getApplicationContext()); try { initLogging(); log = LoggerFactory.getLogger(PivxApplication.class); diff --git a/app/src/main/java/pivx/org/pivxwallet/ui/base/BaseDrawerActivity.java b/app/src/main/java/pivx/org/pivxwallet/ui/base/BaseDrawerActivity.java index e39cbef95..cdbb8568f 100644 --- a/app/src/main/java/pivx/org/pivxwallet/ui/base/BaseDrawerActivity.java +++ b/app/src/main/java/pivx/org/pivxwallet/ui/base/BaseDrawerActivity.java @@ -26,6 +26,8 @@ import pivx.org.pivxwallet.ui.donate.DonateActivity; import pivx.org.pivxwallet.ui.settings_activity.SettingsActivity; import pivx.org.pivxwallet.ui.wallet_activity.WalletActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; import static pivx.org.pivxwallet.module.PivxContext.OUT_OF_SYNC_TIME; import static pivx.org.pivxwallet.service.IntentsConstants.ACTION_NOTIFICATION; @@ -50,7 +52,7 @@ public class BaseDrawerActivity extends PivxActivity implements NavigationView.O private BroadcastReceiver walletServiceReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.hasExtra(INTENT_BROADCAST_DATA_TYPE)){ + if (intent.hasExtra(INTENT_BROADCAST_DATA_TYPE)) { if (intent.getStringExtra(INTENT_BROADCAST_DATA_TYPE).equals(INTENT_BROADCAST_DATA_BLOCKCHAIN_STATE)) { BlockchainState blockchainStateNew = (BlockchainState) intent.getSerializableExtra(INTENT_EXTRA_BLOCKCHAIN_STATE); onBlockchainStateChange(); @@ -60,7 +62,7 @@ public void onReceive(Context context, Intent intent) { } blockchainState = blockchainStateNew; updateBlockchainState(); - }else if(intent.getStringExtra(INTENT_BROADCAST_DATA_TYPE).equals(INTENT_BROADCAST_DATA_PEER_CONNECTED)){ + } else if (intent.getStringExtra(INTENT_BROADCAST_DATA_TYPE).equals(INTENT_BROADCAST_DATA_PEER_CONNECTED)) { checkState(); updateBlockchainState(); } @@ -91,39 +93,39 @@ protected void onCreate(Bundle savedInstanceState) { txt_app_version = (TextView) navigationView.findViewById(R.id.txt_app_version); txt_app_version.setText(BuildConfig.VERSION_NAME); - onCreateView(savedInstanceState,frameLayout); + onCreateView(savedInstanceState, frameLayout); - localBroadcastManager.registerReceiver(walletServiceReceiver,new IntentFilter(ACTION_NOTIFICATION)); + localBroadcastManager.registerReceiver(walletServiceReceiver, new IntentFilter(ACTION_NOTIFICATION)); } - private void checkState(){ + private void checkState() { long now = System.currentTimeMillis(); long lastBlockTime = pivxApplication.getAppConf().getLastBestChainBlockTime(); - if (lastBlockTime+OUT_OF_SYNC_TIME>now){ + if (lastBlockTime + OUT_OF_SYNC_TIME > now) { // check if i'm syncing or i'm synched long peerHeight = pivxModule.getConnectedPeerHeight(); - if (peerHeight!=-1){ - if (pivxModule.getChainHeight()+10>peerHeight) { + if (peerHeight != -1) { + if (pivxModule.getChainHeight() + 10 > peerHeight) { blockchainState = BlockchainState.SYNC; - }else { + } else { blockchainState = BlockchainState.SYNCING; } - }else { + } else { blockchainState = BlockchainState.NOT_CONNECTION; } - }else { + } else { if (pivxModule.isAnyPeerConnected()) { long peerHeight = pivxModule.getConnectedPeerHeight(); - if (peerHeight!=-1){ - if (pivxModule.getChainHeight()+10>peerHeight) { + if (peerHeight != -1) { + if (pivxModule.getChainHeight() + 10 > peerHeight) { blockchainState = BlockchainState.SYNC; - }else { + } else { blockchainState = BlockchainState.SYNCING; } - }else { + } else { blockchainState = BlockchainState.NOT_CONNECTION; } - }else { + } else { blockchainState = BlockchainState.NOT_CONNECTION; } } @@ -148,7 +150,7 @@ protected void onDestroy() { /** * Empty method to check some status before set the main layout of the activity */ - protected void beforeCreate(){ + protected void beforeCreate() { } @@ -157,7 +159,7 @@ protected void beforeCreate(){ * * @param savedInstanceState */ - protected void onCreateView(Bundle savedInstanceState, ViewGroup container){ + protected void onCreateView(Bundle savedInstanceState, ViewGroup container) { } @@ -192,13 +194,13 @@ public boolean onNavigationItemSelected(MenuItem item) { int id = item.getItemId(); //to prevent current item select over and over - if (item.isChecked()){ + if (item.isChecked()) { drawer.closeDrawer(GravityCompat.START); return false; } if (id == R.id.nav_wallet) { - Intent intent = new Intent(this,WalletActivity.class); + Intent intent = new Intent(this, WalletActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); finish(); @@ -206,23 +208,28 @@ public boolean onNavigationItemSelected(MenuItem item) { startActivity(new Intent(this, ContactsActivity.class)); } else if (id == R.id.nav_settings) { startActivity(new Intent(this, SettingsActivity.class)); - } else if (id == R.id.nav_donations){ + } else if (id == R.id.nav_donations) { startActivity(new Intent(this, DonateActivity.class)); - } + } else if (id == R.id.nav_buywithcash) { + startActivity(new Intent(this, BuyDashBaseActivity.class)); + } /*else if (id == R.id.nav_sell_piv) { + startActivity(new Intent(this, SellingBaseActivity.class)); + }*/ + drawer.closeDrawer(GravityCompat.START); return true; } - protected void setNavigationMenuItemChecked(int pos){ + protected void setNavigationMenuItemChecked(int pos) { navigationView.getMenu().getItem(pos).setChecked(true); } private void updateBlockchainState() { // Check if the activity is on foreground - if (!isOnForeground)return; + if (!isOnForeground) return; - if (txt_sync_status!=null) { + if (txt_sync_status != null) { String text = null; int color = 0; int imgSrc = 0; @@ -234,7 +241,7 @@ private void updateBlockchainState() { imgSrc = 0; break; case SYNCING: - text = getString(R.string.syncing)+" "+progress+"%"; + text = getString(R.string.syncing) + " " + progress + "%"; color = Color.parseColor("#f6a623"); imgSrc = R.drawable.ic_header_unsynced; break; @@ -246,21 +253,21 @@ private void updateBlockchainState() { } txt_sync_status.setText(text); txt_sync_status.setTextColor(color); - if (imgSrc!=0) { + if (imgSrc != 0) { img_sync.setImageResource(imgSrc); img_sync.setVisibility(View.VISIBLE); - }else + } else img_sync.setVisibility(View.INVISIBLE); } } private double calculateBlockchainSyncProgress() { long nodeHeight = pivxModule.getConnectedPeerHeight(); - if (nodeHeight>0){ + if (nodeHeight > 0) { // calculate the progress // nodeHeight -> 100 % // current height -> x % - return (pivxModule.getChainHeight()*100) / nodeHeight; + return (pivxModule.getChainHeight() * 100) / nodeHeight; } return -1; } diff --git a/app/src/main/java/pivx/org/pivxwallet/ui/base/BaseRecyclerFragment.java b/app/src/main/java/pivx/org/pivxwallet/ui/base/BaseRecyclerFragment.java index 76edbe438..d5d7d37ad 100644 --- a/app/src/main/java/pivx/org/pivxwallet/ui/base/BaseRecyclerFragment.java +++ b/app/src/main/java/pivx/org/pivxwallet/ui/base/BaseRecyclerFragment.java @@ -1,5 +1,6 @@ package pivx.org.pivxwallet.ui.base; +import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.support.v4.widget.SwipeRefreshLayout; @@ -21,6 +22,7 @@ import pivx.org.pivxwallet.R; import pivx.org.pivxwallet.ui.base.tools.adapter.BaseRecyclerAdapter; import pivx.org.pivxwallet.ui.base.tools.adapter.BaseRecyclerViewHolder; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; /** * Created by furszy on 6/20/17. @@ -75,6 +77,21 @@ public void onRefresh() { } } ); + + imgEmptyView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), BuyDashBaseActivity.class); + startActivity(intent); + } + }); + txt_empty.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), BuyDashBaseActivity.class); + startActivity(intent); + } + }); return root; } diff --git a/app/src/main/java/pivx/org/pivxwallet/ui/qr_activity/MyAddressFragment.java b/app/src/main/java/pivx/org/pivxwallet/ui/qr_activity/MyAddressFragment.java index 9958f95b4..b3338e93c 100644 --- a/app/src/main/java/pivx/org/pivxwallet/ui/qr_activity/MyAddressFragment.java +++ b/app/src/main/java/pivx/org/pivxwallet/ui/qr_activity/MyAddressFragment.java @@ -25,6 +25,7 @@ import pivx.org.pivxwallet.PivxApplication; import pivx.org.pivxwallet.R; import pivx.org.pivxwallet.module.PivxModule; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; import static android.graphics.Color.WHITE; import static pivx.org.pivxwallet.utils.AndroidUtils.copyToClipboard; @@ -41,7 +42,7 @@ public class MyAddressFragment extends Fragment implements View.OnClickListener private View root; private TextView txt_address; private Button btn_share; - private Button btn_copy; + private Button btn_copy,btn_buy; private ImageView img_qr; private Address address; @@ -62,7 +63,9 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, btn_copy = (Button) root.findViewById(R.id.btn_copy); btn_copy.setOnClickListener(this); img_qr = (ImageView) root.findViewById(R.id.img_qr); + btn_buy = (Button) root.findViewById(R.id.btn_buy); btn_share.setOnClickListener(this); + btn_buy.setOnClickListener(this); img_qr.setOnClickListener(this); return root; } @@ -132,5 +135,8 @@ public void onClick(View v) { copyToClipboard(getActivity(),address.toBase58()); Toast.makeText(v.getContext(), R.string.copy_message, Toast.LENGTH_LONG).show(); } + else if (id == R.id.btn_buy) { + startActivity(new Intent(getActivity(), BuyDashBaseActivity.class)); + } } } diff --git a/app/src/main/java/pivx/org/pivxwallet/ui/wallet_activity/TransactionsFragmentBase.java b/app/src/main/java/pivx/org/pivxwallet/ui/wallet_activity/TransactionsFragmentBase.java index b799bb349..f9f53d3a1 100644 --- a/app/src/main/java/pivx/org/pivxwallet/ui/wallet_activity/TransactionsFragmentBase.java +++ b/app/src/main/java/pivx/org/pivxwallet/ui/wallet_activity/TransactionsFragmentBase.java @@ -45,8 +45,10 @@ public class TransactionsFragmentBase extends BaseRecyclerFragment"); + + //setEmptyText("You don't have any transfers yet."); setEmptyTextColor(Color.parseColor("#cccccc")); return view; } diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/BuyDashPref.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/BuyDashPref.java new file mode 100644 index 000000000..9c9617c31 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/BuyDashPref.java @@ -0,0 +1,134 @@ +/* + * Copyright 2014-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins; + +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; + +import com.google.gson.Gson; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import pivx.org.pivxwallet.wallofcoins.response.CreateHoldResp; + + +/** + * Class for Manage Buy Dash SharedPreferences + * @author Andreas Schildbach + */ +public class BuyDashPref { + + private final SharedPreferences prefs; + private final Gson gson; + private static final String CREATE_HOLD_RESP = "create_hold_resp"; + private static final String AUTH_TOKEN = "auth_token"; + private static final String HOLD_ID = "hold_id"; + private static final String PHONE = "phone"; + private static final String EMAIL = "email"; + private static final String DEVICE_CODE = "device_code"; + private static final String DEVICE_ID = "device_id"; + + + private static final Logger log = LoggerFactory.getLogger(BuyDashPref.class); + + public BuyDashPref(final SharedPreferences prefs) { + this.prefs = prefs; + gson = new Gson(); + } + + public String getAuthToken() { + return prefs.getString(AUTH_TOKEN, ""); + } + + public void setAuthToken(String authToken) { + prefs.edit().putString(AUTH_TOKEN, authToken).apply(); + } + + public String getPhone() { + return prefs.getString(PHONE, ""); + } + + public void setPhone(String authToken) { + prefs.edit().putString(PHONE, authToken).apply(); + } + + public String getDeviceCode() { + return prefs.getString(DEVICE_CODE, ""); + } + + public void setDeviceCode(String deviceCode) { + prefs.edit().putString(DEVICE_CODE, deviceCode).apply(); + } + + public String getDeviceId() { + return prefs.getString(DEVICE_ID, ""); + } + + public void setDeviceId(String deviceId) { + prefs.edit().putString(DEVICE_ID, deviceId).apply(); + } + public String getEmail() { + return prefs.getString(EMAIL, ""); + } + + public void setEmail(String authToken) { + prefs.edit().putString(EMAIL, authToken).apply(); + } + + public String getHoldId() { + return prefs.getString(HOLD_ID, ""); + } + + public void setHoldId(String holdId) { + if (holdId != null) { + prefs.edit().putString(HOLD_ID, holdId).apply(); + } else { + prefs.edit().remove(HOLD_ID); + } + } + + public void clearAllPrefrance(){ + setDeviceId(""); + setAuthToken(""); + setDeviceCode(""); + setCreateHoldResp(null); + setPhone(""); + prefs.edit().clear(); + } + + public CreateHoldResp getCreateHoldResp() { + return gson.fromJson(prefs.getString(CREATE_HOLD_RESP, ""), CreateHoldResp.class); + } + + public void setCreateHoldResp(CreateHoldResp createHoldResp) { + if (createHoldResp != null) { + prefs.edit().putString(CREATE_HOLD_RESP, gson.toJson(createHoldResp)).apply(); + } else { + prefs.edit().remove(CREATE_HOLD_RESP); + } + } + + public void registerOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener) { + prefs.registerOnSharedPreferenceChangeListener(listener); + } + + public void unregisterOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener) { + prefs.unregisterOnSharedPreferenceChangeListener(listener); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/CustomAdapter.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/CustomAdapter.java new file mode 100644 index 000000000..9ba8fd52c --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/CustomAdapter.java @@ -0,0 +1,82 @@ +package pivx.org.pivxwallet.wallofcoins; + +import android.app.Activity; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.NonNull; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.response.CountryData; + + +public class CustomAdapter extends ArrayAdapter { + + private Activity activity; + private List data; + private LayoutInflater inflater; + + public CustomAdapter( + Activity activitySpinner, + int textViewResourceId, + List objects + ) { + super(activitySpinner, textViewResourceId, objects); + + /********** Take passed values **********/ + activity = activitySpinner; + data = objects; + + /*********** Layout inflator to call external xml layout () **********************/ + inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + @Override + public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { + return getCustomView(position, convertView, parent); + } + + @Override + public View getView(int position, View convertView, @NonNull ViewGroup parent) { + return getCustomView(position, convertView, parent); + } + + // This funtion called for each row ( Called data.size() times ) + public View getCustomView(int position, View convertView, ViewGroup parent) { + + /********** Inflate spinner_rows.xml file for each row ( Defined below ) ************/ + View row = inflater.inflate(R.layout.spinner_row_country, parent, false); + + /***** Get each Model object from Arraylist ********/ + CountryData.CountriesBean bean = data.get(position); + + TextView label = (TextView) row.findViewById(R.id.tv_country); + ImageView ivCountry = (ImageView) row.findViewById(R.id.iv_country); + + label.setText(bean.name + " (" + bean.code + ")"); + ivCountry.setImageResource(R.drawable.flags); + ivCountry.setScaleType(ImageView.ScaleType.MATRIX); + + Drawable drawable = activity.getResources().getDrawable(R.drawable.flags); + + int height = drawable.getIntrinsicHeight(); + int width = drawable.getIntrinsicWidth(); + + int left = (bean.left * width) / 288; + int top = (bean.top * height) / 266; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ivCountry.drawableHotspotChanged(left, top); + } + return row; + } + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/WOCConstants.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/WOCConstants.java new file mode 100644 index 000000000..448a38cc3 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/WOCConstants.java @@ -0,0 +1,60 @@ +package pivx.org.pivxwallet.wallofcoins; + +/** + * Created by WOC on 27-Jan-18. + * Copyright (c) 2018 WOC Limited. All rights reserved. + */ + +public final class WOCConstants { + + + public static final String CRYPTO = "PIVX"; + + // REST FUll API KEY Constant + public static final String KEY_HEADER_AUTH_TOKEN = "X-Coins-Api-Token"; + public static final String KEY_HEADER_PUBLISHER_ID = "X-Coins-Publisher"; + public static final String KEY_HEADER_CONTENT_TYPE = "Content-Type"; + public static final String KEY_HEADER_CONTENT_TYPE_VALUE = "application/json"; + public static final String KEY_PUBLISHER_ID = "publisherId"; + public static final String KEY_VERIFICATION_CODE = "verificationCode"; + public static final String KEY_CRYPTO_ADDRESS = "cryptoAddress"; + public static final String KEY_USD_AMOUNT = "usdAmount"; + public static final String KEY_CRYPTO = "crypto"; + public static final String KEY_COUNTRY = "country"; + public static final String KEY_BANK = "bank"; + public static final String KEY_CRYPTO_AMOUNT = "cryptoAmount"; + public static final String KEY_ZIP_CODE = "zipCode"; + public static final String KEY_BROWSE_LOCATION = "browserLocation"; + public static final String KEY_LATITUDE = "latitude"; + public static final String KEY_LONGITUDE = "longitude"; + public static final String KEY_PASSWORD = "password"; + public static final String KEY_DEVICECODE = "deviceCode"; + public static final String KEY_DEVICEID = "deviceId"; + public static final String KEY_DEVICE_NAME = "name"; + public static final String KEY_DEVICE_CODE = "code"; + public static final String KEY_PHONE = "phone"; + public static final String KEY_DEVICE_NAME_VALUE = "Dash Wallet (Android)"; + public static final String KEY_OFFER = "offer"; + public static final String KEY_EMAIL = "email"; + public static final String KEY_deviceName = "deviceName"; + + //BuyDash General Constants + public static final String KEY_WEB_URL = "https://wallofcoins.com/"; + public static final String KEY_FORGOT_PASSWORD_URL = "https://wallofcoins.com/forgotPassword/"; + public static final String SUPPORT_EMAIL = "support@wallofcoins.com"; + public static final String SEND_EMAIL = "Send email..."; + public static final String WOC_ADDRESS = "WallofCoins.com"; + public static final String KEY_SIGN_UP_URL = "https://wallofcoins.com/signup/"; + + + //buying wizard + public static String LATITUDE = "latitude"; + public static String LONGITUDE = "longitude"; + public static String ZIP = "zip"; + public static String BANK_ID = "bankId"; + public static String OFFER_ID = "offerId"; + public static String VERIFICATION_OTP = "otp"; + public static String SCREEN_TYPE = "screenType"; + + public static int DIVIDENT_VALUE=1000000; +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/addressbook/AddressBookProvider.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/addressbook/AddressBookProvider.java new file mode 100644 index 000000000..c5953e333 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/addressbook/AddressBookProvider.java @@ -0,0 +1,246 @@ +/* + * Copyright 2011-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.addressbook; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.net.Uri; + +import java.util.List; + +/** + * @author Andreas Schildbach + */ +public class AddressBookProvider extends ContentProvider +{ + private static final String DATABASE_TABLE = "address_book"; + + public static final String KEY_ROWID = "_id"; + public static final String KEY_ADDRESS = "address"; + public static final String KEY_LABEL = "label"; + + public static final String SELECTION_QUERY = "q"; + public static final String SELECTION_IN = "in"; + public static final String SELECTION_NOTIN = "notin"; + + public static Uri contentUri(final String packageName) + { + return Uri.parse("content://" + packageName + '.' + DATABASE_TABLE); + } + + public static String resolveLabel(final Context context, final String address) + { + String label = null; + + final Uri uri = contentUri(context.getPackageName()).buildUpon().appendPath(address).build(); + final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); + + if (cursor != null) + { + if (cursor.moveToFirst()) + label = cursor.getString(cursor.getColumnIndexOrThrow(AddressBookProvider.KEY_LABEL)); + + cursor.close(); + } + + return label; + } + + private Helper helper; + + @Override + public boolean onCreate() + { + helper = new Helper(getContext()); + return true; + } + + @Override + public String getType(final Uri uri) + { + throw new UnsupportedOperationException(); + } + + @Override + public Uri insert(final Uri uri, final ContentValues values) + { + if (uri.getPathSegments().size() != 1) + throw new IllegalArgumentException(uri.toString()); + + final String address = uri.getLastPathSegment(); + values.put(KEY_ADDRESS, address); + + long rowId = helper.getWritableDatabase().insertOrThrow(DATABASE_TABLE, null, values); + + final Uri rowUri = contentUri(getContext().getPackageName()).buildUpon().appendPath(address).appendPath(Long.toString(rowId)).build(); + + getContext().getContentResolver().notifyChange(rowUri, null); + + return rowUri; + } + + @Override + public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) + { + if (uri.getPathSegments().size() != 1) + throw new IllegalArgumentException(uri.toString()); + + final String address = uri.getLastPathSegment(); + + final int count = helper.getWritableDatabase().update(DATABASE_TABLE, values, KEY_ADDRESS + "=?", new String[] { address }); + + if (count > 0) + getContext().getContentResolver().notifyChange(uri, null); + + return count; + } + + @Override + public int delete(final Uri uri, final String selection, final String[] selectionArgs) + { + final List pathSegments = uri.getPathSegments(); + if (pathSegments.size() != 1) + throw new IllegalArgumentException(uri.toString()); + + final String address = uri.getLastPathSegment(); + + final int count = helper.getWritableDatabase().delete(DATABASE_TABLE, KEY_ADDRESS + "=?", new String[] { address }); + + if (count > 0) + getContext().getContentResolver().notifyChange(uri, null); + + return count; + } + + @Override + public Cursor query(final Uri uri, final String[] projection, final String originalSelection, final String[] originalSelectionArgs, + final String sortOrder) + { + final SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); + qb.setTables(DATABASE_TABLE); + + final List pathSegments = uri.getPathSegments(); + if (pathSegments.size() > 1) + throw new IllegalArgumentException(uri.toString()); + + String selection = null; + String[] selectionArgs = null; + + if (pathSegments.size() == 1) + { + final String address = uri.getLastPathSegment(); + + qb.appendWhere(KEY_ADDRESS + "="); + qb.appendWhereEscapeString(address); + } + else if (SELECTION_IN.equals(originalSelection)) + { + final String[] addresses = originalSelectionArgs[0].trim().split(","); + + qb.appendWhere(KEY_ADDRESS + " IN ("); + appendAddresses(qb, addresses); + qb.appendWhere(")"); + } + else if (SELECTION_NOTIN.equals(originalSelection)) + { + final String[] addresses = originalSelectionArgs[0].trim().split(","); + + qb.appendWhere(KEY_ADDRESS + " NOT IN ("); + appendAddresses(qb, addresses); + qb.appendWhere(")"); + } + else if (SELECTION_QUERY.equals(originalSelection)) + { + final String query = '%' + originalSelectionArgs[0].trim() + '%'; + selection = KEY_ADDRESS + " LIKE ? OR " + KEY_LABEL + " LIKE ?"; + selectionArgs = new String[] { query, query }; + } + + final Cursor cursor = qb.query(helper.getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder); + + cursor.setNotificationUri(getContext().getContentResolver(), uri); + + return cursor; + } + + private static void appendAddresses(final SQLiteQueryBuilder qb, final String[] addresses) + { + for (final String address : addresses) + { + qb.appendWhereEscapeString(address.trim()); + if (!address.equals(addresses[addresses.length - 1])) + qb.appendWhere(","); + } + } + + private static class Helper extends SQLiteOpenHelper + { + private static final String DATABASE_NAME = "address_book"; + private static final int DATABASE_VERSION = 1; + + private static final String DATABASE_CREATE = "CREATE TABLE " + DATABASE_TABLE + " (" // + + KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " // + + KEY_ADDRESS + " TEXT NOT NULL, " // + + KEY_LABEL + " TEXT NULL);"; + + public Helper(final Context context) + { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(final SQLiteDatabase db) + { + db.execSQL(DATABASE_CREATE); + } + + @Override + public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) + { + db.beginTransaction(); + try + { + for (int v = oldVersion; v < newVersion; v++) + upgrade(db, v); + + db.setTransactionSuccessful(); + } + finally + { + db.endTransaction(); + } + } + + private void upgrade(final SQLiteDatabase db, final int oldVersion) + { + if (oldVersion == 1) + { + // future + } + else + { + throw new UnsupportedOperationException("old=" + oldVersion); + } + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/api/RestApi.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/api/RestApi.java new file mode 100644 index 000000000..d1015ae41 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/api/RestApi.java @@ -0,0 +1,93 @@ +package pivx.org.pivxwallet.wallofcoins.api; + +import java.util.List; +import java.util.Map; + +import pivx.org.pivxwallet.wallofcoins.response.CaptureHoldResp; +import pivx.org.pivxwallet.wallofcoins.response.CheckAuthResp; +import pivx.org.pivxwallet.wallofcoins.response.ConfirmDepositResp; +import pivx.org.pivxwallet.wallofcoins.response.CreateDeviceResp; +import pivx.org.pivxwallet.wallofcoins.response.CreateHoldResp; +import pivx.org.pivxwallet.wallofcoins.response.DiscoveryInputsResp; +import pivx.org.pivxwallet.wallofcoins.response.GetAuthTokenResp; +import pivx.org.pivxwallet.wallofcoins.response.GetCurrencyResp; +import pivx.org.pivxwallet.wallofcoins.response.GetHoldsResp; +import pivx.org.pivxwallet.wallofcoins.response.GetOffersResp; +import pivx.org.pivxwallet.wallofcoins.response.GetReceivingOptionsResp; +import pivx.org.pivxwallet.wallofcoins.response.OrderListResp; +import retrofit2.Call; +import retrofit2.http.DELETE; +import retrofit2.http.Field; +import retrofit2.http.FieldMap; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Path; +import retrofit2.http.Query; + +/** + * RestApi Client Interface For all WOC RestFull API with Method + * Get,Post,Update & Delete API call + */ +public interface RestApi { + + + @GET("api/v1/orders/") + Call> getOrders(@Query("publisherId") String publisherId); + + + @GET("api/v1/auth/{phone}/") + Call checkAuth(@Path("phone") String username, @Query("publisherId") String publisherId); + + @DELETE("api/v1/auth/{phone}/") + Call deleteAuth(@Path("phone") String username, @Query("publisherId") String publisherId); + + @DELETE("api/v1/orders/{orderId}/") + Call cancelOrder(@Path("orderId") String orderId, @Query("publisherId") String publisherId); + + @FormUrlEncoded + @POST("api/v1/auth/{phone}/authorize/") + Call getAuthToken(@Path("phone") String username, @FieldMap Map partMap); + + + //--------------dash wizard + @GET("api/v1/banks/") + Call> getReceivingOptions(); + //---------------------- + + @GET("api/v1/currency/") + Call> getCurrency(); + + @FormUrlEncoded + @POST("api/v1/discoveryInputs/") + Call discoveryInputs(@FieldMap Map partMap); + + @GET("api/v1/discoveryInputs/{discoveryId}/offers/") + Call getOffers(@Path("discoveryId") String discoveryId, @Query("publisherId") String publisherId); + + @FormUrlEncoded + @POST("api/v1/holds/") + Call createHold(@FieldMap Map partMap); + + @GET("api/v1/holds/") + Call> getHolds(); + + @DELETE("api/v1/holds/{id}/") + Call deleteHold(@Path("id") String id); + + @FormUrlEncoded + @POST("api/v1/holds/{id}/capture/") + Call> captureHold(@Path("id") String id, @FieldMap Map partMap); + + @FormUrlEncoded + @POST("api/v1/orders/{holdId}/confirmDeposit/") + Call confirmDeposit(@Path("holdId") String holdId, @Field("your_field") String yourField, @Query("publisherId") String publisherId); + + @FormUrlEncoded + @POST("api/v1/devices/") + Call createDevice(@FieldMap Map partMap); + + @GET("api/v1/devices/") + Call> getDevice(); + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/api/WallofCoins.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/api/WallofCoins.java new file mode 100644 index 000000000..cac6141e2 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/api/WallofCoins.java @@ -0,0 +1,129 @@ +package pivx.org.pivxwallet.wallofcoins.api; + +import android.content.Context; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; +import pivx.org.pivxwallet.BuildConfig; +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.response.GetReceivingOptionsResp; +import pivx.org.pivxwallet.wallofcoins.response.PayFieldsDeserializer; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * WalloCoins call for manage API call from Base URL + */ +public class WallofCoins { + + private static String API_BASE_URL; + + static final TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + } + }; + + /** + * Method for Create RestAPI call + * @param interceptor + * @param context context object of parent class + * @return RestApi Client object + */ + public static RestApi createService(Interceptor interceptor, Context context) { + API_BASE_URL = context.getString(R.string.base_url); + return getClient(interceptor) + .create(RestApi.class); + } + + /** + * Method for Create RestAPI call + * @param context context object of parent class + * @return RestApi Client object + */ + public static RestApi createService(Context context) { + API_BASE_URL = context.getString(R.string.base_url); + return getClient(null) + .create(RestApi.class); + } + + /** + * Method for get retrofit + * @param interceptor + * @return Retrofit Object + */ + private static Retrofit getClient(Interceptor interceptor) { + + OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); + // add your other interceptors … + httpClient.connectTimeout(60, TimeUnit.SECONDS); + httpClient.readTimeout(60, TimeUnit.SECONDS); + try { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, null); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, "keystore_pass".toCharArray()); + sslContext.init(null, trustAllCerts, new SecureRandom()); + httpClient.sslSocketFactory(sslContext.getSocketFactory()) + .hostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + + HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); + // set your desired log level + logging.setLevel(HttpLoggingInterceptor.Level.BODY); + // add logging as last interceptor + if (BuildConfig.DEBUG) + httpClient.addInterceptor(logging); // <-- this is the important line! + if (null != interceptor) + httpClient.addInterceptor(interceptor); + + Gson gson = new GsonBuilder() + .registerTypeAdapter(GetReceivingOptionsResp.PayFieldsBeanX.class, new PayFieldsDeserializer()) + .create(); + + return new Retrofit.Builder() + .baseUrl(API_BASE_URL).client(httpClient.build()) + .addConverterFactory(GsonConverterFactory.create(gson)).build(); + } + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/binder/ImageBinder.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/binder/ImageBinder.java new file mode 100644 index 000000000..0a6b62442 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/binder/ImageBinder.java @@ -0,0 +1,31 @@ +package pivx.org.pivxwallet.wallofcoins.binder; + +/** + * Created by on 30-Mar-18. + */ + +import android.content.Context; +import android.databinding.BindingAdapter; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; + +import pivx.org.pivxwallet.R; + +public final class ImageBinder { + + private ImageBinder() { + //NO-OP + } + + @BindingAdapter("imageUrl") + public static void setImageUrl(ImageView imageView, String url) { + Context context = imageView.getContext(); + + Glide.with(context) + .load(url) + .placeholder(R.drawable.ic_account_balance_black_24dp) + .error(R.drawable.ic_account_balance_black_24dp) + .into(imageView); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/BuyDashBaseActivity.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/BuyDashBaseActivity.java new file mode 100644 index 000000000..7e98a1394 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/BuyDashBaseActivity.java @@ -0,0 +1,275 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard; + +import android.app.LoaderManager; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.text.format.DateUtils; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import org.bitcoinj.core.Coin; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.BuyDashPref; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.buy_dash_location.BuyDashLocationFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.email_phone.EmailAndPhoneFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.offer_amount.BuyDashOfferAmountFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.order_history.OrderHistoryFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.verification_otp.VerifycationOtpFragment; +import pivx.org.pivxwallet.wallofcoins.response.CreateHoldResp; +import pivx.org.pivxwallet.wallofcoins.ui.CurrencyTextView; +import pivx.org.pivxwallet.wallofcoins.utils.Configuration; +import pivx.org.pivxwallet.wallofcoins.utils.Constants; + + +/** + * Created on 6/3/18. + */ + +public class BuyDashBaseActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener, View.OnClickListener { + + + private FragmentManager fragmentManager; + private FragmentTransaction fragmentTransaction; + public BuyDashPref buyDashPref; + private ImageView imgViewToolbarBack; + // private Wallet wallet; + // private WalletApplication application; + private TextView appBarMessageView; + private ProgressBar progressView; + private LinearLayout viewBalance; + private CurrencyTextView viewBalanceBtc, viewBalanceLocal; + private ImageView viewBalanceTooMuch; + private static final Coin TOO_MUCH_BALANCE_THRESHOLD = Coin.COIN.multiply(30); + private static final int ID_BALANCE_LOADER = 0; + private static final int ID_RATE_LOADER = 1; + private static final int ID_BLOCKCHAIN_STATE_LOADER = 2; + private static final int ID_MASTERNODE_SYNC_LOADER = 3; + + private static final long BLOCKCHAIN_UPTODATE_THRESHOLD_MS = DateUtils.HOUR_IN_MILLIS; + @javax.annotation.Nullable + private Coin balance = null; + private LoaderManager loaderManager; + private boolean showLocalBalance; + private boolean initComplete = false; + @javax.annotation.Nullable + // private BlockchainState blockchainState = null; + private String progressMessage; + private Configuration config; + @javax.annotation.Nullable + // private ExchangeRate exchangeRate = null; + private Context mContext; + private boolean isPopBack; + + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_buy_dash_base); + init(); + setListners(); + if (!TextUtils.isEmpty(buyDashPref.getAuthToken())) { + if (!TextUtils.isEmpty(buyDashPref.getHoldId())) { + CreateHoldResp createHoldResp = buyDashPref.getCreateHoldResp(); + //binding.etOtp.setText(createHoldResp.__PURCHASE_CODE); + // hideViewExcept(binding.layoutVerifyOtp); + Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.VERIFICATION_OTP, createHoldResp.__PURCHASE_CODE); + VerifycationOtpFragment otpFragment = new VerifycationOtpFragment(); + otpFragment.setArguments(bundle); + replaceFragment(otpFragment, true, false); + //navigateToVerifyOtp(createHoldResp.__PURCHASE_CODE); + } else { + //hideViewExcept(binding.rvOrderList); + //getOrderList(false); + //navigateToOrderList(false); + /*OrderHistoryFragment historyFragment = new OrderHistoryFragment(); + Bundle bundle = new Bundle(); + bundle.putBoolean("isFromCreateHold", false); + historyFragment.setArguments(bundle); + replaceFragment(historyFragment, true, false);*/ + replaceFragment(new BuyDashLocationFragment(), true, true); + } + } else + replaceFragment(new BuyDashLocationFragment(), true, true); + } + + private void init() { + mContext = this; + this.loaderManager = getLoaderManager(); + /* this.application = (WalletApplication) this.getApplication(); + this.wallet = application.getWallet(); + this.config = application.getConfiguration();*/ + this.buyDashPref = new BuyDashPref(PreferenceManager.getDefaultSharedPreferences(this)); + buyDashPref.registerOnSharedPreferenceChangeListener(this); + fragmentManager = getSupportFragmentManager(); + imgViewToolbarBack = (ImageView) findViewById(R.id.imgViewToolbarBack); + appBarMessageView = (TextView) findViewById(R.id.toolbar_message); + progressView = (ProgressBar) findViewById(R.id.progress); + viewBalance = (LinearLayout) findViewById(R.id.wallet_balance); + viewBalanceBtc = (CurrencyTextView) findViewById(R.id.wallet_balance_btc); + viewBalanceLocal = (CurrencyTextView) findViewById(R.id.wallet_balance_local); + viewBalanceTooMuch = (ImageView) findViewById(R.id.wallet_balance_too_much_warning); + + + viewBalanceBtc.setPrefixScaleX(0.9f); + viewBalanceLocal.setInsignificantRelativeSize(1); + viewBalanceLocal.setStrikeThru(Constants.TEST); + + // loaderManager.initLoader(ID_BALANCE_LOADER, null, balanceLoaderCallbacks); + + // loaderManager.initLoader(ID_RATE_LOADER, null, rateLoaderCallbacks); + + /* if (!initComplete) { + loaderManager.initLoader(ID_BLOCKCHAIN_STATE_LOADER, null, blockchainStateLoaderCallbacks); + initComplete = true; + } else + loaderManager.restartLoader(ID_BLOCKCHAIN_STATE_LOADER, null, blockchainStateLoaderCallbacks);*/ + + //updateView(); + + } + + private void setListners() { + imgViewToolbarBack.setOnClickListener(this); + viewBalance.setOnClickListener(this); + } + + public void replaceFragment(Fragment fragment, boolean withAnimation, boolean withBackStack) { + fragmentTransaction = fragmentManager.beginTransaction(); + Log.e("Fragment name", fragment.getClass().getName()); + if (withAnimation) + fragmentTransaction.setCustomAnimations(R.anim.activity_in, R.anim.activity_out, R.anim.activity_backin, R.anim.activity_back_out); + if (withBackStack) + fragmentTransaction.replace(R.id.containerBuyDashBase, fragment).addToBackStack(fragment.getClass().getName()); + else + fragmentTransaction.replace(R.id.containerBuyDashBase, fragment); + fragmentTransaction.commitAllowingStateLoss(); + } + + public void finishBaseActivity() { + this.finish(); + } + + public void popbackFragment() { + + Log.e("CurrentFragment", fragmentManager.findFragmentById(R.id.containerBuyDashBase).toString()); + if (fragmentManager.getBackStackEntryCount() > 0) { + Fragment fragment = fragmentManager.findFragmentById(R.id.containerBuyDashBase); + if (fragment instanceof EmailAndPhoneFragment) + ((EmailAndPhoneFragment) fragment).changeView(); + + else if (fragment instanceof BuyDashOfferAmountFragment) + ((BuyDashOfferAmountFragment) fragment).changeView(); + else if (fragment instanceof BuyDashLocationFragment) + this.finish(); + else if (fragment instanceof OrderHistoryFragment) + ((OrderHistoryFragment)fragment).changeView(); + else + fragmentManager.popBackStack(); + } else + this.finish(); + } + + public void popBackDirect() { + if (fragmentManager.getBackStackEntryCount() > 0) + fragmentManager.popBackStack(); + else + this.finish(); + + } + + @Override + public void onBackPressed() { + popbackFragment(); + //super.onBackPressed(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + buyDashPref.unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + + case R.id.imgViewToolbarBack: + popbackFragment(); + break; + + case R.id.wallet_balance: + showWarningIfBalanceTooMuch(); + //showExchangeRatesActivity(); + break; + } + + + } + + @Override + public void onResume() { + super.onResume(); + } + + private void showWarningIfBalanceTooMuch() { + if (balance != null && balance.isGreaterThan(TOO_MUCH_BALANCE_THRESHOLD)) { + Toast.makeText(this, getString(R.string.wallet_balance_fragment_too_much), + Toast.LENGTH_LONG).show(); + } + } + + + private void showAppBarMessage(CharSequence message) { + if (message != null) { + appBarMessageView.setVisibility(View.VISIBLE); + appBarMessageView.setText(message); + } else { + appBarMessageView.setVisibility(View.GONE); + } + } + + private void updateBalanceTooMuchWarning() { + if (balance == null) + return; + + boolean tooMuch = balance.isGreaterThan(TOO_MUCH_BALANCE_THRESHOLD); + viewBalanceTooMuch.setVisibility(tooMuch ? View.VISIBLE : View.GONE); + } + + public void popBackAllFragmentsExcept(String tag) { + fragmentManager.popBackStack(tag, FragmentManager.POP_BACK_STACK_INCLUSIVE); + + } + + public void removeAllFragmentFromStack() { + + if (fragmentManager.getBackStackEntryCount() > 0) { + FragmentUtils.sDisableFragmentAnimations = true; + fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + FragmentUtils.sDisableFragmentAnimations = false; + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/BuyDashBaseFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/BuyDashBaseFragment.java new file mode 100644 index 000000000..812d355b3 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/BuyDashBaseFragment.java @@ -0,0 +1,302 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.Address; +import android.location.Geocoder; +import android.location.Location; +import android.location.LocationManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.util.Base64; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Toast; + +import com.google.common.base.Charsets; + +import org.bitcoinj.core.WrongNetworkException; + +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +import okhttp3.Interceptor; +import okhttp3.Request; +import pivx.org.pivxwallet.PivxApplication; +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.module.PivxModule; +import pivx.org.pivxwallet.wallofcoins.BuyDashPref; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.addressbook.AddressBookProvider; +import pivx.org.pivxwallet.wallofcoins.utils.Constants; + +/** + * Created on 6/3/18. + */ + +public class BuyDashBaseFragment extends Fragment { + + private final int PERMISSIONS_REQUEST_LOCATION = 8989; + protected Context mContext; + private PivxModule module; + private org.pivxj.core.Address address; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + module = PivxApplication.getInstance().getModule(); + address = module.getReceiveAddress(); + } + + + protected boolean checkPermissions() { + int permissionFineLoc = ActivityCompat.checkSelfPermission(mContext, + Manifest.permission.ACCESS_FINE_LOCATION); + int permissionCoarseLoc = ActivityCompat.checkSelfPermission(mContext, + Manifest.permission.ACCESS_COARSE_LOCATION); + + return permissionFineLoc == PackageManager.PERMISSION_GRANTED && + permissionCoarseLoc == PackageManager.PERMISSION_GRANTED; + } + + protected void requestLocationPermission() { + requestPermissions( + new String[]{Manifest.permission.ACCESS_FINE_LOCATION + , Manifest.permission.ACCESS_COARSE_LOCATION}, + PERMISSIONS_REQUEST_LOCATION); + } + + /** + * Get Last known best accurate location from available providers + * + * @return location object + */ + protected Location getLastKnownLocation() { + boolean gps_enabled = false; + boolean network_enabled = false; + LocationManager lm = (LocationManager) getActivity() + .getSystemService(Context.LOCATION_SERVICE); + gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER); + network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); + + Location net_loc = null, gps_loc = null, finalLoc = null; + if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED + && ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + if (gps_enabled) + gps_loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); + if (network_enabled) + net_loc = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); + + } else { + requestPermissions( + new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, + PERMISSIONS_REQUEST_LOCATION); + } + + if (gps_loc != null && net_loc != null) { + if (gps_loc.getAccuracy() > net_loc.getAccuracy()) + finalLoc = net_loc; + else + finalLoc = gps_loc; + } else { + + if (gps_loc != null) { + finalLoc = gps_loc; + } else if (net_loc != null) { + finalLoc = net_loc; + } + } + return finalLoc; + } + + /** + * Method for Open web url link in external browser app + * + * @param url + */ + protected void goToUrl(String url) { + Uri uriUrl = Uri.parse(url); + Intent launchBrowser = new Intent(Intent.ACTION_VIEW, uriUrl); + startActivity(launchBrowser); + } + + /** + * get country code form current latitude & longitude + * + * @return Country Code + */ + protected String getCountryCode(double latitude, double longitude) { + String countryCode = ""; + try { + Geocoder geo = new Geocoder(mContext, Locale.getDefault()); + List
addresses = geo.getFromLocation(latitude, longitude, 1); + Address obj = addresses.get(0); + countryCode = obj.getCountryCode(); + } catch (Exception e) { + e.printStackTrace(); + } + + if (countryCode.equals("")) { + return "us"; + } else { + return countryCode; + } + } + + /** + * Method for hide keyboard + */ + protected void hideKeyBoard() { + View view = getActivity().getCurrentFocus(); + if (view != null) { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + + /** + * Show a dialog to the user requesting that GPS be enabled + */ + protected void showDialogGPS() { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setCancelable(false); + builder.setTitle(getString(R.string.enable_gps)); + builder.setMessage(getString(R.string.enable_gps_location)); + builder.setPositiveButton(getString(R.string.enable_label), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + startActivity( + new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); + } + }); + builder.setNegativeButton(getString(R.string.ignore_label), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } + + /** + * Method for Update Address book of Order Transaction + * + * @param KEY_ADDRESS + * @param newLabel + */ + protected void updateAddressBookValue(String KEY_ADDRESS, String newLabel) { + + try { + if (KEY_ADDRESS != null && newLabel != null) { + + + org.bitcoinj.core.Address keyAddress = org.bitcoinj.core.Address.fromBase58(Constants.NETWORK_PARAMETERS, KEY_ADDRESS); + final Uri uri = AddressBookProvider.contentUri(mContext.getPackageName()).buildUpon().appendPath(keyAddress.toBase58()).build(); + final String addressLabel = AddressBookProvider.resolveLabel(mContext, keyAddress.toBase58()); + + ContentResolver contentResolver; + contentResolver = mContext.getContentResolver(); + + final ContentValues values = new ContentValues(); + + values.put(AddressBookProvider.KEY_LABEL, newLabel); + + if (addressLabel == null) { + contentResolver.insert(uri, values); + } else { + contentResolver.update(uri, values, null, null); + } + } + } catch (WrongNetworkException wrongNetworkException) { + wrongNetworkException.printStackTrace(); + } + + } + + @SuppressLint("HardwareIds") + protected String getDeviceCode(Context context, BuyDashPref buyDashPref) { + + String deviceUID = buyDashPref.getDeviceCode(); + if (TextUtils.isEmpty(deviceUID)) { + String deviceID; + deviceID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); + byte[] data = (deviceID + deviceID + deviceID).getBytes(Charsets.UTF_8); + deviceUID = Base64.encodeToString(data, Base64.DEFAULT).substring(0, 39); + buyDashPref.setDeviceCode(deviceUID); + } + + return deviceUID; + } + + protected void showToast(String msg) { + Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show(); + } + + /** + * Validate Email id + * + * @param target Email + * @return boolean for email valid or not + */ + protected boolean isValidEmail(CharSequence target) { + if (target == null) { + return false; + } else { + return android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches(); + } + } + + /** + * Show alert dialog wrong username or password + */ + protected void showAlertPasswordDialog() { + AlertDialog.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + builder = new AlertDialog.Builder(mContext, android.R.style.Theme_Material_Dialog_Alert); + } else { + builder = new AlertDialog.Builder(mContext); + } + builder.setTitle("") + .setMessage(getString(R.string.user_pass_wrong)) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .show(); + } + + /** + * API Header parameter interceptor + */ + protected Interceptor interceptor = new Interceptor() { + @Override + public okhttp3.Response intercept(Chain chain) throws IOException { + Request original = chain.request(); + // Request customization: add request headers + Request.Builder requestBuilder = original.newBuilder(); + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + requestBuilder.addHeader(WOCConstants.KEY_HEADER_AUTH_TOKEN, ((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken()); + } + requestBuilder.addHeader(WOCConstants.KEY_HEADER_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + requestBuilder.addHeader(WOCConstants.KEY_HEADER_CONTENT_TYPE, WOCConstants.KEY_HEADER_CONTENT_TYPE_VALUE); + Request request = requestBuilder.build(); + return chain.proceed(request); + } + }; +} + diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/BuyDashOffersAdapter.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/BuyDashOffersAdapter.java new file mode 100644 index 000000000..c9baec3ce --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/BuyDashOffersAdapter.java @@ -0,0 +1,281 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.adapters; + +import android.content.Context; +import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.net.Uri; +import android.os.Build; +import android.support.v7.widget.RecyclerView; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.TextView; + +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.List; +import java.util.Locale; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.databinding.BuyDashOffersItemBinding; +import pivx.org.pivxwallet.databinding.BuyDashOffersItemDoubleBinding; +import pivx.org.pivxwallet.wallofcoins.response.GetOffersResp; +import pivx.org.pivxwallet.wallofcoins.utils.GenericUtils; + + +public class BuyDashOffersAdapter extends RecyclerView.Adapter { + + private Context context; + private List singleDepositBeenList; + private List doubleDeposit; + private AdapterView.OnItemSelectedListener onItemSelectedListener; + private String offerAmount; + private boolean incremented; + private DecimalFormat formatter; + + public BuyDashOffersAdapter(Context context, GetOffersResp getOffersResp, String offerAmount, + AdapterView.OnItemSelectedListener onItemSelectedListener) { + this.context = context; + this.singleDepositBeenList = getOffersResp.singleDeposit; + this.doubleDeposit = getOffersResp.doubleDeposit; + if (getOffersResp.multipleBanks != null && doubleDeposit != null) + this.doubleDeposit.addAll(getOffersResp.multipleBanks); + this.onItemSelectedListener = onItemSelectedListener; + this.incremented = getOffersResp.incremented; + this.offerAmount = offerAmount; + formatter = new DecimalFormat("#,###,###.##"); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup group, int type) { + LayoutInflater layoutInflater = LayoutInflater.from(context); + + if (type == 1) { + View v = LayoutInflater.from(context) + .inflate(android.R.layout.simple_list_item_1, group, false); + return new VHolderMore(v); + } else if (type == 2) { + BuyDashOffersItemDoubleBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.buy_dash_offers_item_double, group, false); + return new VHolderDouble2(binding); + } else if (type == 3) { + BuyDashOffersItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.buy_dash_offers_item, group, false); + return new VHolderDouble1(binding); + } else { + BuyDashOffersItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.buy_dash_offers_item, group, false); + return new VHolderSingle(binding); + } + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { + + if (holder instanceof VHolderSingle) { + final GetOffersResp.SingleDepositBean bean = singleDepositBeenList.get(position - 1); + final VHolderSingle vholder = (VHolderSingle) holder; + vholder.binding.setItem(bean); + + if (getNumAmount(bean.deposit.amount) >= 200) { + double uPiv = Double.parseDouble(bean.amount.uPiv.replaceAll(",", "")) ; + vholder.binding.tvItrmOffer2.setText(context.getString(R.string.dotUnicode, formatter.format(uPiv), + GenericUtils.currencySymbol(bean.deposit.currency), getNumAmount(bean.deposit.amount) + / getNumAmount(bean.amount.PIVX))); + + } else { + double uPiv = Double.parseDouble(bean.amount.uPiv.replaceAll(",", "")) ; + vholder.binding.tvItrmOffer2.setText(context.getString(R.string.dotUnicodeNoRate, formatter.format(uPiv))); + } + + if (incremented) { + vholder.binding.txtAmount.setVisibility(View.VISIBLE); + } else { + vholder.binding.txtAmount.setVisibility(View.INVISIBLE); + } + + + vholder.binding.buttonBuyDashItemOrder.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onItemSelectedListener.onItemSelected(null, vholder.binding.getRoot(), position, 0); + } + }); + + vholder.binding.buttonBuyDashItemLocation.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(bean.bankLocationUrl)); + context.startActivity(i); + } + }); + + } else if (holder instanceof VHolderDouble1) { + GetOffersResp.DoubleDepositBean beanTemp = doubleDeposit.get(position - singleDepositBeenList.size() - 2); + final GetOffersResp.SingleDepositBean bean = new GetOffersResp.SingleDepositBean(); + bean.deposit = new GetOffersResp.DepositBean(); + bean.amount = new GetOffersResp.AmountBean(); + + if (beanTemp.secondOffer != null) { + bean.amount.PIVX = beanTemp.sumAmounts(beanTemp.firstOffer.amount.PIVX, beanTemp.secondOffer.amount.PIVX); + bean.amount.uPiv = beanTemp.sumAmounts(beanTemp.firstOffer.amount.uPiv, beanTemp.secondOffer.amount.uPiv); + bean.deposit.amount = beanTemp.sumAmounts(beanTemp.firstOffer.deposit.amount, beanTemp.secondOffer.deposit.amount); + } else { + bean.amount.PIVX = beanTemp.firstOffer.amount.PIVX; + bean.amount.uPiv = beanTemp.firstOffer.amount.uPiv; + bean.deposit.amount = beanTemp.firstOffer.deposit.amount; + } + + bean.bankName = beanTemp.firstOffer.bankName; + bean.bankLogo = beanTemp.firstOffer.bankLogo; + bean.address = beanTemp.firstOffer.address; + bean.distance = beanTemp.firstOffer.distance; + bean.city = beanTemp.firstOffer.city; + bean.state = beanTemp.firstOffer.state; + bean.bankLocationUrl = beanTemp.firstOffer.bankLocationUrl; + bean.deposit.currency = beanTemp.firstOffer.deposit.currency; + + + final VHolderDouble1 vholder = (VHolderDouble1) holder; + vholder.binding.setItem(bean); + + + if (getNumAmount(bean.deposit.amount) >= 200) { + //vholder.binding.tvItrmOffer2.setText(context.getString(R.string.dotUnicode, bean.amount.uPiv, GenericUtils.currencySymbol(bean.deposit.currency), getNumAmount(bean.deposit.amount) / getNumAmount(bean.amount.DASH))); + vholder.binding.tvItrmOffer2.setText(context.getString(R.string.dotUnicode, bean.amount.uPiv, GenericUtils.currencySymbol(bean.deposit.currency), getNumAmount(bean.deposit.amount) / getNumAmount(bean.amount.PIVX))); + + } else { + vholder.binding.tvItrmOffer2.setText(context.getString(R.string.dotUnicodeNoRate, bean.amount.uPiv)); + } + + vholder.binding.buttonBuyDashItemOrder.setOnClickListener(new View.OnClickListener() { + @Override + + public void onClick(View v) { + onItemSelectedListener.onItemSelected(null, vholder.binding.getRoot(), position, 0); + } + }); + + } else if (holder instanceof VHolderDouble2) { + final GetOffersResp.DoubleDepositBean bean = doubleDeposit.get(position - singleDepositBeenList.size() - 2); + final VHolderDouble2 vholder = (VHolderDouble2) holder; + vholder.binding.setItem(bean); + + + vholder.binding.buttonBuyDashItemOrder.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onItemSelectedListener.onItemSelected(null, vholder.binding.getRoot(), position, 0); + } + }); + + } else { + + TextView more = (TextView) holder.itemView; + if (position == 0 && singleDepositBeenList.size() > 0) { + if (incremented) { + more.setText("Below are offers for at least $" + + String.format("%.2f", Double.parseDouble(offerAmount)) + ". You must click the ORDER button before you receive instructions to pay at the Cash Payment center."); + } else { + more.setText("Below are offers for $" + + singleDepositBeenList.get(0).deposit.amount + ". You must click the ORDER button before you receive instructions to pay at the Cash Payment center."); + } + } else { + more.setText("Best Value Options: More PIV for $" + + String.format("%.2f", Double.parseDouble(offerAmount)) + " Cash"); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + more.setTextColor(context.getResources().getColor(R.color.colorPrimary, context.getTheme())); + } else { + more.setTextColor(context.getResources().getColor(R.color.colorPrimary)); + } + more.setGravity(Gravity.CENTER); + more.layout(30, 30, 30, 30); + + } + } + + private float getNumAmount(String strAmount) { + + float amount = 1; + + try { + amount = NumberFormat.getNumberInstance(Locale.getDefault()).parse(strAmount).floatValue(); + } catch (ParseException e) { + e.printStackTrace(); + } + +// return amount; + return amount ; + } + + + @Override + public int getItemCount() { + + int count = singleDepositBeenList.size(); + + if (singleDepositBeenList.size() > 0) { + count++; + } + + if (null != doubleDeposit && doubleDeposit.size() > 0) { + count += doubleDeposit.size(); + count++; + } + + return count; + } + + @Override + public int getItemViewType(int position) { + if ((position == 0 && singleDepositBeenList.size() > 0) + || (singleDepositBeenList.size() + 1 == position)) { + return 1; + } + if (position > singleDepositBeenList.size() + 1) { + if (doubleDeposit.get(position - singleDepositBeenList.size() - 2).secondOffer == null + || doubleDeposit.get(position - singleDepositBeenList.size() - 2).secondOffer.bankName.equals(doubleDeposit.get(position - singleDepositBeenList.size() - 2).firstOffer.bankName)) { + return 3; + } else { + return 2; + } + } + return 0; + } + + private class VHolderSingle extends RecyclerView.ViewHolder { + private BuyDashOffersItemBinding binding; + + private VHolderSingle(BuyDashOffersItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } + + private class VHolderMore extends RecyclerView.ViewHolder { + + private VHolderMore(View v) { + super(v); + } + } + + private class VHolderDouble2 extends RecyclerView.ViewHolder { + private BuyDashOffersItemDoubleBinding binding; + + private VHolderDouble2(BuyDashOffersItemDoubleBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } + + private class VHolderDouble1 extends RecyclerView.ViewHolder { + private BuyDashOffersItemBinding binding; + + private VHolderDouble1(BuyDashOffersItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/OrderListAdapter.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/OrderListAdapter.java new file mode 100644 index 000000000..872789fab --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/OrderListAdapter.java @@ -0,0 +1,269 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.adapters; + +import android.content.Context; +import android.databinding.DataBindingUtil; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.databinding.LayoutItemOrderListBinding; +import pivx.org.pivxwallet.wallofcoins.BuyDashPref; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.models.AccountJson; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.order_history.OrderHistoryFragment; +import pivx.org.pivxwallet.wallofcoins.response.OrderListResp; + + +/** + * Created on 08-Mar-18. + */ + +public class OrderListAdapter extends RecyclerView.Adapter { + + private Context mContext; + private final List orderList; + private OrderHistoryFragment historyFragment; + private BuyDashPref buyDashPref; + + public OrderListAdapter(Context mContext, List orderList, OrderHistoryFragment historyFragment, BuyDashPref buyDashPref) { + this.mContext = mContext; + this.orderList = orderList; + this.historyFragment = historyFragment; + this.buyDashPref = buyDashPref; + } + + @Override + public OrderListAdapter.VHolder onCreateViewHolder(ViewGroup parent, int viewType) { + LayoutInflater layoutInflater = LayoutInflater.from(mContext); + LayoutItemOrderListBinding itemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.layout_item_order_list, parent, false); + return new OrderListAdapter.VHolder(itemBinding); + } + + @Override + public void onBindViewHolder(OrderListAdapter.VHolder holder, int position) { + final OrderListResp orderListResp = orderList.get(position); + if (orderListResp.id != -1 && orderListResp.id != -2 && orderListResp.id != -3) { + + holder.itemBinding.layLogout.setVisibility(View.GONE); + holder.itemBinding.layHelpInstruction.setVisibility(View.GONE); + holder.itemBinding.layOrderHistory.setVisibility(View.GONE); + holder.itemBinding.layoutCompletionDetail.setVisibility(View.VISIBLE); + holder.itemBinding.setItem(orderListResp); + + + Type listType = new TypeToken>() { + }.getType(); + + holder.itemBinding.linearAccountDetail.removeAllViews(); + try { + ArrayList accountList = new Gson().fromJson(orderListResp.account, listType); + + if (accountList != null && orderListResp.status.equals("WD")) { + for (int i = 0; i < accountList.size(); i++) { + TextView textView = new TextView(mContext); + textView.setTextSize(16); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + layoutParams.topMargin = 0; + textView.setLayoutParams(layoutParams); + textView.setText(accountList.get(i).getLabel() + ": " + accountList.get(i).getValue()); + holder.itemBinding.linearAccountDetail.addView(textView); + } + holder.itemBinding.textAccountNo.setVisibility(View.GONE); + holder.itemBinding.textNameAccount.setVisibility(View.GONE); + + } else { + holder.itemBinding.linearAccountDetail.setVisibility(View.GONE); + } + } catch (JsonSyntaxException e) { + e.printStackTrace(); + } + + if (orderListResp.account == null + || orderListResp.account.equals("")) { + holder.itemBinding.textAccountNo.setVisibility(View.GONE); + } + if (orderListResp.nameOnAccount == null + || orderListResp.nameOnAccount.equals("")) { + holder.itemBinding.textNameAccount.setVisibility(View.GONE); + } + + holder.itemBinding.btnDepositFinished.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + historyFragment.depositFinished(orderListResp); + } + }); + + holder.itemBinding.btnCancelOrder.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + historyFragment.cancelHoldOrder(orderListResp); + } + }); + + + if (orderListResp.nearestBranch != null) { + if ((orderListResp.nearestBranch.address == null + || orderListResp.nearestBranch.address.equals("")) + && orderListResp.status.equals("WD") + ) { + holder.itemBinding.buttonBuyDashItemLocation.setVisibility(View.VISIBLE); + holder.itemBinding.tvItrmOffer4.setVisibility(View.VISIBLE); + } else { + holder.itemBinding.buttonBuyDashItemLocation.setVisibility(View.GONE); + holder.itemBinding.tvItrmOffer4.setVisibility(View.GONE); + } + } + + holder.itemBinding.buttonBuyDashItemLocation.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + historyFragment.goToGivenUrl(orderListResp.bankUrl); + } + }); + +// you must deposit cash + double dots = Double.parseDouble(orderListResp.total) * 1000000; + DecimalFormat formatter = new DecimalFormat("#,###,###.##"); + String yourFormattedDots = formatter.format(dots); + + if (orderListResp.bankLogo != null + && !orderListResp.bankLogo.equals("")) { + Glide.with(mContext) + .load(orderListResp.bankLogo) + .placeholder(R.drawable.ic_account_balance_black_24dp) + .error(R.drawable.ic_account_balance_black_24dp) + .into(holder.itemBinding.imageBank); + } else { + holder.itemBinding.imageBank.setImageResource(R.drawable.ic_account_balance_black_24dp); + } + //Log.e(TAG, "onBindViewHolder: " + orderListResp.status); + + if (orderListResp.status.equals("WD")) { + + holder.itemBinding.orderDash.setText("Total PIV: " + orderListResp.total + " (" + yourFormattedDots + " μⱣiv)\n" + + "You must deposit cash at the above Payment Center. Additional fees may apply. Paying in another method other than cash may delay your order."); + holder.itemBinding.orderDashInstruction.setVisibility(View.VISIBLE); + holder.itemBinding.btnCancelOrder.setVisibility(View.VISIBLE); + holder.itemBinding.btnDepositFinished.setVisibility(View.VISIBLE); + holder.itemBinding.layoutDueDate.setVisibility(View.VISIBLE); + + holder.itemBinding.textPaymentDueDate.setVisibility(View.VISIBLE); + historyFragment.countDownStart(orderListResp.paymentDue, holder.itemBinding.textPaymentDueDate); + + + holder.itemBinding.textContactInstruction.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // goToUrl(WOCConstants.KEY_WEB_URL); + historyFragment.goToGivenUrl(WOCConstants.KEY_WEB_URL); + } + }); + + } else { + + holder.itemBinding.orderDash.setText("Total PIV: " + orderListResp.total + " (" + yourFormattedDots + " μⱣiv)"); + holder.itemBinding.layoutDueDate.setVisibility(View.GONE); + holder.itemBinding.textPaymentDueDate.setVisibility(View.GONE); + holder.itemBinding.orderDashInstruction.setVisibility(View.GONE); + holder.itemBinding.btnCancelOrder.setVisibility(View.GONE); + holder.itemBinding.btnDepositFinished.setVisibility(View.GONE); + holder.itemBinding.textContactInstruction.setVisibility(View.GONE); + holder.itemBinding.textAccountNo.setVisibility(View.GONE); + holder.itemBinding.textNameAccount.setVisibility(View.GONE); + } + + if (orderListResp.status.equals("WD")) { + holder.itemBinding.textTransactionStatus.setText(mContext.getString(R.string.status_waiting_deposit)); + } else if (orderListResp.status.equals("WDV")) { + holder.itemBinding.textTransactionStatus.setText(mContext.getString(R.string.status_waiting_deposit_verification)); + } else if (orderListResp.status.equals("RERR")) { + holder.itemBinding.textTransactionStatus.setText(mContext.getString(R.string.status_issue_with_receipt)); + } else if (orderListResp.status.equals("DERR")) { + holder.itemBinding.textTransactionStatus.setText(mContext.getString(R.string.status_issue_with_deposit)); + } else if (orderListResp.status.equals("RSD")) { + holder.itemBinding.textTransactionStatus.setText(mContext.getString(R.string.status_reserved_for_deposit)); + } else if (orderListResp.status.equals("RMIT")) { + holder.itemBinding.textTransactionStatus.setText(mContext.getString(R.string.status_remit_address_missing)); + } else if (orderListResp.status.equals("UCRV")) { + holder.itemBinding.textTransactionStatus.setText(mContext.getString(R.string.status_under_review)); + } else if (orderListResp.status.equals("PAYP")) { + holder.itemBinding.textTransactionStatus.setText(mContext.getString(R.string.status_done_pending_delivery)); + } else if (orderListResp.status.equals("SENT")) { + holder.itemBinding.textTransactionStatus.setText(mContext.getString(R.string.status_done_units_delivered)); + } + + } else if (orderListResp.id == -3) { + + holder.itemBinding.layoutCompletionDetail.setVisibility(View.GONE); + holder.itemBinding.layHelpInstruction.setVisibility(View.GONE); + holder.itemBinding.layLogout.setVisibility(View.GONE); + holder.itemBinding.layOrderHistory.setVisibility(View.VISIBLE); + + } else if (orderListResp.id == -2) { + + holder.itemBinding.layoutCompletionDetail.setVisibility(View.GONE); + holder.itemBinding.layHelpInstruction.setVisibility(View.GONE); + holder.itemBinding.layLogout.setVisibility(View.VISIBLE); + holder.itemBinding.layOrderHistory.setVisibility(View.GONE); + + holder.itemBinding.textMessage.setText(mContext.getString(R.string.wallet_is_signed) + " " + + buyDashPref.getPhone()); + + holder.itemBinding.btnSignout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + historyFragment.deleteAuthCall(false); + } + }); + + + } else if (orderListResp.id == -1) { + + holder.itemBinding.layoutCompletionDetail.setVisibility(View.GONE); + holder.itemBinding.layHelpInstruction.setVisibility(View.VISIBLE); + holder.itemBinding.layLogout.setVisibility(View.GONE); + holder.itemBinding.layOrderHistory.setVisibility(View.GONE); + + holder.itemBinding.textHelpMessage.setText(R.string.call_for_help); + holder.itemBinding.btnWebLink.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //goToUrl(WOCConstants.KEY_WEB_URL); + historyFragment.goToGivenUrl(WOCConstants.KEY_WEB_URL); + } + }); + } + + } + + + @Override + public int getItemCount() { + return orderList.size(); + } + + public class VHolder extends RecyclerView.ViewHolder { + private LayoutItemOrderListBinding itemBinding; + + + public VHolder(LayoutItemOrderListBinding itemBinding) { + super(itemBinding.getRoot()); + this.itemBinding = itemBinding; + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/PhoneListAdapter.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/PhoneListAdapter.java new file mode 100644 index 000000000..0df7d51ae --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/adapters/PhoneListAdapter.java @@ -0,0 +1,68 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.adapters; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +import java.util.ArrayList; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.models.PhoneListVO; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.phone_list.PhoneListFragment; + +/** + * Created on 19-Mar-18. + */ + +public class PhoneListAdapter extends RecyclerView.Adapter { + + private Context mContext; + private ArrayList phoneListVOS; + private PhoneListFragment fragment; + + public PhoneListAdapter(Context context, ArrayList phoneListVOS, PhoneListFragment fragment) { + this.mContext = context; + this.phoneListVOS = phoneListVOS; + this.fragment = fragment; + } + + @Override + public PhoneListAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_phone_list, parent, false); + + return new MyViewHolder(itemView); + } + + @Override + public void onBindViewHolder(PhoneListAdapter.MyViewHolder holder, int position) { + final PhoneListVO phoneListVO = phoneListVOS.get(holder.getAdapterPosition()); + + holder.btnPhone.setText(mContext.getString(R.string.sign_in2, phoneListVO.getPhoneNumber())); + + holder.btnPhone.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + fragment.getAuthTokenCall(phoneListVO.getPhoneNumber(), phoneListVO.getDeviceId()); + } + }); + + } + + @Override + public int getItemCount() { + return phoneListVOS.size(); + } + + public class MyViewHolder extends RecyclerView.ViewHolder { + private Button btnPhone; + + private MyViewHolder(View view) { + super(view); + this.btnPhone = (Button) view.findViewById(R.id.btnPhone); + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/buy_dash_location/BuyDashLocationFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/buy_dash_location/BuyDashLocationFragment.java new file mode 100644 index 000000000..c8dd381e3 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/buy_dash_location/BuyDashLocationFragment.java @@ -0,0 +1,516 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.buy_dash_location; + +import android.content.Context; +import android.content.SharedPreferences; +import android.location.Address; +import android.location.Geocoder; +import android.location.Location; +import android.location.LocationManager; +import android.os.Bundle; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.gson.Gson; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.api.WallofCoins; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.offer_amount.BuyDashOfferAmountFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.order_history.OrderHistoryFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.phone_list.PhoneListFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.verification_otp.VerifycationOtpFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.zip.BuyDashZipFragment; +import pivx.org.pivxwallet.wallofcoins.response.BuyDashErrorResp; +import pivx.org.pivxwallet.wallofcoins.response.CheckAuthResp; +import pivx.org.pivxwallet.wallofcoins.response.CreateDeviceResp; +import pivx.org.pivxwallet.wallofcoins.response.GetAuthTokenResp; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 6/3/18. + */ + +public class BuyDashLocationFragment extends BuyDashBaseFragment implements View.OnClickListener, + SharedPreferences.OnSharedPreferenceChangeListener { + + + private View rootView; + private Button button_buy_dash_get_location, button_buy_dash_get_location_no, btn_sign_out_woc, + btn_order_history_woc, btn_sign_in_woc; + private TextView txtViewLocationMessage, text_message_sign_out, text_message_sign_in; + private String zipCode, password; + private double latitude, longitude; + private final String TAG = "BuyDashOfferAmtFragment"; + private LinearLayout layout_sign_out, linear_progress, layout_sign_in; + private CreateDeviceResp createDeviceResp; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Override + public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { + + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_buy_dash_location, container, false); + init(); + setListeners(); + + return rootView; + } else + return rootView; + } + + private void init() { + + button_buy_dash_get_location_no = (Button) rootView.findViewById(R.id.button_buy_dash_get_location_no); + button_buy_dash_get_location = (Button) rootView.findViewById(R.id.button_buy_dash_get_location); + txtViewLocationMessage = (TextView) rootView.findViewById(R.id.txtViewLocationMessage); + btn_sign_out_woc = (Button) rootView.findViewById(R.id.btn_sign_out_woc); + text_message_sign_out = (TextView) rootView.findViewById(R.id.text_message_sign_out); + layout_sign_out = (LinearLayout) rootView.findViewById(R.id.layout_sign_out); + linear_progress = (LinearLayout) rootView.findViewById(R.id.linear_progress); + btn_order_history_woc = (Button) rootView.findViewById(R.id.btn_order_history_woc); + layout_sign_in = (LinearLayout) rootView.findViewById(R.id.layout_sign_in); + text_message_sign_in = (TextView) rootView.findViewById(R.id.text_message_sign_in); + btn_sign_in_woc = (Button) rootView.findViewById(R.id.btn_sign_in_woc); + } + + private void setListeners() { + button_buy_dash_get_location.setOnClickListener(this); + button_buy_dash_get_location_no.setOnClickListener(this); + btn_sign_out_woc.setOnClickListener(this); + btn_order_history_woc.setOnClickListener(this); + btn_sign_in_woc.setOnClickListener(this); + } + + private void navigateToVerifyOtp(String otp) { + Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.VERIFICATION_OTP, otp); + VerifycationOtpFragment otpFragment = new VerifycationOtpFragment(); + otpFragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(otpFragment, true, true); + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.button_buy_dash_get_location: + if (checkPermissions()) + getZip(); + else + requestLocationPermission(); + break; + + case R.id.button_buy_dash_get_location_no: + ((BuyDashBaseActivity) mContext).replaceFragment(new BuyDashZipFragment(), true, true); + break; + case R.id.btn_sign_out_woc: + deleteAuthCall(false); + break; + case R.id.btn_order_history_woc: + navigateToOrderList(false); + break; + case R.id.btn_sign_in_woc: + ((BuyDashBaseActivity) mContext).replaceFragment(new PhoneListFragment(), true, true); + break; + + } + } + + private void navigateToOrderList(boolean isFromCreateHold) { + OrderHistoryFragment historyFragment = new OrderHistoryFragment(); + Bundle bundle = new Bundle(); + bundle.putBoolean("isFromCreateHold", isFromCreateHold); + historyFragment.setArguments(bundle); + ((BuyDashBaseActivity) mContext).replaceFragment(historyFragment, true, true); + } + + @Override + public void onResume() { + super.onResume(); + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + layout_sign_out.setVisibility(View.VISIBLE); + layout_sign_in.setVisibility(View.GONE); + text_message_sign_out.setText(mContext.getString(R.string.wallet_is_signed) + " " + + ((BuyDashBaseActivity) mContext).buyDashPref.getPhone()); + } else { + layout_sign_out.setVisibility(View.GONE); + layout_sign_in.setVisibility(View.VISIBLE); + } + } + + /** + * User authentication custom dialog for authenticate user using password + */ + private void showUserPasswordAuthenticationDialog() { + + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View dialogView = inflater.inflate(R.layout.layout_authenticate_password_wallet_dialog, null); + dialogBuilder.setView(dialogView); + + final EditText edtPassword = (EditText) dialogView.findViewById(R.id.edt_woc_authenticaion_password); + TextView txtTitle = (TextView) dialogView.findViewById(R.id.txt_existing_user_dialog_message); + Button btnLogin = (Button) dialogView.findViewById(R.id.btnLogin); + Button btnForgotPassword = (Button) dialogView.findViewById(R.id.btnForgotPassword); + + txtTitle.setMovementMethod(LinkMovementMethod.getInstance()); + + final AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.show(); + + ImageView imgClose = (ImageView) dialogView.findViewById(R.id.imgClose); + + imgClose.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + alertDialog.dismiss(); + } + }); + + btnForgotPassword.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + goToUrl(WOCConstants.KEY_FORGOT_PASSWORD_URL); + } + }); + + btnLogin.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + password = edtPassword.getText().toString().trim(); + if (password.length() > 0) { + getAuthTokenCall(password); + alertDialog.dismiss(); + } else { + showToast(mContext.getString(R.string.password_alert)); + } + } + }); + + } + + /** + * Authorized user using password or device code + * + * @param password + */ + private void getAuthTokenCall(final String password) { + if (NetworkUtil.isOnline(mContext)) { + String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + + if (!TextUtils.isEmpty(phone)) { + + HashMap getAuthTokenReq = new HashMap(); + if (!TextUtils.isEmpty(password)) { + getAuthTokenReq.put(WOCConstants.KEY_PASSWORD, password); + } else { + getAuthTokenReq.put(WOCConstants.KEY_DEVICECODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + } + + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId())) { + getAuthTokenReq.put(WOCConstants.KEY_DEVICEID, ((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()); + } + + getAuthTokenReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + + linear_progress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).getAuthToken(phone, getAuthTokenReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + linear_progress.setVisibility(View.GONE); + int code = response.code(); + + if (code >= 400 && response.body() == null) { + try { + BuyDashErrorResp buyDashErrorResp = new Gson().fromJson(response.errorBody().string(), BuyDashErrorResp.class); + if (!TextUtils.isEmpty(password)) { + showAlertPasswordDialog(); + } else { + createDevice(); + } + } catch (Exception e) { + e.printStackTrace(); + showToast(mContext.getString(R.string.try_again)); + } + return; + } + + if (!TextUtils.isEmpty(response.body().token)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(response.body().token); + } + // hideViewExcept(null); + if (!TextUtils.isEmpty(password) && TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId())) { + getDevice(); + } else { + //createHold(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(mContext.getString(R.string.try_again)); + linear_progress.setVisibility(View.GONE); + } + }); + + } else { + showToast(mContext.getString(R.string.alert_phone_password_required)); + } + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Get Devices for Register user with password + */ + private void getDevice() { + if (NetworkUtil.isOnline(mContext)) { + linear_progress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).getDevice().enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (response.code() == 200 && response.body() != null) { + List deviceList = response.body(); + if (deviceList.size() > 0) { + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(deviceList.get(deviceList.size() - 1).getId() + ""); + getAuthTokenCall(""); + } else { + createDevice(); + } + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + linear_progress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Method for register new device + */ + private void createDevice() { + if (NetworkUtil.isOnline(mContext)) { + final HashMap createDeviceReq = new HashMap(); + createDeviceReq.put(WOCConstants.KEY_DEVICE_NAME, mContext.getString(R.string.pivx_wallet_name)); + createDeviceReq.put(WOCConstants.KEY_DEVICE_CODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + createDeviceReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + linear_progress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).createDevice(createDeviceReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (null != response.body() && response.code() < 299) { + createDeviceResp = response.body(); + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(createDeviceResp.getId() + ""); + getAuthTokenCall(""); + } else { + showToast(mContext.getString(R.string.try_again)); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(mContext.getString(R.string.try_again)); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Method for check authentication type + */ + private void checkAuth() { + if (NetworkUtil.isOnline(mContext)) { + String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + if (!TextUtils.isEmpty(phone)) { + linear_progress.setVisibility(View.VISIBLE); + + WallofCoins.createService(interceptor, mContext).checkAuth(phone, getString(R.string.WALLOFCOINS_PUBLISHER_ID)).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Log.d(TAG, "onResponse: response code==>>" + response.code()); + linear_progress.setVisibility(View.GONE); + if (response.code() == 200) { + if (response.body() != null + && response.body().getAvailableAuthSources() != null + && response.body().getAvailableAuthSources().size() > 0) { + if (response.body().getAvailableAuthSources().get(0).equals("password")) { + showUserPasswordAuthenticationDialog(); + return; + } else if ((response.body().getAvailableAuthSources().size() >= 2 + && response.body().getAvailableAuthSources().get(1).equals("device")) + || (response.body().getAvailableAuthSources().get(0).equals("device"))) { + hideKeyBoard(); + //createHold(); + } + } + } else if (response.code() == 404) { + hideKeyBoard(); + //createHold(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linear_progress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else { + showToast(mContext.getString(R.string.alert_phone)); + } + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Method for singout user + * + * @param isPendingHold + */ + public void deleteAuthCall(final boolean isPendingHold) { + if (NetworkUtil.isOnline(mContext)) { + final String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + if (!TextUtils.isEmpty(phone)) { + linear_progress.setVisibility(View.VISIBLE); + password = ""; + WallofCoins.createService(interceptor, mContext) + .deleteAuth(phone, getString(R.string.WALLOFCOINS_PUBLISHER_ID)) + .enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Log.d(TAG, "onResponse: response code==>>" + response.code()); + linear_progress.setVisibility(View.GONE); + if (response.code() < 299) { + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(""); + password = ""; + ((BuyDashBaseActivity) mContext).buyDashPref.clearAllPrefrance(); + if (isPendingHold) { + // binding.editBuyDashPhone.setText(null); + checkAuth(); + } else { + showToast(mContext.getString(R.string.alert_sign_out)); + layout_sign_in.setVisibility(View.VISIBLE); + layout_sign_out.setVisibility(View.GONE); + //hideViewExcept(binding.layoutLocation); + + } + } else { + showToast(mContext.getString(R.string.try_again)); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linear_progress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else { + showToast(mContext.getString(R.string.alert_phone)); + } + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Get ZipCode for device current location + */ + private void getZip() { + + Location myLocation = getLastKnownLocation(); + if (myLocation != null) { + + Geocoder geocoder; + List
addresses; + geocoder = new Geocoder(mContext, Locale.getDefault()); + if (geocoder != null) { + try { + addresses = geocoder.getFromLocation(myLocation.getLatitude(), myLocation.getLongitude(), 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5 + latitude = myLocation.getLatitude(); + longitude = myLocation.getLongitude(); + zipCode = addresses.get(0).getPostalCode(); + navigateToOtherScreen(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + } else { + LocationManager mlocManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); + boolean enabled = mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + + if (!enabled) { + showDialogGPS(); + } + } + } + + private void navigateToOtherScreen() { + Bundle bundle = new Bundle(); + bundle.putDouble(WOCConstants.LATITUDE, latitude); + bundle.putDouble(WOCConstants.LONGITUDE, longitude); + bundle.putString(WOCConstants.ZIP, zipCode); + BuyDashOfferAmountFragment offerAmountFragment = new BuyDashOfferAmountFragment(); + offerAmountFragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(offerAmountFragment, true, true); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + + } + + //this method remove animation when user want to clear back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/email_phone/EmailAndPhoneFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/email_phone/EmailAndPhoneFragment.java new file mode 100644 index 000000000..9d99ddc85 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/email_phone/EmailAndPhoneFragment.java @@ -0,0 +1,657 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.email_phone; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.Gson; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.CustomAdapter; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.api.WallofCoins; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.order_history.OrderHistoryFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.BuyDashPhoneListPref; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.verification_otp.VerifycationOtpFragment; +import pivx.org.pivxwallet.wallofcoins.response.CheckAuthResp; +import pivx.org.pivxwallet.wallofcoins.response.CountryData; +import pivx.org.pivxwallet.wallofcoins.response.CreateDeviceResp; +import pivx.org.pivxwallet.wallofcoins.response.CreateHoldResp; +import pivx.org.pivxwallet.wallofcoins.response.GetAuthTokenResp; +import pivx.org.pivxwallet.wallofcoins.response.GetHoldsResp; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 08-Mar-18. + */ + +public class EmailAndPhoneFragment extends BuyDashBaseFragment implements View.OnClickListener, SharedPreferences.OnSharedPreferenceChangeListener { + + private final String TAG = "EmailAndPhoneFragment"; + private View rootView; + private LinearLayout linearProgress, linear_email, linear_phone, layout_hold; + private CountryData countryData; + private Spinner sp_country; + private Button btn_next_phone, btn_next_email, btn_sign_in; + private String country_code = "", phone_no = "", email = "", password = "", offerId = ""; + private EditText edit_buy_dash_phone, edit_buy_dash_email; + private TextView tv_skip_email; + private CreateDeviceResp createDeviceResp; + private CreateHoldResp createHoldResp; + private BuyDashPhoneListPref credentilasPref; + private String fromScreen = ""; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_buy_dash_email_and_phone, container, false); + init(); + addCountryCodeList(); + setListeners(); + handleArgs(); + return rootView; + } else + return rootView; + } + + private void init() { + credentilasPref = new BuyDashPhoneListPref(PreferenceManager.getDefaultSharedPreferences(mContext)); + + linearProgress = (LinearLayout) rootView.findViewById(R.id.linear_progress); + linear_email = (LinearLayout) rootView.findViewById(R.id.linear_email); + sp_country = (Spinner) rootView.findViewById(R.id.sp_country); + btn_next_phone = (Button) rootView.findViewById(R.id.btn_next_phone); + edit_buy_dash_phone = (EditText) rootView.findViewById(R.id.edit_buy_dash_phone); + btn_next_email = (Button) rootView.findViewById(R.id.btn_next_email); + edit_buy_dash_email = (EditText) rootView.findViewById(R.id.edit_buy_dash_email); + linear_phone = (LinearLayout) rootView.findViewById(R.id.linear_phone); + layout_hold = (LinearLayout) rootView.findViewById(R.id.layout_hold); + tv_skip_email = (TextView) rootView.findViewById(R.id.tv_skip_email); + btn_sign_in = (Button) rootView.findViewById(R.id.btn_sign_in); + } + + private void setListeners() { + btn_next_phone.setOnClickListener(this); + btn_next_email.setOnClickListener(this); + tv_skip_email.setOnClickListener(this); + btn_sign_in.setOnClickListener(this); + } + + /** + * handle the arguments according to user come from previos screen + */ + private void handleArgs() { + if (getArguments() != null) { + if (getArguments().containsKey(WOCConstants.OFFER_ID)) { + offerId = getArguments().getString(WOCConstants.OFFER_ID); + } + if (getArguments().containsKey(WOCConstants.SCREEN_TYPE)) { + fromScreen = getArguments().getString(WOCConstants.SCREEN_TYPE); + } + } + } + + public void changeView() { + if (linear_email.getVisibility() == View.VISIBLE) + ((BuyDashBaseActivity) mContext).popBackDirect(); + else if (linear_phone.getVisibility() == View.GONE) { + layout_hold.setVisibility(View.GONE); + linear_phone.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + + } else if (linear_email.getVisibility() == View.GONE) { + linear_email.setVisibility(View.VISIBLE); + linear_phone.setVisibility(View.GONE); + layout_hold.setVisibility(View.GONE); + } + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.btn_next_phone: + if (isValidPhone()) { + hideKeyBoard(); + // if (!offerId.isEmpty()) { + country_code = countryData.countries.get(sp_country.getSelectedItemPosition()).code; + phone_no = edit_buy_dash_phone.getText().toString().trim(); + String phone = country_code + edit_buy_dash_phone.getText().toString().trim(); + ((BuyDashBaseActivity) mContext).buyDashPref.setPhone(phone); + + checkAuth(); + /*} else { + showToast(getString(R.string.offerid_not_available)); + ((BuyDashBaseActivity) mContext).popBackDirect(); + }*/ + } + break; + + case R.id.btn_next_email: + if (!edit_buy_dash_email.getText().toString().isEmpty() && isValidEmail(edit_buy_dash_email.getText().toString())) { + email = edit_buy_dash_email.getText().toString(); + linear_phone.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + // hideViewExcept(binding.linearPhone); + } else { + showToast(mContext.getString(R.string.alert_enter_valid_email)); + } + break; + case R.id.tv_skip_email: + /* binding.tvSkipEmail.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + hideViewExcept(binding.linearPhone); + } + });*/ + linear_phone.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + break; + case R.id.btn_sign_in: + goToUrl("https://wallofcoins.com/signin/" + country_code.replace("+", "") + "-" + phone_no + "/"); + break; + } + } + + private boolean isValidPhone() { + if (edit_buy_dash_phone.getText().toString().trim().isEmpty()) { + edit_buy_dash_phone.requestFocus(); + showToast(mContext.getString(R.string.please_enter_phone_no)); + return false; + } else if (edit_buy_dash_phone.getText().toString().trim().length() < 10) { + edit_buy_dash_phone.requestFocus(); + showToast(mContext.getString(R.string.please_enter_10_digits_phone_no)); + return false; + } + return true; + } + + //add country code list for phone + private void addCountryCodeList() { + String json; + try { + InputStream is = getActivity().getAssets().open("countries.json"); + int size = is.available(); + byte[] buffer = new byte[size]; + is.read(buffer); + is.close(); + json = new String(buffer, "UTF-8"); + } catch (IOException ex) { + ex.printStackTrace(); + return; + } + + countryData = new Gson().fromJson(json, CountryData.class); + + List stringList = new ArrayList<>(); + + for (CountryData.CountriesBean bean : countryData.countries) { + stringList.add(bean.name + " (" + bean.code + ")"); + } + CustomAdapter customAdapter = new CustomAdapter(getActivity(), R.layout.spinner_row_country, countryData.countries); + customAdapter.setDropDownViewResource(R.layout.spinner_row_country); + sp_country.setAdapter(customAdapter); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + + } + + /** + * Method for check authentication type + */ + private void checkAuth() { + if (NetworkUtil.isOnline(mContext)) { + String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + if (!TextUtils.isEmpty(phone)) { + linearProgress.setVisibility(View.VISIBLE); + + WallofCoins.createService(interceptor, mContext).checkAuth(phone, getString(R.string.WALLOFCOINS_PUBLISHER_ID)).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Log.d(TAG, "onResponse: response code==>>" + response.code()); + linearProgress.setVisibility(View.GONE); + if (response.code() == 200) { + if (response.body() != null + && response.body().getAvailableAuthSources() != null + && response.body().getAvailableAuthSources().size() > 0) { + + if (response.body().getAvailableAuthSources().get(0).equals("password")) {//from wesite + showUserPasswordAuthenticationDialog(); + return; + } else if ((response.body().getAvailableAuthSources().size() >= 2//from mobile + && response.body().getAvailableAuthSources().get(1).equals("device")) + || (response.body().getAvailableAuthSources().get(0).equals("device"))) { + hideKeyBoard(); + createHold(); + } + } + } else if (response.code() == 404) { + hideKeyBoard(); + createHold(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else { + showToast(mContext.getString(R.string.alert_phone)); + } + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } + + /** + * User authentication custom dialog for authenticate user using password + */ + private void showUserPasswordAuthenticationDialog() { + + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View dialogView = inflater.inflate(R.layout.layout_authenticate_password_wallet_dialog, null); + dialogBuilder.setView(dialogView); + + final EditText edtPassword = (EditText) dialogView.findViewById(R.id.edt_woc_authenticaion_password); + TextView txtTitle = (TextView) dialogView.findViewById(R.id.txt_existing_user_dialog_message); + Button btnLogin = (Button) dialogView.findViewById(R.id.btnLogin); + Button btnForgotPassword = (Button) dialogView.findViewById(R.id.btnForgotPassword); + + txtTitle.setMovementMethod(LinkMovementMethod.getInstance()); + + final AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.show(); + + ImageView imgClose = (ImageView) dialogView.findViewById(R.id.imgClose); + + imgClose.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + alertDialog.dismiss(); + } + }); + + btnForgotPassword.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + goToUrl(WOCConstants.KEY_FORGOT_PASSWORD_URL); + } + }); + + btnLogin.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + password = edtPassword.getText().toString().trim(); + if (password.length() > 0) { + getAuthTokenCall(password); + alertDialog.dismiss(); + } else { + showToast(mContext.getString(R.string.password_alert)); + } + } + }); + + } + + /** + * Authorized user using password or device code + * + * @param password + */ + private void getAuthTokenCall(final String password) { + if (NetworkUtil.isOnline(mContext)) { + String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + + if (!TextUtils.isEmpty(phone)) { + + HashMap getAuthTokenReq = new HashMap(); + if (!TextUtils.isEmpty(password)) { + getAuthTokenReq.put(WOCConstants.KEY_PASSWORD, password); + } else { + getAuthTokenReq.put(WOCConstants.KEY_DEVICECODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + } + + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId())) { + getAuthTokenReq.put(WOCConstants.KEY_DEVICEID, ((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()); + } + + getAuthTokenReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).getAuthToken(phone, getAuthTokenReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + linearProgress.setVisibility(View.GONE); + int code = response.code(); + + if (code >= 400 && response.body() == null) { + try { + //BuyDashErrorResp buyDashErrorResp = new Gson().fromJson(response.errorBody().string(), BuyDashErrorResp.class); + if (!TextUtils.isEmpty(password)) { + showAlertPasswordDialog(); + } else { + createDevice(); + } + } catch (Exception e) { + e.printStackTrace(); + showToast(mContext.getString(R.string.try_again)); + } + return; + } + + if (!TextUtils.isEmpty(response.body().token)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(response.body().token); + } + //hideViewExcept(null); + if (!TextUtils.isEmpty(password) && TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId())) { + getDevice(); + } else { + credentilasPref.addPhone(country_code + edit_buy_dash_phone.getText().toString().trim(), ((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()); + if (fromScreen.equalsIgnoreCase("PhoneListFragment")) + ((BuyDashBaseActivity) mContext).popBackAllFragmentsExcept("pivx.org.pivxwallet.wallofcoins.buyingwizard.phone_list.PhoneListFragment"); + else + createHold(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(mContext.getString(R.string.try_again)); + linearProgress.setVisibility(View.GONE); + } + }); + + } else { + showToast(mContext.getString(R.string.alert_phone_password_required)); + } + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } + + /** + * Method for create new hold + */ + public void createHold() { + if (NetworkUtil.isOnline(mContext)) { + String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + + final HashMap createHoldPassReq = new HashMap(); + + if (TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + createHoldPassReq.put(WOCConstants.KEY_PHONE, phone); + createHoldPassReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + createHoldPassReq.put(WOCConstants.KEY_EMAIL, email); + createHoldPassReq.put(WOCConstants.KEY_deviceName, WOCConstants.KEY_DEVICE_NAME_VALUE); + createHoldPassReq.put(WOCConstants.KEY_DEVICECODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + } + createHoldPassReq.put(WOCConstants.KEY_OFFER, offerId); + + linearProgress.setVisibility(View.VISIBLE); + + WallofCoins.createService(interceptor, getActivity()).createHold(createHoldPassReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + linearProgress.setVisibility(View.GONE); + + if (null != response.body() && response.code() < 299) { + + createHoldResp = response.body(); + ((BuyDashBaseActivity) mContext).buyDashPref.setHoldId(createHoldResp.id); + ((BuyDashBaseActivity) mContext).buyDashPref.setCreateHoldResp(createHoldResp); + if (TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()) + && !TextUtils.isEmpty(createHoldResp.deviceId)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(createHoldResp.deviceId); + + //added + String phone = country_code + edit_buy_dash_phone.getText().toString().trim(); + credentilasPref.addPhone(phone, ((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()); + } + if (!TextUtils.isEmpty(response.body().token)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(createHoldResp.token); + } + navigateToVerifyOtp(createHoldResp.__PURCHASE_CODE); + //hideViewExcept(binding.layoutVerifyOtp); + //clearForm((ViewGroup) binding.getRoot()); + //binding.etOtp.setText(createHoldResp.__PURCHASE_CODE); + + } else if (null != response.errorBody()) { + if (response.code() == 403 && TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + + /* String token = credentilasPref.getAuthTokenFromPhoneNum(phone_no); + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(token); + getHolds();*/ + layout_hold.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + linear_phone.setVisibility(View.GONE); + //hideViewExcept(binding.layoutHold); + //clearForm((ViewGroup) binding.getRoot()); + } else if (response.code() == 403 && !TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + getHolds(); + } else if (response.code() == 400) { + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + navigateToOrderList(false); + } else { + layout_hold.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + linear_phone.setVisibility(View.GONE); + // hideViewExcept(binding.layoutHold); + //clearForm((ViewGroup) binding.getRoot()); + } + } else { + try { + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + navigateToOrderList(false); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } else { + //clearForm((ViewGroup) binding.getRoot()); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Toast.makeText(getContext(), R.string.try_again, Toast.LENGTH_SHORT).show(); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * navigate to otp code screen with code + * + * @param otp + */ + private void navigateToVerifyOtp(String otp) { + Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.VERIFICATION_OTP, otp); + VerifycationOtpFragment otpFragment = new VerifycationOtpFragment(); + otpFragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(otpFragment, true, true); + } + + /** + * Get all holds for delete active hold + */ + private void getHolds() { + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).getHolds().enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (response.code() == 200 && response.body() != null) { + linearProgress.setVisibility(View.GONE); + List holdsList = response.body(); + int holdCount = 0; + if (holdsList.size() > 0) { + for (int i = 0; i < holdsList.size(); i++) { + if (null != holdsList.get(i).status && holdsList.get(i).status.equals("AC")) { + deleteHold(holdsList.get(i).id); + holdCount++; + } + } + if (holdCount == 0) { + //getOrderList(false); + navigateToOrderList(false); + } + } else { + //getOrderList(false); + navigateToOrderList(false); + } + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + } + + private void navigateToOrderList(boolean isFromCreateHold) { + OrderHistoryFragment historyFragment = new OrderHistoryFragment(); + Bundle bundle = new Bundle(); + bundle.putBoolean("isFromCreateHold", isFromCreateHold); + historyFragment.setArguments(bundle); + ((BuyDashBaseActivity) mContext).replaceFragment(historyFragment, true, true); + } + + /** + * Method call for delete for provide holdId + * + * @param holdId + */ + private void deleteHold(String holdId) { + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).deleteHold(holdId).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + createHold(); + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + } + + /** + * Get Devices for Register user with password + */ + private void getDevice() { + + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).getDevice().enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (response.code() == 200 && response.body() != null) { + linearProgress.setVisibility(View.GONE); + List deviceList = response.body(); + if (deviceList.size() > 0) { + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(deviceList.get(deviceList.size() - 1).getId() + ""); + getAuthTokenCall(""); + } else { + createDevice(); + } + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + + } + + /** + * Method for register new device + */ + private void createDevice() { + final HashMap createDeviceReq = new HashMap(); + createDeviceReq.put(WOCConstants.KEY_DEVICE_NAME, mContext.getString(R.string.pivx_wallet_name)); + createDeviceReq.put(WOCConstants.KEY_DEVICE_CODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + createDeviceReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).createDevice(createDeviceReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (null != response.body() && response.code() < 299) { + createDeviceResp = response.body(); + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(createDeviceResp.getId() + ""); + getAuthTokenCall(""); + } else { + showToast(mContext.getString(R.string.try_again)); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(mContext.getString(R.string.try_again)); + } + }); + } + + //this method remove animation when user want to clear whole back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/models/AccountJson.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/models/AccountJson.java new file mode 100644 index 000000000..be84591a7 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/models/AccountJson.java @@ -0,0 +1,52 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.models; + +/** + * Created on 08-Mar-18. + */ + +public class AccountJson { + + /** + * displaySort : 0 + * name : fullName + * value : Ian Marshall + * label : Full Name + */ + + private String displaySort; + private String name; + private String value; + private String label; + + public String getDisplaySort() { + return displaySort; + } + + public void setDisplaySort(String displaySort) { + this.displaySort = displaySort; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } +} \ No newline at end of file diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/models/PhoneListVO.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/models/PhoneListVO.java new file mode 100644 index 000000000..a01477073 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/models/PhoneListVO.java @@ -0,0 +1,31 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.models; + +import java.io.Serializable; + +/** + * Created on 12-Mar-18. + */ + +public class PhoneListVO implements Serializable { + + private String phoneNumber = ""; + private String deviceId = ""; + + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/offer_amount/BuyDashOfferAmountFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/offer_amount/BuyDashOfferAmountFragment.java new file mode 100644 index 000000000..8b2f2fab2 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/offer_amount/BuyDashOfferAmountFragment.java @@ -0,0 +1,556 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.offer_amount; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.Nullable; +import android.support.v4.app.LoaderManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.Toast; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import org.bitcoinj.wallet.Wallet; +import org.pivxj.core.Address; + +import java.util.HashMap; +import java.util.List; + +import pivx.org.pivxwallet.PivxApplication; +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.module.PivxModule; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.adapters.BuyDashOffersAdapter; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.api.WallofCoins; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.email_phone.EmailAndPhoneFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.order_history.OrderHistoryFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.BuyDashAddressPref; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.verification_otp.VerifycationOtpFragment; +import pivx.org.pivxwallet.wallofcoins.response.BuyDashErrorResp; +import pivx.org.pivxwallet.wallofcoins.response.CreateHoldResp; +import pivx.org.pivxwallet.wallofcoins.response.DiscoveryInputsResp; +import pivx.org.pivxwallet.wallofcoins.response.GetHoldsResp; +import pivx.org.pivxwallet.wallofcoins.response.GetOffersResp; +import pivx.org.pivxwallet.wallofcoins.ui.CurrencyAmountView; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 07-Mar-18. + */ + +public class BuyDashOfferAmountFragment extends BuyDashBaseFragment implements View.OnClickListener, SharedPreferences.OnSharedPreferenceChangeListener { + + private View rootView; + private String zipCode; + private double latitude, longitude; + private Button button_buy_dash_get_offers; + private EditText request_coins_amount_btc_edittext, request_coins_amount_local_edittext, edtViewDollar; + private LinearLayout linearProgress, layout_create_hold; + private final String TAG = "BuyDashOfferFragment"; + private Wallet wallet; + private String keyAddress, offerId, dashAmount = "", bankId; + // private Configuration config; + //private WalletApplication application; + private RecyclerView rv_offers; + private CurrencyAmountView request_coins_amount_local, request_coins_amount_btc; + //private CurrencyCalculatorLink amountCalculatorLink; + private LoaderManager loaderManager; + private final int ID_RATE_LOADER = 1; + private CreateHoldResp createHoldResp; + private BuyDashAddressPref dashAddressPref; + private PivxModule module; + private Address address; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_buy_dash_offer_amount, container, false); + init(); + setListeners(); + handleArgs(); + return rootView; + } else + return rootView; + } + + + private void init() { + module = PivxApplication.getInstance().getModule(); + address = module.getReceiveAddress(); + this.loaderManager = getLoaderManager(); + dashAddressPref = new BuyDashAddressPref(PreferenceManager.getDefaultSharedPreferences(mContext)); + + button_buy_dash_get_offers = (Button) rootView.findViewById(R.id.button_buy_dash_get_offers); + //request_coins_amount_btc_edittext = (EditText) rootView.findViewById(R.id.request_coins_amount_btc_edittext); + //request_coins_amount_local_edittext = (EditText) rootView.findViewById(R.id.request_coins_amount_local_edittext); + linearProgress = (LinearLayout) rootView.findViewById(R.id.linear_progress); + layout_create_hold = (LinearLayout) rootView.findViewById(R.id.layout_create_hold); + //request_coins_amount_local = (CurrencyAmountView) rootView.findViewById(R.id.request_coins_amount_local); + //request_coins_amount_btc = (CurrencyAmountView) rootView.findViewById(R.id.request_coins_amount_btc); + edtViewDollar = (EditText) rootView.findViewById(R.id.edtViewDollar); + // request_coins_amount_btc.setCurrencySymbol(config.getFormat().code()); + // request_coins_amount_btc.setInputFormat(config.getMaxPrecisionFormat()); + //request_coins_amount_btc.setHintFormat(config.getFormat()); + + //request_coins_amount_local.setInputFormat(Constants.LOCAL_FORMAT); + // request_coins_amount_local.setHintFormat(Constants.LOCAL_FORMAT); + + //amountCalculatorLink = new CurrencyCalculatorLink(request_coins_amount_btc, request_coins_amount_local); + + rv_offers = (RecyclerView) rootView.findViewById(R.id.rv_offers); + rv_offers.setLayoutManager(new LinearLayoutManager(mContext)); + } + + private void setListeners() { + button_buy_dash_get_offers.setOnClickListener(this); + } + + /** + * handle the arguments according to user come from previos screen + */ + private void handleArgs() { + if (getArguments() != null) { + if (getArguments().containsKey(WOCConstants.LATITUDE)) { //user come from my location + latitude = getArguments().getDouble(WOCConstants.LATITUDE); + longitude = getArguments().getDouble(WOCConstants.LONGITUDE); + } + if (getArguments().containsKey(WOCConstants.ZIP)) { // user come with only zip + zipCode = getArguments().getString(WOCConstants.ZIP); + } + if (getArguments().containsKey(WOCConstants.BANK_ID)) {// user come from bank list + bankId = getArguments().getString(WOCConstants.BANK_ID); + } + } + } + + @Override + public void onViewCreated(final View view, final Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + //amountCalculatorLink.setExchangeDirection(config.getLastExchangeDirection()); + //amountCalculatorLink.requestFocus(); + } + + @Override + public void onResume() { + super.onResume(); + + } + + @Override + public void onPause() { + super.onPause(); + } + + @Override + public void onDestroy() { + loaderManager.destroyLoader(ID_RATE_LOADER); + super.onDestroy(); + } + + /** + * hide show view + */ + public void changeView() { + if (layout_create_hold.getVisibility() == View.GONE) { + layout_create_hold.setVisibility(View.VISIBLE); + rv_offers.setVisibility(View.GONE); + } else + ((BuyDashBaseActivity) mContext).popBackDirect(); + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.button_buy_dash_get_offers: + hideKeyBoard(); + if (isValidAmount()) + callDiscoveryInputs(); + break; + + + } + } + + private boolean isValidAmount() { + String amt=edtViewDollar.getText().toString().trim(); + + if (edtViewDollar.getText().toString().trim().isEmpty()) { + showToast(mContext.getString(R.string.alert_amount)); + return false; + } else if (amt.matches("^\\.$")) { + showToast(mContext.getString(R.string.enter_valid_amt)); + return false; + } else if (Double.parseDouble(edtViewDollar.getText().toString().trim()) < 5) { + showToast(mContext.getString(R.string.alert_puchase_amout)); + return false; + } else if (Double.parseDouble(edtViewDollar.getText().toString().trim()) > 1000000) { + showToast(mContext.getString(R.string.amount_less_than_1000000)); + return false; + } + return true; + } + + + private void callDiscoveryInputs() { + if (NetworkUtil.isOnline(mContext)) { + HashMap discoveryInputsReq = new HashMap(); + discoveryInputsReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + keyAddress = address.toBase58(); + dashAddressPref.setBuyDashAddress(keyAddress); + + discoveryInputsReq.put(WOCConstants.KEY_CRYPTO_ADDRESS, keyAddress); + String offerAmount = "0"; + + discoveryInputsReq.put(WOCConstants.KEY_USD_AMOUNT, "" + edtViewDollar.getText().toString()); + offerAmount = "" + edtViewDollar.getText().toString(); + /*try { + if (Float.valueOf(request_coins_amount_local.getTextView().getHint().toString()) > 0f) { + discoveryInputsReq.put(WOCConstants.KEY_USD_AMOUNT, "" + request_coins_amount_local.getTextView().getHint()); + offerAmount = "" + request_coins_amount_local_edittext.getHint(); + } else { + discoveryInputsReq.put(WOCConstants.KEY_USD_AMOUNT, "" + request_coins_amount_local.getTextView().getText()); + offerAmount = "" + request_coins_amount_local_edittext.getText(); + } + Log.d(TAG, "callDiscoveryInputs: usdAmount==>>" + request_coins_amount_local.getTextView().getHint()); + } catch (Exception e) { + discoveryInputsReq.put(WOCConstants.KEY_USD_AMOUNT, "0"); + e.printStackTrace(); + }*/ + + if (latitude > 0.0) + discoveryInputsReq.put(WOCConstants.KEY_COUNTRY, getCountryCode(latitude, longitude).toLowerCase()); + + //discoveryInputsReq.put(WOCConstants.KEY_CRYPTO, config.getFormat().code()); + discoveryInputsReq.put(WOCConstants.KEY_CRYPTO, WOCConstants.CRYPTO); + if (bankId != null) + discoveryInputsReq.put(WOCConstants.KEY_BANK, bankId); + + if (zipCode != null) + discoveryInputsReq.put(WOCConstants.KEY_ZIP_CODE, zipCode); + + if (latitude > 0.0) { + JsonObject jObj = new JsonObject(); + jObj.addProperty(WOCConstants.KEY_LATITUDE, latitude + ""); + jObj.addProperty(WOCConstants.KEY_LONGITUDE, longitude + ""); + + discoveryInputsReq.put(WOCConstants.KEY_BROWSE_LOCATION, jObj.toString()); + } + discoveryInputsReq.put(WOCConstants.KEY_CRYPTO_AMOUNT, "0"); + linearProgress.setVisibility(View.VISIBLE); + + final String finalOfferAmount = offerAmount; + WallofCoins.createService(interceptor, getActivity()) + .discoveryInputs(discoveryInputsReq) + .enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + + if (null != response && null != response.body()) { + if (null != response.body().id) { + updateAddressBookValue(keyAddress, WOCConstants.WOC_ADDRESS);// Update Address Book for Order + + WallofCoins.createService(null, getActivity()).getOffers(response.body().id, getString(R.string.WALLOFCOINS_PUBLISHER_ID)).enqueue(new Callback() { + @Override + public void onResponse(Call call, final Response response) { + + if (null != response && null != response.body()) { + + linearProgress.setVisibility(View.GONE); + + if (null != response.body().singleDeposit && !response.body().singleDeposit.isEmpty()) { + rv_offers.setVisibility(View.VISIBLE); + layout_create_hold.setVisibility(View.GONE); + + BuyDashOffersAdapter buyDashOffersAdapter = new BuyDashOffersAdapter(mContext, response.body(), finalOfferAmount, new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + hideKeyBoard(); + if (position < response.body().singleDeposit.size() + 1) { + offerId = response.body().singleDeposit.get(position - 1).id; + dashAmount = response.body().singleDeposit.get(position - 1).amount.DASH; + } else { + offerId = response.body().doubleDeposit.get(position - response.body().singleDeposit.size() - 2).id; + dashAmount = response.body().doubleDeposit.get(position - response.body().singleDeposit.size() - 2).totalAmount.DASH; + } + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + createHold(); + } else { + Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.OFFER_ID, offerId); + EmailAndPhoneFragment fragment = new EmailAndPhoneFragment(); + fragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(fragment, true, + true); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + linearProgress.setVisibility(View.GONE); + } + }); + rv_offers.setAdapter(buyDashOffersAdapter); + } else { + showToast(mContext.getString(R.string.alert_no_offers)); + } + } else if (null != response && null != response.errorBody()) { + linearProgress.setVisibility(View.GONE); + try { + BuyDashErrorResp buyDashErrorResp = new Gson().fromJson(response.errorBody().string(), BuyDashErrorResp.class); + Toast.makeText(getContext(), buyDashErrorResp.detail, Toast.LENGTH_LONG).show(); + } catch (Exception e) { + e.printStackTrace(); + showToast(mContext.getString(R.string.try_again)); + } + + } else { + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else { + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + } else if (null != response && null != response.errorBody()) { + + linearProgress.setVisibility(View.GONE); + + try { + BuyDashErrorResp buyDashErrorResp = new Gson().fromJson(response.errorBody().string(), BuyDashErrorResp.class); + if (buyDashErrorResp.detail != null && !TextUtils.isEmpty(buyDashErrorResp.detail)) { + Toast.makeText(getContext(), buyDashErrorResp.detail, Toast.LENGTH_LONG).show(); + } else { + showToast(mContext.getString(R.string.try_again)); + } + } catch (Exception e) { + e.printStackTrace(); + showToast(mContext.getString(R.string.try_again)); + } + + } else { + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + String message = t.getMessage(); + Log.d("failure", message); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Method for create new hold + */ + public void createHold() { + if (NetworkUtil.isOnline(mContext)) { + String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + + final HashMap createHoldPassReq = new HashMap(); + + if (TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + createHoldPassReq.put(WOCConstants.KEY_PHONE, phone); + createHoldPassReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + //createHoldPassReq.put(WOCConstants.KEY_EMAIL, email); + createHoldPassReq.put(WOCConstants.KEY_deviceName, WOCConstants.KEY_DEVICE_NAME_VALUE); + createHoldPassReq.put(WOCConstants.KEY_DEVICECODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + } + createHoldPassReq.put(WOCConstants.KEY_OFFER, offerId); + + linearProgress.setVisibility(View.VISIBLE); + + WallofCoins.createService(interceptor, getActivity()).createHold(createHoldPassReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + linearProgress.setVisibility(View.GONE); + + if (null != response.body() && response.code() < 299) { + + createHoldResp = response.body(); + ((BuyDashBaseActivity) mContext).buyDashPref.setHoldId(createHoldResp.id); + ((BuyDashBaseActivity) mContext).buyDashPref.setCreateHoldResp(createHoldResp); + if (TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()) + && !TextUtils.isEmpty(createHoldResp.deviceId)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(createHoldResp.deviceId); + } + if (!TextUtils.isEmpty(response.body().token)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(createHoldResp.token); + } + navigateToVerifyOtp(createHoldResp.__PURCHASE_CODE); + + } else if (null != response.errorBody()) { + if (response.code() == 403 && TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + } else if (response.code() == 403 && !TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + getHolds(); + } else if (response.code() == 400) { + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + navigateToOrderList(false); + } + } else { + try { + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + navigateToOrderList(false); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + + } + + /** + * Get all holds for delete active hold + */ + private void getHolds() { + if (NetworkUtil.isOnline(mContext)) { + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).getHolds().enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + linearProgress.setVisibility(View.GONE); + if (response.code() == 200 && response.body() != null) { + List holdsList = response.body(); + int holdCount = 0; + if (holdsList.size() > 0) { + for (int i = 0; i < holdsList.size(); i++) { + if (null != holdsList.get(i).status && holdsList.get(i).status.equals("AC")) { + deleteHold(holdsList.get(i).id); + holdCount++; + } + } + if (holdCount == 0) { + navigateToOrderList(false); + } + } else { + navigateToOrderList(false); + } + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Method call for delete for provide holdId + * + * @param holdId + */ + private void deleteHold(String holdId) { + if (NetworkUtil.isOnline(mContext)) { + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).deleteHold(holdId).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + createHold(); + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + private void navigateToOrderList(boolean isFromCreateHold) { + OrderHistoryFragment historyFragment = new OrderHistoryFragment(); + Bundle bundle = new Bundle(); + bundle.putBoolean("isFromCreateHold", isFromCreateHold); + historyFragment.setArguments(bundle); + ((BuyDashBaseActivity) mContext).replaceFragment(historyFragment, true, true); + } + + private void navigateToVerifyOtp(String otp) { + Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.VERIFICATION_OTP, otp); + VerifycationOtpFragment otpFragment = new VerifycationOtpFragment(); + otpFragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(otpFragment, true, true); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + + } + + //this method remove animation when user want to clear back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/order_history/OrderHistoryFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/order_history/OrderHistoryFragment.java new file mode 100644 index 000000000..8a87fe491 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/order_history/OrderHistoryFragment.java @@ -0,0 +1,617 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.order_history; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.Html; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.Gson; + +import java.lang.ref.WeakReference; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.api.WallofCoins; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.adapters.OrderListAdapter; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.buy_dash_location.BuyDashLocationFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.response.BuyDashErrorResp; +import pivx.org.pivxwallet.wallofcoins.response.CaptureHoldResp; +import pivx.org.pivxwallet.wallofcoins.response.CheckAuthResp; +import pivx.org.pivxwallet.wallofcoins.response.ConfirmDepositResp; +import pivx.org.pivxwallet.wallofcoins.response.OrderListResp; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 08-Mar-18. + */ + +public class OrderHistoryFragment extends BuyDashBaseFragment implements SharedPreferences.OnSharedPreferenceChangeListener, View.OnClickListener { + + private final String TAG = "OrderHistoryFragment"; + private View rootView; + private RecyclerView rv_order_list; + private LinearLayout linearProgress, layoutOrderHistory, layoutInstruction, layoutLogout; + private Button btn_buy_more, btnSignout, btnWebLink; + private boolean isFromCreateHold; + private OrderHistoryFragment fragment; + private int countdownInterval = 1000; + private TextView text_email_receipt, text_no_order, text_message, textHelpMessage; + private Handler handler; + private MyRunnable myRunnable; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_buy_dash_order_history, container, false); + init(); + setListeners(); + handleArgs(); + getOrderList(isFromCreateHold); + return rootView; + } else + return rootView; + } + + private void init() { + fragment = this; + rv_order_list = (RecyclerView) rootView.findViewById(R.id.rv_order_list); + linearProgress = (LinearLayout) rootView.findViewById(R.id.linear_progress); + layoutOrderHistory = (LinearLayout) rootView.findViewById(R.id.layout_order_list); + layoutInstruction = (LinearLayout) rootView.findViewById(R.id.lay_help_instruction_order); + layoutLogout = (LinearLayout) rootView.findViewById(R.id.lay_logout_order); + text_message = (TextView ) rootView.findViewById(R.id.text_message); + textHelpMessage = (TextView ) rootView.findViewById(R.id.text_help_message); + btnSignout = (Button) rootView.findViewById(R.id.btn_signout); + btnWebLink = (Button) rootView.findViewById(R.id.btn_WebLink); + btn_buy_more = (Button) rootView.findViewById(R.id.btn_buy_more); + text_email_receipt = (TextView) rootView.findViewById(R.id.text_email_receipt); + text_no_order = (TextView) rootView.findViewById(R.id.text_no_order_history); + } + + private void setListeners() { + btn_buy_more.setOnClickListener(this); + btnSignout.setOnClickListener(this); + btnWebLink.setOnClickListener(this); + } + + private void handleArgs() { + + if (getArguments() != null && getArguments().containsKey("isFromCreateHold")) + isFromCreateHold = getArguments().getBoolean("isFromCreateHold"); + + } + + /** + * Get order list using auth token + * + * @param isFromCreateHold + */ + private void getOrderList(final boolean isFromCreateHold) { + if (NetworkUtil.isOnline(mContext)) { + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, mContext) + .getOrders(getString(R.string.WALLOFCOINS_PUBLISHER_ID)) + .enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + linearProgress.setVisibility(View.GONE); + if (response.code() == 200 && response.body() != null) { + Log.d(TAG, "onResponse: boolean==>" + isFromCreateHold); + if (response.body() != null && response.body().size() > 0) { + if (isFromCreateHold) { + List orderList = new ArrayList<>(); + for (OrderListResp orderListResp : response.body()) { + if (orderListResp.status.equals("WD")) { + Log.d(TAG, "onResponse: status==>" + orderListResp.status); + orderList.add(orderListResp); + break; + } + } + if (orderList.size() > 0) { + manageOrderList(orderList, isFromCreateHold); + } else { + manageOrderList(response.body(), isFromCreateHold); + } + } else { + manageOrderList(response.body(), false); + } + } else { + //hideViewExcept(binding.layoutLocation); + //navigateToLocationScreen(); + blankOrderHistory(); + } + } else if (response.code() == 403) { + //hideViewExcept(binding.layoutLocation); + //((BuyDashBaseActivity)mContext).popBackAllFragmentsExcept("de.schildbach.wallet.wallofcoins.buyingwizard.buy_dash_location.BuyDashLocationFragment"); + ((BuyDashBaseActivity) mContext).removeAllFragmentFromStack(); + navigateToLocationScreen(); + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Method for manage order list + * + * @param orderList + * @param isFromCreateHold + */ + private void manageOrderList(final List orderList, boolean isFromCreateHold) { + + if (orderList.size() > 0) { + //hideViewExcept(binding.layoutOrderList); + for (OrderListResp orderListResp : orderList) { + if (orderListResp.status.equals("WD")) { + btn_buy_more.setVisibility(View.GONE); + break; + } else { + btn_buy_more.setVisibility(View.VISIBLE); + } + } + + int lastWDV = -1; + for (int i = 0; i < orderList.size(); i++) { + if (orderList.get(i).status.equals("WD")) { + if(i != 0){ + OrderListResp tempOrder = orderList.get(i); + orderList.remove(i); + orderList.add(0,tempOrder); + lastWDV = 0; + }else{ + lastWDV = i; + } + + } + } + + OrderListResp orderListResp1 = new OrderListResp(); + orderListResp1.id = -1; + orderList.add(lastWDV + 1, orderListResp1); + + OrderListResp orderListResp = new OrderListResp(); + orderListResp.id = -2; + orderList.add(lastWDV + 2, orderListResp); + + if (orderList.size() - 2 == 1 && orderList.get(0).status != null && orderList.get(0).status.equals("WD")) { + isFromCreateHold = true; + } + + if (!isFromCreateHold) { + OrderListResp orderListResp2 = new OrderListResp(); + orderListResp2.id = -3; + orderList.add(lastWDV + 3, orderListResp2); + } + + + if (orderList.size() == 1 && orderList.get(0).status.equals("WD")) { + text_email_receipt.setVisibility(View.GONE); + } else { + + text_email_receipt.setVisibility(View.VISIBLE); + text_email_receipt.setText(Html.fromHtml(getString(R.string.text_send_email_receipt))); + + text_email_receipt.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts( + "mailto", WOCConstants.SUPPORT_EMAIL, null)); + emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{WOCConstants.SUPPORT_EMAIL}); + if (orderList.size() > 0) + emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Order #{" + orderList.get(0).id + "} - {" + + ((BuyDashBaseActivity) mContext).buyDashPref.getPhone() + "}."); + emailIntent.putExtra(Intent.EXTRA_TEXT, ""); + startActivity(Intent.createChooser(emailIntent, WOCConstants.SEND_EMAIL)); + } + }); + } + + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext); + rv_order_list.setLayoutManager(linearLayoutManager); + rv_order_list.setAdapter(new OrderListAdapter(mContext, orderList, fragment, ((BuyDashBaseActivity) mContext).buyDashPref)); + } else { + //hideViewExcept(binding.layoutLocation); + //navigateToLocationScreen(); + blankOrderHistory(); + } + } + + private void navigateToLocationScreen() { + ((BuyDashBaseActivity) mContext).replaceFragment(new BuyDashLocationFragment(), true, false); + } + + private void blankOrderHistory(){ + layoutOrderHistory.setVisibility(View.VISIBLE); + text_no_order.setVisibility(View.VISIBLE); + btn_buy_more.setVisibility(View.VISIBLE); + layoutLogout.setVisibility(View.VISIBLE); + layoutInstruction.setVisibility(View.VISIBLE); + text_message.setText(mContext.getString(R.string.wallet_is_signed) + " " + + ((BuyDashBaseActivity) mContext).buyDashPref.getPhone()); + textHelpMessage.setText(R.string.call_for_help); + } + + /** + * hide show view + */ + public void changeView() { + if (isFromCreateHold ) { + isFromCreateHold = false; + getOrderList(isFromCreateHold); + } else { + navigateToLocationScreen(); + } + } + + + + private static class MyRunnable implements Runnable { + WeakReference textDepositeDue1; + Handler handler; + String dueDateTime; + int countdownInterval; + + public MyRunnable(TextView tvText, Handler handler, String dueDateTime, int countdownInterval) { + this.textDepositeDue1 = new WeakReference(tvText); + this.handler = handler; + this.dueDateTime = dueDateTime; + this.countdownInterval = countdownInterval; + } + + @Override + public void run() { + //Save the TextView to a local variable because the weak referenced object could become empty at any time + TextView textDepositeDue = textDepositeDue1.get(); + handler.postDelayed(this, countdownInterval); + try { + //2018-03-21T19:03:51.900811+03:00 + SimpleDateFormat dateFormat = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZZZ"); + /* SimpleDateFormat dateFormat = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZ");*/ +// + // Here Set your Event Date + //dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + //Date eventDate = dateFormat.parse(dueDateTime.replace("T", " ").substring(0, 19)); + Date eventDate = dateFormat.parse(dueDateTime); + Date currentDate = new Date(); + if (!currentDate.after(eventDate)) { + long diff = eventDate.getTime() + - currentDate.getTime(); + long hours = diff / (60 * 60 * 1000); + diff -= hours * (60 * 60 * 1000); + long minutes = diff / (60 * 1000); + diff -= minutes * (60 * 1000); + long seconds = diff / 1000; + + if (hours > 0) { + textDepositeDue.setText("Deposit Due: " + hours + " hours " + minutes + " minutes"); + countdownInterval = 60 * 1000; // call in minutes + } else { + if (minutes < 10) { + textDepositeDue.setTextColor(Color.parseColor("#DD0000")); + } else { + textDepositeDue.setTextColor(Color.parseColor("#000000")); + } + textDepositeDue.setText("Deposit Due: " + minutes + " minutes " + seconds + " seconds"); + countdownInterval = 1000; // call in seconds + } + } else { + textDepositeDue.setText("Deposit Due: 0 minutes 0 seconds"); + handler.removeMessages(0); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (handler != null) { + handler.removeCallbacks(myRunnable); + myRunnable = null; + } + + } + + /** + * Count down timer for Hold Expire status + * + * @param dueDateTime + * @param textDepositeDue + */ + public void countDownStart(final String dueDateTime, final TextView textDepositeDue) { + Log.e(TAG, "countDownStart: " + dueDateTime); + countdownInterval = 1000; + + if (handler == null) { + handler = new Handler(); + myRunnable = new MyRunnable(textDepositeDue, handler, dueDateTime, countdownInterval); + handler.postDelayed(myRunnable, 0); + } + } + + /** + * Method for singout user + * + * @param isPendingHold + */ + public void deleteAuthCall(final boolean isPendingHold) { + if (NetworkUtil.isOnline(mContext)) { + final String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + if (!TextUtils.isEmpty(phone)) { + linearProgress.setVisibility(View.VISIBLE); + //password = ""; + WallofCoins.createService(interceptor, mContext) + .deleteAuth(phone, getString(R.string.WALLOFCOINS_PUBLISHER_ID)) + .enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Log.d(TAG, "onResponse: response code==>>" + response.code()); + linearProgress.setVisibility(View.GONE); + if (response.code() < 299) { + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(""); + // password = ""; + ((BuyDashBaseActivity) mContext).buyDashPref.clearAllPrefrance(); + if (isPendingHold) { + //binding.editBuyDashPhone.setText(null); + //checkAuth(); + } else { + showToast(mContext.getString(R.string.alert_sign_out)); + //hideViewExcept(binding.layoutLocation); + navigateToLocationScreen(); + } + } else { + showToast(mContext.getString(R.string.try_again)); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else { + showToast(mContext.getString(R.string.alert_phone)); + } + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + public void goToGivenUrl(String url) { + goToUrl(url); + } + + public void cancelHoldOrder(final OrderListResp orderListResp) { + AlertDialog.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + builder = new AlertDialog.Builder(mContext, android.R.style.Theme_Material_Dialog_Alert); + } else { + builder = new AlertDialog.Builder(mContext); + } + builder.setTitle(getString(R.string.deposit_cancel_confirmation_title)) + .setMessage(getString(R.string.deposit_cancel_confirmation_message)) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + cancelOrder("" + orderListResp.id); + } + }) + .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .show(); + } + + public void depositFinished(final OrderListResp orderListResp) { + hideKeyBoard(); + AlertDialog.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + builder = new AlertDialog.Builder(mContext, android.R.style.Theme_Material_Dialog_Alert); + } else { + builder = new AlertDialog.Builder(mContext); + } + builder.setTitle(getString(R.string.deposit_finish_confirmation_title)) + .setMessage(getString(R.string.deposit_finish_confirmation_message)) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + CaptureHoldResp response = new CaptureHoldResp(); + response.id = orderListResp.id; + response.total = orderListResp.total; + response.payment = orderListResp.payment; + response.paymentDue = orderListResp.paymentDue; + response.bankName = orderListResp.bankName; + response.nameOnAccount = orderListResp.nameOnAccount; + response.account = orderListResp.account; + response.status = orderListResp.status; + CaptureHoldResp.NearestBranchBean nearestBranchBean = new CaptureHoldResp.NearestBranchBean(); + if (orderListResp.nearestBranch != null) { + nearestBranchBean.name = orderListResp.nearestBranch.name; + nearestBranchBean.city = orderListResp.nearestBranch.city; + nearestBranchBean.state = orderListResp.nearestBranch.state; + nearestBranchBean.phone = orderListResp.nearestBranch.phone; + nearestBranchBean.address = orderListResp.nearestBranch.address; + response.nearestBranch = nearestBranchBean; + } + response.bankUrl = orderListResp.account; + response.bankLogo = orderListResp.account; + response.bankIcon = orderListResp.account; + response.bankIconHq = orderListResp.account; + response.privateId = orderListResp.account; + confirmDeposit(response); + } + }) + .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .show(); + } + + /** + * Method call for Cancel order with status code "WD" + * + * @param orderId + */ + private void cancelOrder(String orderId) { + if (NetworkUtil.isOnline(mContext)) { + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, mContext).cancelOrder(orderId, getString(R.string.WALLOFCOINS_PUBLISHER_ID)).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + linearProgress.setVisibility(View.GONE); + if (response.code() == 204) { + showToast(mContext.getString(R.string.alert_cancel_order)); + //binding.requestCoinsAmountBtcEdittext.setText(""); + //binding.requestCoinsAmountLocalEdittext.setText(""); + //binding.buyDashZip.setText(""); + //hideViewExcept(binding.layoutLocation); + navigateToLocationScreen(); + } else { + showToast(mContext.getString(R.string.try_again)); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.e(TAG, "onFailure: ", t); + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Method call for confirm order deposit amount + * + * @param response + */ + private void confirmDeposit(CaptureHoldResp response) { + if (NetworkUtil.isOnline(mContext)) { + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).confirmDeposit("" + response.id, "", getString(R.string.WALLOFCOINS_PUBLISHER_ID)).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + linearProgress.setVisibility(View.GONE); + + if (null != response && null != response.body()) { + showToast(mContext.getString(R.string.alert_payment_done)); + getOrderList(false); + } else if (null != response && null != response.errorBody()) { + try { + BuyDashErrorResp buyDashErrorResp = new Gson().fromJson(response.errorBody().string(), BuyDashErrorResp.class); + Toast.makeText(getContext(), buyDashErrorResp.detail, Toast.LENGTH_LONG).show(); + } catch (Exception e) { + e.printStackTrace(); + showToast(mContext.getString(R.string.try_again)); + } + + } else { + showToast(mContext.getString(R.string.try_again)); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.btn_buy_more: + navigateToLocationScreen(); + break; + case R.id.btn_signout: + deleteAuthCall(false); + break; + case R.id.btn_WebLink: + goToGivenUrl(WOCConstants.KEY_WEB_URL); + break; + } + } + + //this method remove animation when user want to clear back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/payment_center/BuyDashPaymentCenterFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/payment_center/BuyDashPaymentCenterFragment.java new file mode 100644 index 000000000..6c135f932 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/payment_center/BuyDashPaymentCenterFragment.java @@ -0,0 +1,189 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.payment_center; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatSpinner; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.LinearLayout; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.api.WallofCoins; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.offer_amount.BuyDashOfferAmountFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.response.GetReceivingOptionsResp; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + + +/** + * Created on 07-Mar-18. + */ + +public class BuyDashPaymentCenterFragment extends BuyDashBaseFragment implements View.OnClickListener { + + private View rootView; + private LinearLayout linear_progress; + private final String TAG = "PaymentCenterFragment"; + private AppCompatSpinner sp_banks; + private String bankId; + private Button button_buy_dash_bank_next; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_buy_dash_payment_center, container, false); + init(); + setListeners(); + getReceivingOptions(); + return rootView; + } else + return rootView; + } + + private void init() { + linear_progress = (LinearLayout) rootView.findViewById(R.id.linear_progress); + sp_banks = (AppCompatSpinner) rootView.findViewById(R.id.sp_banks); + button_buy_dash_bank_next = (Button) rootView.findViewById(R.id.button_buy_dash_bank_next); + } + + private void setListeners() { + button_buy_dash_bank_next.setOnClickListener(this); + } + + /** + * API call for get all receiving options by country code + */ + private void getReceivingOptions() { + if (NetworkUtil.isOnline(mContext)) { + String locale; + locale = getResources().getConfiguration().locale.getCountry(); + linear_progress.setVisibility(View.VISIBLE); + //WallofCoins.createService(interceptor, getActivity()).getReceivingOptions(locale.toLowerCase(), getString(R.string.WALLOFCOINS_PUBLISHER_ID)).enqueue(new Callback>() { + WallofCoins.createService(interceptor, getActivity()).getReceivingOptions().enqueue(new Callback>() { + + @Override + public void onResponse(Call> call, Response> response) { + + if (response.body() != null) { + Log.e(TAG, "onResponse: " + response.body().size()); + linear_progress.setVisibility(View.GONE); + setPaymentOptNames(response.body()); + } + + } + + @Override + public void onFailure(Call> call, Throwable t) { + linear_progress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + t.printStackTrace(); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * Set Payment option name for Payment options + * + * @param receivingOptionsResps + */ + private void setPaymentOptNames(final List receivingOptionsResps) { + final ArrayList names = new ArrayList(); + GetReceivingOptionsResp optionsRespDefaultName = new GetReceivingOptionsResp(); + Collections.sort(receivingOptionsResps, new ContactComparator()); + + optionsRespDefaultName.name = getString(R.string.label_select_payment_center); + receivingOptionsResps.add(0, optionsRespDefaultName); + + for (GetReceivingOptionsResp receivingOptionsResp : receivingOptionsResps) { + names.add((receivingOptionsResp.name)); + } + ArrayAdapter adapter = new ArrayAdapter(mContext, android.R.layout.simple_spinner_dropdown_item, names); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + sp_banks.setAdapter(adapter); + + sp_banks.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + if (position == 0) return; + bankId = "" + receivingOptionsResps.get(position).id; + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + + } + + private class ContactComparator implements Comparator { + public int compare(GetReceivingOptionsResp optionsResp1, GetReceivingOptionsResp optionsResp2) { + //In the following line you set the criterion, + //which is the name of Contact in my example scenario + return optionsResp1.name.compareTo(optionsResp2.name); + } + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + + case R.id.button_buy_dash_bank_next: + if (sp_banks.getSelectedItemPosition() == 0) + showToast(mContext.getString(R.string.alert_select_any_payment_center)); + else + navigateToOtherScreen(); + break; + + } + } + + private void navigateToOtherScreen() { + Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.BANK_ID, bankId); + BuyDashOfferAmountFragment offerAmountFragment = new BuyDashOfferAmountFragment(); + offerAmountFragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(offerAmountFragment, true, true); + } + + //this method remove animation when user want to clear back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/phone_list/PhoneListFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/phone_list/PhoneListFragment.java new file mode 100644 index 000000000..85fdd23c7 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/phone_list/PhoneListFragment.java @@ -0,0 +1,152 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.phone_list; + +import android.content.Context; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.api.WallofCoins; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.adapters.PhoneListAdapter; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.email_phone.EmailAndPhoneFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.models.PhoneListVO; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.BuyDashPhoneListPref; +import pivx.org.pivxwallet.wallofcoins.response.GetAuthTokenResp; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 19-Mar-18. + */ + +public class PhoneListFragment extends BuyDashBaseFragment implements View.OnClickListener { + + private final String TAG = "OrderHistoryFragment"; + private View rootView; + private RecyclerView recyclerViewPhoneList; + private Button btnSignUp, btnExistingSignIn; + private PhoneListFragment fragment; + private TextView txtViewNoData; + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + rootView = inflater.inflate(R.layout.fragment_buy_dash_phone_list, container, false); + init(); + setListeners(); + setPhoneList(); + return rootView; + } + + private void init() { + fragment = this; + recyclerViewPhoneList = (RecyclerView) rootView.findViewById(R.id.recyclerViewPhoneList); + btnSignUp = (Button) rootView.findViewById(R.id.btnSignUp); + btnExistingSignIn = (Button) rootView.findViewById(R.id.btnExistingSignIn); + txtViewNoData = (TextView) rootView.findViewById(R.id.txtViewNoData); + recyclerViewPhoneList.setLayoutManager(new LinearLayoutManager(mContext)); + } + + private void setListeners() { + btnExistingSignIn.setOnClickListener(this); + btnSignUp.setOnClickListener(this); + } + + private void setPhoneList() { + BuyDashPhoneListPref credentialsPref = + new BuyDashPhoneListPref(PreferenceManager.getDefaultSharedPreferences(mContext)); + + ArrayList phoneListVOS = credentialsPref.getStoredPhoneList(); + + HashSet hashSet = new HashSet<>(); + hashSet.addAll(phoneListVOS); + phoneListVOS.clear(); + phoneListVOS.addAll(hashSet); + + if (phoneListVOS != null & phoneListVOS.size() > 0) { + recyclerViewPhoneList.setAdapter(new PhoneListAdapter(mContext, credentialsPref.getStoredPhoneList(), fragment)); + txtViewNoData.setVisibility(View.GONE); + } else + txtViewNoData.setVisibility(View.VISIBLE); + + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.btnExistingSignIn: + Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.SCREEN_TYPE, "PhoneListFragment"); + EmailAndPhoneFragment phoneFragment = new EmailAndPhoneFragment(); + phoneFragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(phoneFragment, true, true); + break; + case R.id.btnSignUp: + goToUrl(WOCConstants.KEY_SIGN_UP_URL); + break; + } + } + + /** + * Authorized user using phone + * + * @param deviceId + */ + public void getAuthTokenCall(final String phone, String deviceId) { + if (NetworkUtil.isOnline(mContext)) { + + HashMap getAuthTokenReq = new HashMap(); + getAuthTokenReq.put(WOCConstants.KEY_DEVICEID, deviceId); + getAuthTokenReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + getAuthTokenReq.put(WOCConstants.KEY_DEVICECODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + + WallofCoins.createService(interceptor, getActivity()).getAuthToken(phone, getAuthTokenReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + int code = response.code(); + + if (code == 200) { + if (!TextUtils.isEmpty(response.body().token)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(response.body().token); + ((BuyDashBaseActivity) mContext).buyDashPref.setPhone(phone); + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(response.body().deviceId); + ((BuyDashBaseActivity) mContext).popBackDirect(); + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(mContext.getString(R.string.try_again)); + } + }); + + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/BuyDashAddressPref.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/BuyDashAddressPref.java new file mode 100644 index 000000000..6868608e6 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/BuyDashAddressPref.java @@ -0,0 +1,32 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.utils; + +import android.content.SharedPreferences; + +/** + * Created by on 13-Mar-18. + */ + +public class BuyDashAddressPref { + private final SharedPreferences prefs; + private static final String BUY_DASH_ADDRESS = "addres"; + + public BuyDashAddressPref(final SharedPreferences prefs) { + this.prefs = prefs; + } + + public void setBuyDashAddress(String address) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(BUY_DASH_ADDRESS, address); + editor.commit(); + } + + public String getBuyDashAddress() { + return prefs.getString(BUY_DASH_ADDRESS, ""); + } + + public void clearBuyDashAddress() { + SharedPreferences.Editor editor = prefs.edit(); + editor.clear(); + editor.commit(); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/BuyDashPhoneListPref.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/BuyDashPhoneListPref.java new file mode 100644 index 000000000..3263c91dc --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/BuyDashPhoneListPref.java @@ -0,0 +1,85 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.utils; + +import android.content.SharedPreferences; +import android.util.Log; + +import java.util.ArrayList; + +import pivx.org.pivxwallet.wallofcoins.buyingwizard.models.PhoneListVO; + + +/** + * Created on 12-Mar-18. + */ + +public class BuyDashPhoneListPref { + + private final SharedPreferences prefs; + private static final String CREDENTIALS_LIST = "credentials_list"; + + public BuyDashPhoneListPref(final SharedPreferences prefs) { + this.prefs = prefs; + } + + + public void addPhone(String phone, String deviceId) { + ArrayList voArrayList; + + try { + voArrayList = (ArrayList) ObjectSerializer.deserialize(prefs.getString(CREDENTIALS_LIST, + ObjectSerializer.serialize(new ArrayList()))); + PhoneListVO createHoldResp = new PhoneListVO(); + createHoldResp.setDeviceId(deviceId); + createHoldResp.setPhoneNumber(phone); + + voArrayList.add(createHoldResp); + + + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(CREDENTIALS_LIST, ObjectSerializer.serialize(voArrayList)); + + editor.commit(); + + for (PhoneListVO vo : voArrayList) { + Log.e("Auth id list", vo.getDeviceId()); + Log.e("phone no list", vo.getPhoneNumber()); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public ArrayList getStoredPhoneList() { + ArrayList voArrayList = new ArrayList<>(); + + try { + voArrayList = (ArrayList) ObjectSerializer.deserialize(prefs.getString(CREDENTIALS_LIST, + ObjectSerializer.serialize(new ArrayList()))); + } catch (Exception e) { + e.printStackTrace(); + } + return voArrayList; + } + + public String getDeviceIdFromPhone(String phone) { + String deviceId = ""; + ArrayList voArrayList; + + try { + voArrayList = (ArrayList) ObjectSerializer.deserialize(prefs.getString(CREDENTIALS_LIST, + ObjectSerializer.serialize(new ArrayList()))); + + for (PhoneListVO vo : voArrayList) { + Log.e("Stored phone",vo.getPhoneNumber()+"---"+"Stored deviceId"+vo.getDeviceId()); + if (vo.getPhoneNumber().equalsIgnoreCase(phone)) { + deviceId = vo.getDeviceId(); + break; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return deviceId; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/FragmentUtils.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/FragmentUtils.java new file mode 100644 index 000000000..e5e5dc948 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/FragmentUtils.java @@ -0,0 +1,9 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.utils; + +/** + * Created on 09-Mar-18. + */ + +public class FragmentUtils { + public static boolean sDisableFragmentAnimations = false; +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/ObjectSerializer.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/ObjectSerializer.java new file mode 100644 index 000000000..864272a5a --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/utils/ObjectSerializer.java @@ -0,0 +1,52 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * Created on 12-Mar-18. + */ + +public class ObjectSerializer { + public static String serialize(Serializable obj) throws IOException { + if (obj == null) return ""; + ByteArrayOutputStream serialObj = new ByteArrayOutputStream(); + ObjectOutputStream objStream = new ObjectOutputStream(serialObj); + objStream.writeObject(obj); + objStream.close(); + return encodeBytes(serialObj.toByteArray()); + } + + public static Object deserialize(String str) throws IOException, ClassNotFoundException { + if (str == null || str.length() == 0) return null; + ByteArrayInputStream serialObj = new ByteArrayInputStream(decodeBytes(str)); + ObjectInputStream objStream = new ObjectInputStream(serialObj); + return objStream.readObject(); + } + + public static String encodeBytes(byte[] bytes) { + StringBuffer strBuf = new StringBuffer(); + + for (int i = 0; i < bytes.length; i++) { + strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a'))); + strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a'))); + } + + return strBuf.toString(); + } + + public static byte[] decodeBytes(String str) { + byte[] bytes = new byte[str.length() / 2]; + for (int i = 0; i < str.length(); i += 2) { + char c = str.charAt(i); + bytes[i / 2] = (byte) ((c - 'a') << 4); + c = str.charAt(i + 1); + bytes[i / 2] += (c - 'a'); + } + return bytes; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/verification_otp/VerifycationOtpFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/verification_otp/VerifycationOtpFragment.java new file mode 100644 index 000000000..3bd688d5d --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/verification_otp/VerifycationOtpFragment.java @@ -0,0 +1,238 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.verification_otp; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.os.Build; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.Toast; + +import com.google.gson.Gson; + +import org.bitcoinj.wallet.Wallet; + +import java.util.HashMap; +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.api.WallofCoins; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.buy_dash_location.BuyDashLocationFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.order_history.OrderHistoryFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.BuyDashAddressPref; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.response.BuyDashErrorResp; +import pivx.org.pivxwallet.wallofcoins.response.CaptureHoldResp; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 08-Mar-18. + */ + +public class VerifycationOtpFragment extends BuyDashBaseFragment implements View.OnClickListener, SharedPreferences.OnSharedPreferenceChangeListener { + + + private View rootView; + private Button button_verify_otp; + private EditText et_otp; + private LinearLayout linearProgress; + private final String TAG = "VerifycationOtpFragment"; + private String otp = "", keyAddress = ""; + private Wallet wallet; + // private WalletApplication application; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_buy_dash_verification_otp, container, false); + init(); + setListeners(); + handleArgs(); + return rootView; + } else + return rootView; + } + + private void init() { + // this.application = (WalletApplication) getActivity().getApplication(); + //this.wallet = application.getWallet(); + //this.loaderManager = getLoaderManager(); + + BuyDashAddressPref dashAddressPref = new BuyDashAddressPref(PreferenceManager.getDefaultSharedPreferences(mContext)); + //keyAddress = wallet.freshAddress(RECEIVE_FUNDS).toBase58(); + keyAddress = dashAddressPref.getBuyDashAddress(); + Log.e("------------------", keyAddress); + linearProgress = (LinearLayout) rootView.findViewById(R.id.linear_progress); + button_verify_otp = (Button) rootView.findViewById(R.id.button_verify_otp); + et_otp = (EditText) rootView.findViewById(R.id.et_otp); + } + + private void setListeners() { + button_verify_otp.setOnClickListener(this); + } + + private void handleArgs() { + if (getArguments() != null) + otp = getArguments().getString(WOCConstants.VERIFICATION_OTP); + + et_otp.setText(otp); + + } + + @Override + public void onClick(View view) { + + switch (view.getId()) { + case R.id.button_verify_otp: + verifyOTP(); + break; + } + } + + + /** + * API call for call for Capture Hold @POST("api/v1/holds/{id}/capture/") + */ + private void verifyOTP() { + + if (NetworkUtil.isOnline(mContext)) { + hideKeyBoard(); + HashMap captureHoldReq = new HashMap(); + String otp = et_otp.getText().toString().trim(); + + if (TextUtils.isEmpty(otp)) { + showToast(mContext.getString(R.string.alert_purchase_code)); + return; + } + + captureHoldReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + captureHoldReq.put(WOCConstants.KEY_VERIFICATION_CODE, otp); + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).captureHold(( + (BuyDashBaseActivity) mContext).buyDashPref.getHoldId(), captureHoldReq) + .enqueue(new Callback>() { + @Override + public void onResponse(Call> call, final Response> response) { + linearProgress.setVisibility(View.GONE); + ((BuyDashBaseActivity) mContext).buyDashPref.setHoldId(""); + ((BuyDashBaseActivity) mContext).buyDashPref.setCreateHoldResp(null); + Log.e(TAG, "onResponse: " + ((BuyDashBaseActivity) mContext).buyDashPref.getHoldId() + " here"); + if (null != response && null != response.body() && !response.body().isEmpty()) { + if (response.body().get(0).account != null && !TextUtils.isEmpty(response.body().get(0).account)) { + updateAddressBookValue(keyAddress, "WallofCoins.com - Order " + response.body().get(0).id); + navigateToOrderList(true); + // getOrderList(true); + } else { + //getOrderList(true); + navigateToOrderList(true); + } + + // hideViewExcept(binding.scrollCompletionDetail); + + } else if (null != response && null != response.errorBody()) { + linearProgress.setVisibility(View.GONE); + + if (response.code() == 404) { + AlertDialog.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + builder = new AlertDialog.Builder(mContext, android.R.style.Theme_Material_Dialog_Alert); + } else { + builder = new AlertDialog.Builder(mContext); + } + builder.setTitle(getString(R.string.alert_title_purchase_code)) + .setMessage(getString(R.string.alert_description_purchase_code)) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + // hideViewExcept(binding.layoutCreateHold); + navigateToLocation(); + + } + }) + .show(); + } else { + try { + BuyDashErrorResp buyDashErrorResp = new Gson().fromJson(response.errorBody().string(), BuyDashErrorResp.class); + Toast.makeText(getContext(), buyDashErrorResp.detail, Toast.LENGTH_LONG).show(); + } catch (Exception e) { + e.printStackTrace(); + showToast(mContext.getString(R.string.try_again)); + } + } + } else { + showToast(mContext.getString(R.string.try_again)); + linearProgress.setVisibility(View.GONE); + } + } + + @Override + public void onFailure + (Call> call, Throwable t) { + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + Log.e(TAG, "onFailure: ", t); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * create hold screen + * + * @param + */ + private void navigateToLocation() { + BuyDashLocationFragment locationFragment = new BuyDashLocationFragment(); + ((BuyDashBaseActivity) mContext).replaceFragment(locationFragment, true, true); + } + + private void navigateToOrderList(boolean isFromCreateHold) { + OrderHistoryFragment historyFragment = new OrderHistoryFragment(); + Bundle bundle = new Bundle(); + bundle.putBoolean("isFromCreateHold", isFromCreateHold); + historyFragment.setArguments(bundle); + ((BuyDashBaseActivity) mContext).replaceFragment(historyFragment, true, true); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + + } + + //this method remove animation when user want to clear back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/zip/BuyDashZipFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/zip/BuyDashZipFragment.java new file mode 100644 index 000000000..4f413f659 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/buyingwizard/zip/BuyDashZipFragment.java @@ -0,0 +1,113 @@ +package pivx.org.pivxwallet.wallofcoins.buyingwizard.zip; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.EditText; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.offer_amount.BuyDashOfferAmountFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.payment_center.BuyDashPaymentCenterFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; + + +/** + * Created on 6/3/18. + */ + +public class BuyDashZipFragment extends BuyDashBaseFragment implements View.OnClickListener { + + private View rootView; + private Button button_buy_dash_zip_next; + private String zipCode; + private EditText buy_dash_zip; + private final String TAG = "BuyDashZipFragment"; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_buy_dash_zip, container, false); + init(); + setListeners(); + return rootView; + } else + return rootView; + } + + private void init() { + + button_buy_dash_zip_next = (Button) rootView.findViewById(R.id.button_buy_dash_zip_next); + buy_dash_zip = (EditText) rootView.findViewById(R.id.buy_dash_zip); + } + + private void setListeners() { + button_buy_dash_zip_next.setOnClickListener(this); + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.button_buy_dash_zip_next: + zipCode = buy_dash_zip.getText().toString().trim(); + if (TextUtils.isEmpty(zipCode)) { // open bank list screen + navigateToBankListScreen(); + } else { + if (isValidZip()) + navigateToOtherScreen1(); + } + break; + } + } + + private boolean isValidZip() { + if (buy_dash_zip.getText().toString().trim().length() < 5 || buy_dash_zip.getText().toString().trim().length() > 6) { + buy_dash_zip.requestFocus(); + showToast(getString(R.string.invalid_zip_code)); + return false; + } + return true; + } + + private void navigateToOtherScreen1() { + Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.ZIP, zipCode); + BuyDashOfferAmountFragment offerAmountFragment = new BuyDashOfferAmountFragment(); + offerAmountFragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(offerAmountFragment, true, true); + } + + //if zip code is empty user navigate to all bank list screen + private void navigateToBankListScreen() { + BuyDashPaymentCenterFragment centerFragment = new BuyDashPaymentCenterFragment(); + ((BuyDashBaseActivity) mContext).replaceFragment(centerFragment, true, true); + } + + //this method remove animation when user want to clear back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/BuyDashErrorResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/BuyDashErrorResp.java new file mode 100644 index 000000000..1cecb5af0 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/BuyDashErrorResp.java @@ -0,0 +1,10 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +public class BuyDashErrorResp { + + /** + * detail : Not found + */ + + public String detail; +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CaptureHoldResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CaptureHoldResp.java new file mode 100644 index 000000000..2b540647d --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CaptureHoldResp.java @@ -0,0 +1,52 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +public class CaptureHoldResp { + + /** + * id : 70 + * total : 51.87391467 + * payment : 504.0000000193 + * paymentDue : 2017-08-09T14:42:46.565Z + * bankName : MoneyGram + * nameOnAccount : + * account : [{"displaySort": 2.0, "name": "birthCountry", "value": "US", "label": "Country of Birth"}, {"displaySort": 0.5, "name": "pickupState", "value": "Florida", "label": "Pick-up State"}, {"displaySort": 1.0, "name": "lastName", "value": "Genito", "label": "Last Name"}, {"displaySort": 0.0, "name": "firstName", "value": "Robert", "label": "First Name"}] + * status : WD + * nearestBranch : {"city":"","state":"","name":"MoneyGram","phone":null,"address":""} + * bankUrl : https://secure.moneygram.com + * bankLogo : /media/logos/logo_us_MoneyGram.png + * bankIcon : /media/logos/icon_us_MoneyGram.png + * bankIconHq : /media/logos/icon_us_MoneyGram%402x.png + * privateId : 8eca9b5b05b92925ba31cf4e1682d790871acd93 + */ + + public int id; + public String total; + public String payment; + public String paymentDue; + public String bankName; + public String nameOnAccount; + public String account; + public String status; + public NearestBranchBean nearestBranch; + public String bankUrl; + public String bankLogo; + public String bankIcon; + public String bankIconHq; + public String privateId; + + public static class NearestBranchBean { + /** + * city : + * state : + * name : MoneyGram + * phone : null + * address : + */ + + public String city; + public String state; + public String name; + public String phone; + public String address; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CheckAuthResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CheckAuthResp.java new file mode 100644 index 000000000..fb278250b --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CheckAuthResp.java @@ -0,0 +1,34 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +import java.util.List; + +/** + * Created on 04-Sep-17. + */ + +public class CheckAuthResp { + + /** + * phone : 17439995953 + * availableAuthSources : ["deviceCode"] + */ + + private String phone; + private List availableAuthSources; + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public List getAvailableAuthSources() { + return availableAuthSources; + } + + public void setAvailableAuthSources(List availableAuthSources) { + this.availableAuthSources = availableAuthSources; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/ConfirmDepositResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/ConfirmDepositResp.java new file mode 100644 index 000000000..140f432ea --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/ConfirmDepositResp.java @@ -0,0 +1,204 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +public class ConfirmDepositResp { + + /** + * id : 85243 + * total : 9.62314870 + * payment : 3344.4500006610 + * paymentDue : 2017-09-04T16:04:21.290Z + * bankName : Bank of America + * nameOnAccount : Gerald Verzosa + * account : 7475844139 + * status : WD + * nearestBranch : {"city":"Sarasota","state":"FL","name":"Bank of America","phone":"(941) 952-2868","address":"1605 Main St, #501"} + * bankUrl : http://bankofamerica.com + * bankLogo : https://wallofcoins-static.s3.amazonaws.com/logos/logo_11.png + * bankIcon : https://wallofcoins-static.s3.amazonaws.com/logos/icon_11.png + * bankIconHq : https://wallofcoins-static.s3.amazonaws.com/logos/icon_11%402x.png + * privateId : 05dbf8a622641ce60cb7b26543e7a9908209034d + */ + + private int id; + private String total; + private String payment; + private String paymentDue; + private String bankName; + private String nameOnAccount; + private String account; + private String status; + private NearestBranchBean nearestBranch; + private String bankUrl; + private String bankLogo; + private String bankIcon; + private String bankIconHq; + private String privateId; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTotal() { + return total; + } + + public void setTotal(String total) { + this.total = total; + } + + public String getPayment() { + return payment; + } + + public void setPayment(String payment) { + this.payment = payment; + } + + public String getPaymentDue() { + return paymentDue; + } + + public void setPaymentDue(String paymentDue) { + this.paymentDue = paymentDue; + } + + public String getBankName() { + return bankName; + } + + public void setBankName(String bankName) { + this.bankName = bankName; + } + + public String getNameOnAccount() { + return nameOnAccount; + } + + public void setNameOnAccount(String nameOnAccount) { + this.nameOnAccount = nameOnAccount; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public NearestBranchBean getNearestBranch() { + return nearestBranch; + } + + public void setNearestBranch(NearestBranchBean nearestBranch) { + this.nearestBranch = nearestBranch; + } + + public String getBankUrl() { + return bankUrl; + } + + public void setBankUrl(String bankUrl) { + this.bankUrl = bankUrl; + } + + public String getBankLogo() { + return bankLogo; + } + + public void setBankLogo(String bankLogo) { + this.bankLogo = bankLogo; + } + + public String getBankIcon() { + return bankIcon; + } + + public void setBankIcon(String bankIcon) { + this.bankIcon = bankIcon; + } + + public String getBankIconHq() { + return bankIconHq; + } + + public void setBankIconHq(String bankIconHq) { + this.bankIconHq = bankIconHq; + } + + public String getPrivateId() { + return privateId; + } + + public void setPrivateId(String privateId) { + this.privateId = privateId; + } + + public static class NearestBranchBean { + /** + * city : Sarasota + * state : FL + * name : Bank of America + * phone : (941) 952-2868 + * address : 1605 Main St, #501 + */ + + private String city; + private String state; + private String name; + private String phone; + private String address; + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CountryData.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CountryData.java new file mode 100644 index 000000000..958156d6d --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CountryData.java @@ -0,0 +1,33 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class CountryData { + + + public List countries; + + public static class CountriesBean { + /** + * name : United States + * code : +1 + * currency : USD + * short : us + */ + + public String name; + public String code; + public String currency; + @SerializedName("short") + public String shortX; + public int top; + public int left; + + @Override + public String toString() { + return name + " (" + code + ")"; + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CreateDeviceResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CreateDeviceResp.java new file mode 100644 index 000000000..ea8dc3ae9 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CreateDeviceResp.java @@ -0,0 +1,38 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +public class CreateDeviceResp { + + /** + * id : 4 + * name : New iPhone + * createdOn : 2015-01-20T17:13:34.154Z + */ + + private int id; + private String name; + private String createdOn; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(String createdOn) { + this.createdOn = createdOn; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CreateHoldResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CreateHoldResp.java new file mode 100644 index 000000000..938b73bb5 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/CreateHoldResp.java @@ -0,0 +1,38 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +import java.util.List; + +public class CreateHoldResp { + + + /** + * id : 5e179adf417275ef3e138d73f1fa39aa + * expirationTime : 2017-08-08T17:23:01.440Z + * discoveryInput : 5cb0c411f83f7c2fdb5a4af909bdb690 + * holds : [{"amount":"53.23435843","currentPrice":"9.43","status":""}] + * token : ZGV2aWNlOjM5NjoxNTAyMjIzNjAxfGIzNWZmOGYxOTlmYjRkNTM2YTdkZWNmZjJmNjY0MzNjN2M2NWZhOWQ= + * tokenExpiresAt : 2017-08-08T20:20:01.399Z + * __PURCHASE_CODE : AARXX + */ + + public String id; + public String expirationTime; + public String discoveryInput; + public String token; + public String tokenExpiresAt; + public String deviceId; + public String __PURCHASE_CODE; + public List holds; + + public static class HoldsBean { + /** + * amount : 53.23435843 + * currentPrice : 9.43 + * status : + */ + + public String amount; + public String currentPrice; + public String status; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/DiscoveryInputsResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/DiscoveryInputsResp.java new file mode 100644 index 000000000..064eac08e --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/DiscoveryInputsResp.java @@ -0,0 +1,45 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +public class DiscoveryInputsResp { + + + /** + * id : 2948e301f2dbc2cd52c7284e2ebbd6bd + * usdAmount : 500 + * cryptoAmount : 0 + * crypto : DASH + * fiat : USD + * zipCode : 34236 + * bank : null + * state : null + * cryptoAddress : null + * createdIp : 127.0.0.1 + * location : {"latitude":27.3331293,"longitude":-82.5456374} + * browserLocation : null + * publisher : null + */ + + public String id; + public String usdAmount; + public String cryptoAmount; + public String crypto; + public String fiat; + public String zipCode; + public String bank; + public String state; + public String cryptoAddress; + public String createdIp; + public LocationBean location; + //public String browserLocation; + public String publisher; + + public static class LocationBean { + /** + * latitude : 27.3331293 + * longitude : -82.5456374 + */ + + public double latitude; + public double longitude; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetAuthTokenResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetAuthTokenResp.java new file mode 100644 index 000000000..ff8b948ef --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetAuthTokenResp.java @@ -0,0 +1,23 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +public class GetAuthTokenResp { + + /** + * createdOn : 2017-07-10T16:04:24.887Z + * tokenExpiresAt : 2017-07-10T20:14:55.642Z + * accessedOn : 2017-07-10T17:14:55.646Z + * phone : 19418555706 + * token : YXV0aDoxNzM6MTQ5OTcxNzY5NXwzZDljNDkxZDgwNmVjZDUzYTNmM2NjNzFiMTI0ZWE2ZGIzMTRlMjJk + * authSource : deviceCode + * email : demo@gmail.com + */ + + public String createdOn; + public String tokenExpiresAt; + public String accessedOn; + public String phone; + public String token; + public String authSource; + public String email; + public String deviceId; +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetCurrencyResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetCurrencyResp.java new file mode 100644 index 000000000..fee3c54bb --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetCurrencyResp.java @@ -0,0 +1,16 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +public class GetCurrencyResp { + + public String code; + public String name; + public String symbol; + + @Override + public String toString() { +// return name + " (" + symbol + ")"; + return symbol; + } + + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetHoldsResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetHoldsResp.java new file mode 100644 index 000000000..32613a571 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetHoldsResp.java @@ -0,0 +1,19 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +public class GetHoldsResp { + + /** + * [ + { + "id": "ec11665efc6eeb8e8ca083360c70a659", + "expirationTime": "2018-02-16T06:38:14.408227Z", + "discoveryInput": "8f4a39a2ca29607da6d8c891e8318b26" + } + ] + */ + + public String id; + public String expirationTime; + public String discoveryInput; + public String status; +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetOffersResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetOffersResp.java new file mode 100644 index 000000000..1d537bceb --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetOffersResp.java @@ -0,0 +1,186 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.List; +import java.util.Locale; + +public class GetOffersResp { + + /** + * singleDeposit : [{"id":"eyJ1c2QiOiAiNTAxLjAwIiwgImVhIjogdHJ1ZSwgImFkIjogMTAsICJkaSI6ICIyOTQ4ZTMwMWYyZGJjMmNkNTJjNzI4NGUyZWJiZDZiZCJ9fHxTaW5nbGVEZXBvc2l0T2ZmZXJ8fDA3ZGQzOGVhY2NlYTlhYmRiY2E1ZDNlM2Q2OWY4Mjky","deposit":{"currency":"USD","amount":"501.00"},"crypto":"DASH","amount":{"DASH":"51.562","dots":"51,562,544.25","bits":"51,562,544.25","BTC":"51.562"},"discoveryId":"2948e301f2dbc2cd52c7284e2ebbd6bd","distance":0,"address":"","state":"","bankName":"MoneyGram","bankLogo":"/media/logos/logo_us_MoneyGram.png","bankLogoHq":"/media/logos/logo_us_MoneyGram%402x.png","bankIcon":"/media/logos/icon_us_MoneyGram.png","bankIconHq":"/media/logos/icon_us_MoneyGram%402x.png","bankLocationUrl":"https://secure.moneygram.com/locations","city":""},{"id":"eyJ1c2QiOiAiNTAyLjAwIiwgImVhIjogdHJ1ZSwgImFkIjogMTEsICJkaSI6ICIyOTQ4ZTMwMWYyZGJjMmNkNTJjNzI4NGUyZWJiZDZiZCJ9fHxTaW5nbGVEZXBvc2l0T2ZmZXJ8fGU1N2JlOWUxZTFmNTZmY2VjYzBiMjkyYzI0ZjdjM2Zj","deposit":{"currency":"USD","amount":"502.00"},"crypto":"DASH","amount":{"DASH":"32.480","dots":"32,480,900.05","bits":"32,480,900.05","BTC":"32.480"},"discoveryId":"2948e301f2dbc2cd52c7284e2ebbd6bd","distance":0.9639473391774286,"address":"240 N Washington Blvd, #100","state":"FL","bankName":"Chase","bankLogo":"/media/logos/logo_us_Chase.png","bankLogoHq":"/media/logos/logo_us_Chase%402x.png","bankIcon":"/media/logos/icon_us_Chase.png","bankIconHq":"/media/logos/icon_us_Chase%402x.png","bankLocationUrl":null,"city":"Sarasota"},{"id":"eyJ1c2QiOiAiNTAwLjAwIiwgImVhIjogdHJ1ZSwgImFkIjogMzgsICJkaSI6ICIyOTQ4ZTMwMWYyZGJjMmNkNTJjNzI4NGUyZWJiZDZiZCJ9fHxTaW5nbGVEZXBvc2l0T2ZmZXJ8fDMwMzViOTI0ODliNTI2ZmI1MWU5NWJhZWE5YmM5NGRl","deposit":{"currency":"USD","amount":"500.00"},"crypto":"DASH","amount":{"DASH":"5.508","dots":"5,508,014.94","bits":"5,508,014.94","BTC":"5.508"},"discoveryId":"2948e301f2dbc2cd52c7284e2ebbd6bd","distance":0.495030456581863,"address":"1605 Main St, #501","state":"FL","bankName":"Bank of America","bankLogo":"/media/logos/logo_us_Bank%20of%20America.png","bankLogoHq":"/media/logos/logo_us_Bank%20of%20America%402x.png","bankIcon":"/media/logos/icon_us_Bank%20of%20America.png","bankIconHq":"/media/logos/icon_us_Bank%20of%20America%402x.png","bankLocationUrl":null,"city":"Sarasota"}] + * doubleDeposit : [{"id":"eyJkaSI6ICIyOTQ4ZTMwMWYyZGJjMmNkNTJjNzI4NGUyZWJiZDZiZCIsICJhZDIiOiAzMywgImFkMSI6IDQxfXx8RG91YmxlRGVwb3NpdE9mZmVyfHxlOGU2NzBmMTM2MmE5ZjQ5MGQzZGE0ZWI3MjIxNWE4MA==","firstOffer":{"deposit":{"currency":"USD","amount":"490.00"},"crypto":"DASH","amount":{"DASH":"47.547","dots":"47,547,115.08","bits":"47,547,115.08","BTC":"47.547"},"discoveryId":"2948e301f2dbc2cd52c7284e2ebbd6bd","distance":0.9639473391774286,"address":"240 N Washington Blvd, #100","state":"FL","bankName":"Chase","bankLogo":"/media/logos/logo_us_Chase.png","bankLogoHq":"/media/logos/logo_us_Chase%402x.png","bankIcon":"/media/logos/icon_us_Chase.png","bankIconHq":"/media/logos/icon_us_Chase%402x.png","bankLocationUrl":null,"city":"Sarasota"},"secondOffer":{"deposit":{"currency":"USD","amount":"10.00"},"crypto":"DASH","amount":{"DASH":"0.088","dots":"88,491.58","bits":"88,491.58","BTC":"0.088"},"discoveryId":"2948e301f2dbc2cd52c7284e2ebbd6bd","distance":0.9639473391774286,"address":"240 N Washington Blvd, #100","state":"FL","bankName":"Chase","bankLogo":"/media/logos/logo_us_Chase.png","bankLogoHq":"/media/logos/logo_us_Chase%402x.png","bankIcon":"/media/logos/icon_us_Chase.png","bankIconHq":"/media/logos/icon_us_Chase%402x.png","bankLocationUrl":null,"city":"Sarasota"},"totalAmount":{"bits":"47,635,606.67","BTC":"47.635"},"totalDeposit":{"currency":"USD","amount":"500.00"}}] + * multipleBanks : [] + * isExtendedSearch : false + * incremented : true + */ + + public boolean isExtendedSearch; + public boolean incremented; + public List singleDeposit; + public List doubleDeposit; + public List multipleBanks; + + public static class SingleDepositBean { + /** + * id : eyJ1c2QiOiAiNTAxLjAwIiwgImVhIjogdHJ1ZSwgImFkIjogMTAsICJkaSI6ICIyOTQ4ZTMwMWYyZGJjMmNkNTJjNzI4NGUyZWJiZDZiZCJ9fHxTaW5nbGVEZXBvc2l0T2ZmZXJ8fDA3ZGQzOGVhY2NlYTlhYmRiY2E1ZDNlM2Q2OWY4Mjky + * deposit : {"currency":"USD","amount":"501.00"} + * crypto : DASH + * amount : {"DASH":"51.562","dots":"51,562,544.25","bits":"51,562,544.25","BTC":"51.562"} + * discoveryId : 2948e301f2dbc2cd52c7284e2ebbd6bd + * distance : 0 + * address : + * state : + * bankName : MoneyGram + * bankLogo : /media/logos/logo_us_MoneyGram.png + * bankLogoHq : /media/logos/logo_us_MoneyGram%402x.png + * bankIcon : /media/logos/icon_us_MoneyGram.png + * bankIconHq : /media/logos/icon_us_MoneyGram%402x.png + * bankLocationUrl : https://secure.moneygram.com/locations + * city : + */ + + public String id; + public DepositBean deposit; + public String crypto; + public AmountBean amount; + public String discoveryId; + public double distance; + public String address; + public String state; + public String bankName; + public String bankLogo; + public String bankLogoHq; + public String bankIcon; + public String bankIconHq; + public String bankLocationUrl; + public String city; + + + } + + public static class DoubleDepositBean { + /** + * id : eyJkaSI6ICIyOTQ4ZTMwMWYyZGJjMmNkNTJjNzI4NGUyZWJiZDZiZCIsICJhZDIiOiAzMywgImFkMSI6IDQxfXx8RG91YmxlRGVwb3NpdE9mZmVyfHxlOGU2NzBmMTM2MmE5ZjQ5MGQzZGE0ZWI3MjIxNWE4MA== + * firstOffer : {"deposit":{"currency":"USD","amount":"490.00"},"crypto":"DASH","amount":{"DASH":"47.547","dots":"47,547,115.08","bits":"47,547,115.08","BTC":"47.547"},"discoveryId":"2948e301f2dbc2cd52c7284e2ebbd6bd","distance":0.9639473391774286,"address":"240 N Washington Blvd, #100","state":"FL","bankName":"Chase","bankLogo":"/media/logos/logo_us_Chase.png","bankLogoHq":"/media/logos/logo_us_Chase%402x.png","bankIcon":"/media/logos/icon_us_Chase.png","bankIconHq":"/media/logos/icon_us_Chase%402x.png","bankLocationUrl":null,"city":"Sarasota"} + * secondOffer : {"deposit":{"currency":"USD","amount":"10.00"},"crypto":"DASH","amount":{"DASH":"0.088","dots":"88,491.58","bits":"88,491.58","BTC":"0.088"},"discoveryId":"2948e301f2dbc2cd52c7284e2ebbd6bd","distance":0.9639473391774286,"address":"240 N Washington Blvd, #100","state":"FL","bankName":"Chase","bankLogo":"/media/logos/logo_us_Chase.png","bankLogoHq":"/media/logos/logo_us_Chase%402x.png","bankIcon":"/media/logos/icon_us_Chase.png","bankIconHq":"/media/logos/icon_us_Chase%402x.png","bankLocationUrl":null,"city":"Sarasota"} + * totalAmount : {"bits":"47,635,606.67","BTC":"47.635"} + * totalDeposit : {"currency":"USD","amount":"500.00"} + */ + + public String id; + public FirstOfferBean firstOffer; + public SecondOfferBean secondOffer; + public AmountBean totalAmount; + public DepositBean totalDeposit; + + public static class FirstOfferBean { + /** + * deposit : {"currency":"USD","amount":"490.00"} + * crypto : DASH + * amount : {"DASH":"47.547","dots":"47,547,115.08","bits":"47,547,115.08","BTC":"47.547"} + * discoveryId : 2948e301f2dbc2cd52c7284e2ebbd6bd + * distance : 0.9639473391774286 + * address : 240 N Washington Blvd, #100 + * state : FL + * bankName : Chase + * bankLogo : /media/logos/logo_us_Chase.png + * bankLogoHq : /media/logos/logo_us_Chase%402x.png + * bankIcon : /media/logos/icon_us_Chase.png + * bankIconHq : /media/logos/icon_us_Chase%402x.png + * bankLocationUrl : null + * city : Sarasota + */ + + public DepositBean deposit; + public String crypto; + public AmountBean amount; + public String discoveryId; + public double distance; + public String address; + public String state; + public String bankName; + public String bankLogo; + public String bankLogoHq; + public String bankIcon; + public String bankIconHq; + public String bankLocationUrl; + public String city; + } + + public static class SecondOfferBean { + /** + * deposit : {"currency":"USD","amount":"10.00"} + * crypto : DASH + * amount : {"DASH":"0.088","dots":"88,491.58","bits":"88,491.58","BTC":"0.088"} + * discoveryId : 2948e301f2dbc2cd52c7284e2ebbd6bd + * distance : 0.9639473391774286 + * address : 240 N Washington Blvd, #100 + * state : FL + * bankName : Chase + * bankLogo : /media/logos/logo_us_Chase.png + * bankLogoHq : /media/logos/logo_us_Chase%402x.png + * bankIcon : /media/logos/icon_us_Chase.png + * bankIconHq : /media/logos/icon_us_Chase%402x.png + * bankLocationUrl : null + * city : Sarasota + */ + + public DepositBean deposit; + public String crypto; + public AmountBean amount; + public String discoveryId; + public double distance; + public String address; + public String state; + public String bankName; + public String bankLogo; + public String bankLogoHq; + public String bankIcon; + public String bankIconHq; + public String bankLocationUrl; + public String city; + } + + public String sumAmounts(String... args) { + + double amount = 0; + + for (String s : args) { + try { + if (s != null) + amount += NumberFormat.getNumberInstance(Locale.getDefault()).parse(s.replaceAll(",","")).doubleValue(); + } catch (ParseException e) { + e.printStackTrace(); + } + } + return NumberFormat.getNumberInstance(Locale.getDefault()).format(amount); + } + } + + public static class DepositBean { + /** + * currency : USD + * amount : 501.00 + */ + + public String currency; + public String amount; + } + + public static class AmountBean { + /** + * DASH : 51.562 + * dots : 51,562,544.25 + * bits : 51,562,544.25 + * BTC : 51.562 + */ + + public String DASH; + public String dots; + public String bits; + public String BTC; + public String uPiv; + public String PIVX; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetReceivingOptionsResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetReceivingOptionsResp.java new file mode 100644 index 000000000..2f7035ea1 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/GetReceivingOptionsResp.java @@ -0,0 +1,110 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class GetReceivingOptionsResp { + + /** + * id : 19 + * name : Axis Bank + * url : https://www.axisbank.com/ + * logo : https://woc.reference.genitrust.com/static/logos/logo_in_Axis%20Bank.png + * logoHq : https://woc.reference.genitrust.com/static/logos/logo_in_Axis%20Bank%402x.png + * icon : https://woc.reference.genitrust.com/static/logos/icon_in_Axis%20Bank.png + * iconHq : https://woc.reference.genitrust.com/static/logos/icon_in_Axis%20Bank%402x.png + * country : in + * payFields : {"payFields":[{"name":"birthCountry","label":"Country of Birth","parse":"","displaySort":2,"paymentDestination_id":17,"id":7},{"name":"pickupState","label":"Pick-up State","parse":"","displaySort":0.5,"paymentDestination_id":17,"id":6},{"name":"lastName","label":"Last Name","parse":"","displaySort":1,"paymentDestination_id":17,"id":5},{"name":"firstName","label":"First Name","parse":"","displaySort":0,"paymentDestination_id":17,"id":4}],"confirmFields":[{"name":"receiveCode","label":"Receive Code (Confirm)","parse":"","displaySort":0,"paymentDestination_id":17,"id":3}],"trigger":"Check here if this is a biller account (Business)","dynamicFields":[{"name":"accountNumber","label":"Customer Account #","parse":"","displaySort":2,"paymentDestination_id":17,"id":4},{"name":"receiveCode","label":"Receive Code","parse":"","displaySort":1.5,"paymentDestination_id":17,"id":3},{"name":"businessCity","label":"Business City/State","parse":"","displaySort":1,"paymentDestination_id":17,"id":2},{"name":"businessName","label":"Business Name","parse":"","displaySort":0,"paymentDestination_id":17,"id":1}]} + */ + + public int id; + public String name; + public String url; + public String logo; + public String logoHq; + public String icon; + public String iconHq; + public String country; + public PayFieldsBeanX payFields; + + + public static class PayFieldsBeanX { + /** + * payFields : [{"name":"birthCountry","label":"Country of Birth","parse":"","displaySort":2,"paymentDestination_id":17,"id":7},{"name":"pickupState","label":"Pick-up State","parse":"","displaySort":0.5,"paymentDestination_id":17,"id":6},{"name":"lastName","label":"Last Name","parse":"","displaySort":1,"paymentDestination_id":17,"id":5},{"name":"firstName","label":"First Name","parse":"","displaySort":0,"paymentDestination_id":17,"id":4}] + * confirmFields : [{"name":"receiveCode","label":"Receive Code (Confirm)","parse":"","displaySort":0,"paymentDestination_id":17,"id":3}] + * trigger : Check here if this is a biller account (Business) + * dynamicFields : [{"name":"accountNumber","label":"Customer Account #","parse":"","displaySort":2,"paymentDestination_id":17,"id":4},{"name":"receiveCode","label":"Receive Code","parse":"","displaySort":1.5,"paymentDestination_id":17,"id":3},{"name":"businessCity","label":"Business City/State","parse":"","displaySort":1,"paymentDestination_id":17,"id":2},{"name":"businessName","label":"Business Name","parse":"","displaySort":0,"paymentDestination_id":17,"id":1}] + */ + + + public String trigger; + @SerializedName("payFields") + public List payFieldsX; + public List confirmFields; + public List dynamicFields; + public Boolean payFieldsB; + + public static class PayFieldsBean { + /** + * name : birthCountry + * label : Country of Birth + * parse : + * displaySort : 2 + * paymentDestination_id : 17 + * id : 7 + */ + + @SerializedName("name") + public String nameX; + public String label; + public String parse; + public float displaySort; + public int paymentDestination_id; + @SerializedName("id") + public int idX; + + + @Override + public String toString() { + return "PayFieldsBean{" + + "nameX='" + nameX + '\'' + + ", label='" + label + '\'' + + ", parse='" + parse + '\'' + + ", displaySort=" + displaySort + + ", paymentDestination_id=" + paymentDestination_id + + ", idX=" + idX + + '}'; + } + } + + @Override + public String toString() { + return "PayFieldsBeanX{" + + "trigger='" + trigger + '\'' + + ", payFieldsX=" + payFieldsX + + ", confirmFields=" + confirmFields + + ", dynamicFields=" + dynamicFields + + '}'; + } + } + + public class JsonPayFieldsBeanX extends PayFieldsBeanX { + } + + + @Override + public String toString() { + return "GetReceivingOptionsResp{" + + "id=" + id + + ", name='" + name + '\'' + + ", url='" + url + '\'' + + ", logo='" + logo + '\'' + + ", logoHq='" + logoHq + '\'' + + ", icon='" + icon + '\'' + + ", iconHq='" + iconHq + '\'' + + ", country='" + country + '\'' + + ", payFields=" + payFields + + '}'; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/OrderListResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/OrderListResp.java new file mode 100644 index 000000000..7491be99f --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/OrderListResp.java @@ -0,0 +1,56 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +/** + * Created on 05-Sep-17. + */ + +public class OrderListResp { + + /** + * id : 85337 + * total : 0.02747620 + * payment : 10.00 + * paymentDue : 2017-09-05T09:31:23.474Z + * bankName : Fifth Third + * nameOnAccount : Todd A Rogers + * account : 7914882944 + * status : WD + * nearestBranch : {"city":"Sarasota","state":"FL","name":"Fifth Third","phone":"(941) 365-6568","address":"50 Central Ave"} + * bankUrl : http://www.53.com + * bankLogo : https://wallofcoins-static.s3.amazonaws.com/logos/logo_18.png + * bankIcon : https://wallofcoins-static.s3.amazonaws.com/logos/icon_18.png + * bankIconHq : https://wallofcoins-static.s3.amazonaws.com/logos/icon_18%402x.png + * privateId : df5a5c438ffea5c36e899858cc33b828e4485a67 + */ + + public int id; + public String total; + public String payment; + public String paymentDue; + public String bankName; + public String nameOnAccount; + public String account; + public String status; + public NearestBranchBean nearestBranch; + public String bankUrl; + public String bankLogo; + public String bankIcon; + public String bankIconHq; + public String privateId; + + public static class NearestBranchBean { + /** + * city : Sarasota + * state : FL + * name : Fifth Third + * phone : (941) 365-6568 + * address : 50 Central Ave + */ + + public String city; + public String state; + public String name; + public String phone; + public String address; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/PayFieldsDeserializer.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/PayFieldsDeserializer.java new file mode 100644 index 000000000..325ff4a9d --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/response/PayFieldsDeserializer.java @@ -0,0 +1,26 @@ +package pivx.org.pivxwallet.wallofcoins.response; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +import java.lang.reflect.Type; + + + +public class PayFieldsDeserializer implements JsonDeserializer { + + private static final String TAG = PayFieldsDeserializer.class.getSimpleName(); + + @Override + public GetReceivingOptionsResp.PayFieldsBeanX deserialize(JsonElement jsonElement, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + if (jsonElement.isJsonPrimitive()) { + GetReceivingOptionsResp.PayFieldsBeanX payFieldsBeanX = new GetReceivingOptionsResp.PayFieldsBeanX(); + payFieldsBeanX.payFieldsB = jsonElement.getAsBoolean(); + return payFieldsBeanX; + } + + return context.deserialize(jsonElement, GetReceivingOptionsResp.JsonPayFieldsBeanX.class); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/SellingBaseActivity.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/SellingBaseActivity.java new file mode 100644 index 000000000..96963a8ea --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/SellingBaseActivity.java @@ -0,0 +1,127 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.BuyDashPref; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.selling_home.SellingHomeFragment; + +/** + * Created on 03-Apr-18. + */ + +public class SellingBaseActivity extends AppCompatActivity implements View.OnClickListener { + + + private FragmentManager fragmentManager; + private FragmentTransaction fragmentTransaction; + public BuyDashPref buyDashPref; + private ImageView image_toolbar_back; + private TextView text_toolbar_title; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_base_selling_wizard); + init(); + setListners(); + replaceFragment(new SellingHomeFragment(), true, false); + + } + + private void init() { + fragmentManager = getSupportFragmentManager(); + image_toolbar_back = (ImageView) findViewById(R.id.image_toolbar_back); + text_toolbar_title = (TextView) findViewById(R.id.text_toolbar_title); + + } + + private void setListners() { + image_toolbar_back.setOnClickListener(this); + } + + public void replaceFragment(Fragment fragment, boolean withAnimation, boolean withBackStack) { + fragmentTransaction = fragmentManager.beginTransaction(); + Log.e("Fragment name", fragment.getClass().getName()); + if (withAnimation) + fragmentTransaction.setCustomAnimations(R.anim.activity_in, R.anim.activity_out, R.anim.activity_backin, R.anim.activity_back_out); + if (withBackStack) + fragmentTransaction.replace(R.id.container_selling_base, fragment).addToBackStack(fragment.getClass().getName()); + else + fragmentTransaction.replace(R.id.container_selling_base, fragment); + fragmentTransaction.commitAllowingStateLoss(); + } + + public void setTopbarTitle(String msg) { + text_toolbar_title.setText(msg); + } + + public void finishBaseActivity() { + this.finish(); + } + + public void popBackDirect() { + if (fragmentManager.getBackStackEntryCount() > 0) + fragmentManager.popBackStack(); + else + this.finish(); + + } + + @Override + public void onBackPressed() { + popBackDirect(); + //super.onBackPressed(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + + @Override + public void onClick(View view) { + switch (view.getId()) { + + case R.id.image_toolbar_back: + popBackDirect(); + break; + + case R.id.wallet_balance: + break; + } + + + } + + @Override + public void onResume() { + super.onResume(); + } + + public void popBackInclusive(String tag) { + fragmentManager.popBackStack(tag, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + + public void removeAllFragmentFromStack() { + + if (fragmentManager.getBackStackEntryCount() > 0) { + FragmentUtils.sDisableFragmentAnimations = true; + fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + FragmentUtils.sDisableFragmentAnimations = false; + } + } +} + diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/SellingBaseFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/SellingBaseFragment.java new file mode 100644 index 000000000..8fb03584a --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/SellingBaseFragment.java @@ -0,0 +1,171 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.location.Address; +import android.location.Geocoder; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.util.Base64; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Toast; + +import com.google.common.base.Charsets; + +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +import okhttp3.Interceptor; +import okhttp3.Request; +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingApiConstants; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.storage.SharedPreferenceUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.SellingConstants; + +/** + * Created on 03-Apr-18. + */ + +public class SellingBaseFragment extends Fragment { + + protected Context mContext; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + } + + /** + * Method for Open web url link in external browser app + * + * @param url + */ + protected void goToUrl(String url) { + Uri uriUrl = Uri.parse(url); + Intent launchBrowser = new Intent(Intent.ACTION_VIEW, uriUrl); + startActivity(launchBrowser); + } + + /** + * get country code form current latitude & longitude + * + * @return Country Code + */ + protected String getCountryCode(double latitude, double longitude) { + String countryCode = ""; + try { + Geocoder geo = new Geocoder(mContext, Locale.getDefault()); + List
addresses = geo.getFromLocation(latitude, longitude, 1); + Address obj = addresses.get(0); + countryCode = obj.getCountryCode(); + } catch (Exception e) { + e.printStackTrace(); + } + + if (countryCode.equals("")) { + return "us"; + } else { + return countryCode; + } + } + + /** + * Method for hide keyboard + */ + protected void hideKeyBoard() { + View view = getActivity().getCurrentFocus(); + if (view != null) { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + + + @SuppressLint("HardwareIds") + protected String getDeviceCode(Context context) { + + String deviceUID = SharedPreferenceUtil.getString(SellingConstants.PREF_DEVICE_CODE, ""); + if (TextUtils.isEmpty(deviceUID)) { + String deviceID; + deviceID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); + byte[] data = (deviceID + deviceID + deviceID).getBytes(Charsets.UTF_8); + deviceUID = Base64.encodeToString(data, Base64.DEFAULT).substring(0, 39); + SharedPreferenceUtil.putValue(SellingConstants.PREF_DEVICE_CODE, deviceUID); + } + + return deviceUID; + } + + protected void showToast(String msg) { + Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show(); + } + + /** + * Validate Email id + * + * @param target Email + * @return boolean for email valid or not + */ + protected boolean isValidEmail(CharSequence target) { + if (target == null) { + return false; + } else { + return android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches(); + } + } + + /** + * Show alert dialog wrong username or password + */ + protected void showAlertPasswordDialog() { + AlertDialog.Builder builder; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + builder = new AlertDialog.Builder(mContext, android.R.style.Theme_Material_Dialog_Alert); + } else { + builder = new AlertDialog.Builder(mContext); + } + builder.setTitle("") + .setMessage(getString(R.string.user_pass_wrong)) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .show(); + } + + /** + * API Header parameter interceptor + */ + protected Interceptor interceptor = new Interceptor() { + @Override + public okhttp3.Response intercept(Chain chain) throws IOException { + Request original = chain.request(); + // Request customization: add request headers + Request.Builder requestBuilder = original.newBuilder(); + if (!TextUtils.isEmpty(SharedPreferenceUtil.getString(SellingConstants.PREF_TOKEN_ID, ""))) { + requestBuilder.addHeader(SellingApiConstants.KEY_HEADER_AUTH_TOKEN, + SharedPreferenceUtil.getString(SellingConstants.PREF_TOKEN_ID, "")); + } + requestBuilder.addHeader(SellingApiConstants.KEY_HEADER_PUBLISHER_ID, + SellingApiConstants.WALLOFCOINS_PUBLISHER_ID); + requestBuilder.addHeader(SellingApiConstants.KEY_HEADER_CONTENT_TYPE, + SellingApiConstants.KEY_HEADER_CONTENT_TYPE_VALUE); + Request request = requestBuilder.build(); + return chain.proceed(request); + } + }; +} + + diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/AddressListAdapter.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/AddressListAdapter.java new file mode 100644 index 000000000..38bdd6d7d --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/AddressListAdapter.java @@ -0,0 +1,54 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.adapters; + +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.ArrayList; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AddressListRespVo; + +/** + * Created on 06-Apr-18. + */ + +public class AddressListAdapter extends RecyclerView.Adapter { + + + private ArrayList body; + LayoutInflater inflater; + + public AddressListAdapter(ArrayList body) { + this.body = body; + } + + @Override + public VHListing onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_selling_address, parent, false); + + return new VHListing(itemView); + } + + @Override + public void onBindViewHolder(VHListing holder, int position) { + holder.text_current_price.setText(body.get(position).getCurrentPrice()); + } + + @Override + public int getItemCount() { + return body.size(); + } + + class VHListing extends RecyclerView.ViewHolder { + private TextView text_current_price; + + private VHListing(View view) { + super(view); + this.text_current_price = (TextView) view.findViewById(R.id.text_current_price); + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/CountryAdapter.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/CountryAdapter.java new file mode 100644 index 000000000..dbda89189 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/CountryAdapter.java @@ -0,0 +1,82 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.adapters; + +import android.app.Activity; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.NonNull; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.response.CountryData; + + +public class CountryAdapter extends ArrayAdapter { + + private Activity activity; + private List data; + private LayoutInflater inflater; + + public CountryAdapter( + Activity activitySpinner, + int textViewResourceId, + List objects + ) { + super(activitySpinner, textViewResourceId, objects); + + /********** Take passed values **********/ + activity = activitySpinner; + data = objects; + + /*********** Layout inflator to call external xml layout () **********************/ + inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + @Override + public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { + return getCustomView(position, convertView, parent); + } + + @Override + public View getView(int position, View convertView, @NonNull ViewGroup parent) { + return getCustomView(position, convertView, parent); + } + + // This funtion called for each row ( Called data.size() times ) + public View getCustomView(int position, View convertView, ViewGroup parent) { + + /********** Inflate spinner_rows.xml file for each row ( Defined below ) ************/ + View row = inflater.inflate(R.layout.item_selling_country, parent, false); + + /***** Get each Model object from Arraylist ********/ + CountryData.CountriesBean bean = data.get(position); + + TextView text_country = (TextView) row.findViewById(R.id.text_country); + ImageView image_country = (ImageView) row.findViewById(R.id.image_country); + + text_country.setText(bean.name + " (" + bean.code + ")"); + image_country.setImageResource(R.drawable.flags); + image_country.setScaleType(ImageView.ScaleType.MATRIX); + + Drawable drawable = activity.getResources().getDrawable(R.drawable.flags); + + int height = drawable.getIntrinsicHeight(); + int width = drawable.getIntrinsicWidth(); + + int left = (bean.left * width) / 288; + int top = (bean.top * height) / 266; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + image_country.drawableHotspotChanged(left, top); + } + return row; + } + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/PhoneListAdapter.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/PhoneListAdapter.java new file mode 100644 index 000000000..3e54f6858 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/adapters/PhoneListAdapter.java @@ -0,0 +1,69 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.adapters; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +import java.util.ArrayList; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.PhoneListVO; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.phone_list.PhoneListFragment; + + +/** + * Created on 19-Mar-18. + */ + +public class PhoneListAdapter extends RecyclerView.Adapter { + + private Context mContext; + private ArrayList phoneListVOS; + private PhoneListFragment fragment; + + public PhoneListAdapter(Context context, ArrayList phoneListVOS, PhoneListFragment fragment) { + this.mContext = context; + this.phoneListVOS = phoneListVOS; + this.fragment = fragment; + } + + @Override + public PhoneListAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_selling_phone_list, parent, false); + + return new MyViewHolder(itemView); + } + + @Override + public void onBindViewHolder(PhoneListAdapter.MyViewHolder holder, final int position) { + final PhoneListVO phoneListVO = phoneListVOS.get(holder.getAdapterPosition()); + + holder.button_phone.setText(mContext.getString(R.string.sign_in2, phoneListVO.getPhoneNumber())); + + holder.button_phone.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + fragment.onItemClick(phoneListVO.getPhoneNumber()); + } + }); + + } + + @Override + public int getItemCount() { + return phoneListVOS.size(); + } + + public class MyViewHolder extends RecyclerView.ViewHolder { + private Button button_phone; + + private MyViewHolder(View view) { + super(view); + this.button_phone = (Button) view.findViewById(R.id.button_phone); + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/add_listing/AddressListingFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/add_listing/AddressListingFragment.java new file mode 100644 index 000000000..125c3264e --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/add_listing/AddressListingFragment.java @@ -0,0 +1,112 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.add_listing; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; + +import java.util.ArrayList; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.adapters.AddressListAdapter; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingAPIClient; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AddressListRespVo; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 06-Apr-18. + */ + +public class AddressListingFragment extends SellingBaseFragment { + + private View rootView; + private RecyclerView rv_sell_dash_ads_list; + private ArrayList voArrayList; + private ProgressBar progressBar; + private AddressListAdapter adapter; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_address_listing, container, false); + init(); + setListeners(); + setTopbar(); + setAdapter(); + getAddressList(); + return rootView; + } else + return rootView; + } + + private void setAdapter() { + adapter = new AddressListAdapter(voArrayList); + rv_sell_dash_ads_list.setAdapter(adapter); + } + + private void init() { + rv_sell_dash_ads_list = (RecyclerView) rootView.findViewById(R.id.rv_sell_dash_ads_list); + rv_sell_dash_ads_list.setLayoutManager(new LinearLayoutManager(mContext)); + progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); + voArrayList = new ArrayList<>(); + } + + private void setListeners() { + //btnContinue.setOnClickListener(this); + } + + private void setTopbar() { + ((SellingBaseActivity) mContext).setTopbarTitle( + mContext.getString(R.string.title_address)); + } + + private void getAddressList() { + progressBar.setVisibility(View.VISIBLE); + //here show the listing of ads first and if empty then redirect back to create Ads screen @getReceivingOptions + SellingAPIClient.createService(interceptor, getActivity()).getAddressListing(). + enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + + if (response.code() == 200) { + progressBar.setVisibility(View.GONE); + + if (response.body() != null && response.body().size() > 0) { + //here show the list + voArrayList = response.body(); + setAdapter(); + + } else { + showToast(getString(R.string.no_ad_created)); + //getReceivingOptions(); + } + } else { + //getReceivingOptions(); + } + + } + + @Override + public void onFailure(Call> call, Throwable t) { + progressBar.setVisibility(View.GONE); + showToast(t.getMessage()); + } + }); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/advanced_options/AdvanceOptionsFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/advanced_options/AdvanceOptionsFragment.java new file mode 100644 index 000000000..17c2a9ba8 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/advanced_options/AdvanceOptionsFragment.java @@ -0,0 +1,129 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.advanced_options; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AddressVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.SellingConstants; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.verify_details.VerifySellingDetailsFragment; + +/** + * Created on 20-Apr-18. + */ + +public class AdvanceOptionsFragment extends SellingBaseFragment implements View.OnClickListener { + + private View rootView; + private CheckBox checkbox; + private Button button_cancle, button_save; + private EditText edit_min_payment, edit_max_payment; + private AddressVo addressVo; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.dialog_selling_options, container, false); + init(); + setListeners(); + setTopbar(); + handleArgs(); + return rootView; + } else + return rootView; + } + + private void init() { + + edit_min_payment = (EditText) rootView.findViewById(R.id.edit_min_payment); + edit_max_payment = (EditText) rootView.findViewById(R.id.edit_max_payment); + button_cancle = (Button) rootView.findViewById(R.id.button_cancle); + button_save = (Button) rootView.findViewById(R.id.button_save); + checkbox = (CheckBox) rootView.findViewById(R.id.checkbox); + + button_save.setText(getString(R.string.action_continue)); + } + + private void setListeners() { + button_cancle.setOnClickListener(this); + button_save.setOnClickListener(this); + } + + private void setTopbar() { + ((SellingBaseActivity) mContext).setTopbarTitle( + mContext.getString(R.string.title_advanced_options)); + } + + private void handleArgs() { + + if (getArguments() != null) { + addressVo = (AddressVo) + getArguments().getSerializable(SellingConstants.ARGUMENT_ADDRESS_DETAILS_VO); + } + } + + @Override + public void onClick(View view) { + + switch (view.getId()) { + case R.id.button_save: + if (isValidDetails()) { + Bundle bundle = new Bundle(); + bundle.putSerializable(SellingConstants.ARGUMENT_ADDRESS_DETAILS_VO, getSellingDetails()); + VerifySellingDetailsFragment fragment = new VerifySellingDetailsFragment(); + fragment.setArguments(bundle); + + ((SellingBaseActivity) mContext).replaceFragment(fragment, true, true); + } + break; + case R.id.button_cancle: + showToast("Under Implementation"); + break; + + + } + } + + @Override + public void onResume() { + super.onResume(); + setTopbar(); + } + + private boolean isValidDetails() { + + if (edit_min_payment.getText().toString().isEmpty()) { + showToast(getString(R.string.enter_min_payment)); + edit_min_payment.requestFocus(); + return false; + } else if (edit_max_payment.getText().toString().isEmpty()) { + showToast(getString(R.string.enter_max_payment)); + edit_max_payment.requestFocus(); + return false; + } else if (!checkbox.isChecked()) { + return false; + } + return true; + } + + private AddressVo getSellingDetails() { + + return addressVo; + } +} \ No newline at end of file diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/RetrofitErrorUtil.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/RetrofitErrorUtil.java new file mode 100644 index 000000000..3bc7e0597 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/RetrofitErrorUtil.java @@ -0,0 +1,37 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.api; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.WOCLogUtil; +import retrofit2.Response; + +/** + * Created on 05-Apr-18. + */ + +public class RetrofitErrorUtil { + public static String parseError(Response response) { + BufferedReader reader = null; + StringBuilder sb = new StringBuilder(); + try { + reader = new BufferedReader(new InputStreamReader(response.errorBody().byteStream())); + String line; + try { + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + } catch (Exception e) { + e.printStackTrace(); + } + String finallyError = sb.toString(); + + WOCLogUtil.showLogError("getErrorList", finallyError); + return finallyError; + } +} + diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingAPIClient.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingAPIClient.java new file mode 100644 index 000000000..40e8ae6c2 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingAPIClient.java @@ -0,0 +1,131 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.api; + +import android.content.Context; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; +import pivx.org.pivxwallet.BuildConfig; +import pivx.org.pivxwallet.wallofcoins.api.RestApi; +import pivx.org.pivxwallet.wallofcoins.response.GetReceivingOptionsResp; +import pivx.org.pivxwallet.wallofcoins.response.PayFieldsDeserializer; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * Created on 04-Apr-18. + */ + +public class SellingAPIClient { + private static String API_BASE_URL; + + static final TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + } + }; + + /** + * Method for Create RestAPI call + * + * @param interceptor + * @param context context object of parent class + * @return RestApi Client object + */ + public static SellingApi createService(Interceptor interceptor, Context context) { + API_BASE_URL = SellingApiConstants.BASE_URL; + return getClient(interceptor) + .create(SellingApi.class); + } + + /** + * Method for Create RestAPI call + * + * @param context context object of parent class + * @return RestApi Client object + */ + public static SellingApi createService(Context context) { + API_BASE_URL = SellingApiConstants.BASE_URL; + return getClient(null) + .create(SellingApi.class); + } + + /** + * Method for get retrofit + * + * @param interceptor + * @return Retrofit Object + */ + private static Retrofit getClient(Interceptor interceptor) { + + OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); + // add your other interceptors … + httpClient.connectTimeout(60, TimeUnit.SECONDS); + httpClient.readTimeout(60, TimeUnit.SECONDS); + try { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, null); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, "keystore_pass".toCharArray()); + sslContext.init(null, trustAllCerts, new SecureRandom()); + httpClient.sslSocketFactory(sslContext.getSocketFactory()) + .hostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + + HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); + // set your desired log level + logging.setLevel(HttpLoggingInterceptor.Level.BODY); + // add logging as last interceptor + if (BuildConfig.DEBUG) + httpClient.addInterceptor(logging); // <-- this is the important line! + if (null != interceptor) + httpClient.addInterceptor(interceptor); + + Gson gson = new GsonBuilder() + .registerTypeAdapter(GetReceivingOptionsResp.PayFieldsBeanX.class, new PayFieldsDeserializer()) + .create(); + + return new Retrofit.Builder() + .baseUrl(SellingApiConstants.BASE_URL).client(httpClient.build()) + .addConverterFactory(GsonConverterFactory.create(gson)).build(); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingApi.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingApi.java new file mode 100644 index 000000000..3a824e533 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingApi.java @@ -0,0 +1,135 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.api; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import pivx.org.pivxwallet.wallofcoins.response.CaptureHoldResp; +import pivx.org.pivxwallet.wallofcoins.response.CheckAuthResp; +import pivx.org.pivxwallet.wallofcoins.response.ConfirmDepositResp; +import pivx.org.pivxwallet.wallofcoins.response.CreateHoldResp; +import pivx.org.pivxwallet.wallofcoins.response.DiscoveryInputsResp; +import pivx.org.pivxwallet.wallofcoins.response.GetAuthTokenResp; +import pivx.org.pivxwallet.wallofcoins.response.GetCurrencyResp; +import pivx.org.pivxwallet.wallofcoins.response.GetHoldsResp; +import pivx.org.pivxwallet.wallofcoins.response.GetOffersResp; +import pivx.org.pivxwallet.wallofcoins.response.OrderListResp; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AddressListRespVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AddressVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AuthVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.CreateDeviceVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.GetReceivingOptionsResp; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.MarketsVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.SendVerificationRespVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.SignUpResponseVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.VerifyAdResp; +import retrofit2.Call; +import retrofit2.http.DELETE; +import retrofit2.http.Field; +import retrofit2.http.FieldMap; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Path; +import retrofit2.http.Query; + +/** + * Created on 04-Apr-18. + */ + +public interface SellingApi { + + @FormUrlEncoded + @POST(SellingApiConstants.CREATE_AUTH) + Call signUp(@FieldMap Map partMap); + + + //crypto=PIVX currency=USD + @GET(SellingApiConstants.MARKETS + "{crypto}/{currency}/") + Call> getMarkets(@Path("crypto") String crypto, @Path("currency") String currency); + + + //create address + @FormUrlEncoded + @POST(SellingApiConstants.CREATE_ADDRESS) + Call createAddress(@FieldMap Map partMap); + + + //send verification code + @FormUrlEncoded + @POST(SellingApiConstants.SEND_VERIFICATION) + Call sendVerificationCode(@FieldMap Map partMap); + + @GET(SellingApiConstants.GET_AUTH + "{phone}/") + Call getAuthToken(@Path("phone") String phone, @Query("publisherId") String publisherId); + + + @FormUrlEncoded + @POST("api/v1/auth/{phone}/authorize/") + Call authorize(@Path("phone") String username, @FieldMap Map partMap); + + @DELETE("api/v1/auth/{phone}/") + Call deleteAuth(@Path("phone") String username, @Query("publisherId") String publisherId); + + @FormUrlEncoded + @POST("api/verifyAd/") + Call verifyAd(@FieldMap Map partMap); + + @GET("api/v1/ad/") + Call> getAddressListing(); + + //---------------------------------------------------------- + @GET("api/v1/orders/") + Call> getOrders(@Query("publisherId") String publisherId); + + + @DELETE("api/v1/orders/{orderId}/") + Call cancelOrder(@Path("orderId") String orderId, @Query("publisherId") String publisherId); + + @FormUrlEncoded + @POST("api/v1/auth/{phone}/authorize/") + Call getAuthToken(@Path("phone") String username, @FieldMap Map partMap); + + + //--------------dash wizard + @GET("api/v1/banks/") + Call> getReceivingOptions(@Query("country") String country); + //---------------------- + + @GET("api/v1/currency/") + Call> getCurrency(); + + @FormUrlEncoded + @POST("api/v1/discoveryInputs/") + Call discoveryInputs(@FieldMap Map partMap); + + @GET("api/v1/discoveryInputs/{discoveryId}/offers/") + Call getOffers(@Path("discoveryId") String discoveryId, @Query("publisherId") String publisherId); + + @FormUrlEncoded + @POST("api/v1/holds/") + Call createHold(@FieldMap Map partMap); + + @GET("api/v1/holds/") + Call> getHolds(); + + @DELETE("api/v1/holds/{id}/") + Call deleteHold(@Path("id") String id); + + @FormUrlEncoded + @POST("api/v1/holds/{id}/capture/") + Call> captureHold(@Path("id") String id, @FieldMap Map partMap); + + @FormUrlEncoded + @POST("api/v1/orders/{holdId}/confirmDeposit/") + Call confirmDeposit(@Path("holdId") String holdId, @Field("your_field") String yourField, @Query("publisherId") String publisherId); + + @FormUrlEncoded + @POST("api/v1/devices/") + Call createDevice(@FieldMap Map partMap); + + @GET("api/v1/devices/") + Call> getDevice(); + + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingApiConstants.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingApiConstants.java new file mode 100644 index 000000000..4eff6dd78 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/api/SellingApiConstants.java @@ -0,0 +1,51 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.api; + +/** + * Created on 04-Apr-18. + */ + +public class SellingApiConstants { + + public static String BASE_URL = "https://woc.reference.genitrust.com/"; + public final static String CREATE_AUTH = "api/v1/auth/"; + public final static String GET_AUTH = "api/v1/auth/"; + public final static String MARKETS = "api/v1/markets/"; + public final static String CREATE_ADDRESS = "api/adcreate/"; + public final static String SEND_VERIFICATION = "api/v1/sendVerification/"; + + public static final String WALLOFCOINS_PUBLISHER_ID = "46"; + public static final String KEY_HEADER_AUTH_TOKEN = "X-Coins-Api-Token"; + public static final String KEY_HEADER_PUBLISHER_ID = "X-Coins-Publisher"; + public static final String KEY_HEADER_CONTENT_TYPE = "Content-Type"; + public static final String KEY_HEADER_CONTENT_TYPE_VALUE = "application/json"; + public static final String KEY_PUBLISHER_ID = "publisherId"; + public static final String KEY_PHONE = "phone"; + public static final String KEY_EMAIL = "email"; + public static final String KEY_PASSWORD = "password"; + public static final String AD_ID = "ad_id"; + public static final String CODE = "code"; + public static final String KEY_DEVICECODE = "deviceCode"; + public static final String KEY_DEVICEID = "deviceId"; + public static final String DEVICE_NAME = "PIV Wallet (Android)"; + public static final String KEY_DEVICE_NAME = "name"; + public static final String KEY_CODE = "code"; + public static final String KEY_USER_ENABLED = "userEnabled"; + public static final String KEY_PHONE_CODE = "phoneCode"; + public static final String KEY_BANK_BUSINESS = "bankBusiness"; + public static final String KEY_DYNAMIC_PRICE = "dynamicPrice"; + public static final String KEY_USER_PAY_FIELDS = "usePayFields"; + public static final String KEY_PRIMARY_MARKETS = "primaryMarket"; + public static final String KEY_SECONDARY_MARKETS = "secondaryMarket"; + public static final String KEY_MIN_PAYMETS = "minPayment"; + public static final String KEY_MAX_PAYMETS = "maxPayment"; + public static final String KEY_SELLER_FEE = "sellerFee"; + public static final String KEY_CURRENT_PRICE = "currentPrice"; + public static final String KEY_NAME = "name"; + public static final String KEY_NUMBER = "number"; + public static final String KEY_NUMBER2 = "number2"; + public static final String KEY_SELL_CRYPTO = "sellCrypto"; + + + + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/cash_deposit/CashDepositFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/cash_deposit/CashDepositFragment.java new file mode 100644 index 000000000..34e1d7799 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/cash_deposit/CashDepositFragment.java @@ -0,0 +1,246 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.cash_deposit; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatSpinner; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingAPIClient; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AddressVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.GetReceivingOptionsResp; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.price.PriceFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.SellingConstants; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 04-Apr-18. + */ + +public class CashDepositFragment extends SellingBaseFragment implements View.OnClickListener { + + + private View rootView; + private Button button_continue; + private EditText edit_holder_name, edit_account_number, edit_confirm_account_number; + private final String TAG = "CashDepositFragment"; + private AppCompatSpinner spinner_banks; + private ProgressBar progressBar; + private String mBankId = ""; + private List bankList; + private RelativeLayout layout_acc_details; + private AddressVo addressVo; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_cash_deposit, container, false); + init(); + setListeners(); + setTopbar(); + getReceivingOptions(); + handleArgs(); + return rootView; + } else + return rootView; + } + + private void init() { + + edit_holder_name = (EditText) rootView.findViewById(R.id.edit_holder_name); + edit_account_number = (EditText) rootView.findViewById(R.id.edit_account_number); + edit_confirm_account_number = (EditText) rootView.findViewById(R.id.edit_confirm_account_number); + spinner_banks = (AppCompatSpinner) rootView.findViewById(R.id.spinner_banks); + button_continue = (Button) rootView.findViewById(R.id.button_continue); + progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); + layout_acc_details = (RelativeLayout) rootView.findViewById(R.id.layout_acc_details); + + bankList = new ArrayList<>(); + } + + private void setListeners() { + button_continue.setOnClickListener(this); + spinner_banks.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView adapterView, View view, int position, long l) { + if (position == 0) { + layout_acc_details.setVisibility(View.GONE); + mBankId = ""; + return; + } + layout_acc_details.setVisibility(View.VISIBLE); + mBankId = "" + bankList.get(position).id; + } + + @Override + public void onNothingSelected(AdapterView adapterView) { + + } + }); + + } + + private void setTopbar() { + + ((SellingBaseActivity) mContext).setTopbarTitle( + mContext.getString(R.string.title_cash_depo_details)); + } + + private boolean isValidDetails() { + String acc, confirmAcc; + acc = edit_account_number.getText().toString().trim(); + confirmAcc = edit_confirm_account_number.getText().toString().trim(); + + if (mBankId.isEmpty()) { + showToast(getString(R.string.please_select_bank)); + return false; + } else if (edit_holder_name.getText().toString().trim().isEmpty()) { + showToast(getString(R.string.please_enter_holder)); + edit_holder_name.requestFocus(); + return false; + } else if (acc.isEmpty()) { + showToast(getString(R.string.please_enter_acc_no)); + edit_account_number.requestFocus(); + return false; + } else if (confirmAcc.isEmpty()) { + showToast(getString(R.string.please_enter_conf_acc_no)); + edit_confirm_account_number.requestFocus(); + return false; + } else if (!acc.equalsIgnoreCase(confirmAcc)) { + showToast(getString(R.string.acc_not_matched)); + return false; + } + return true; + } + + @Override + public void onResume() { + super.onResume(); + setTopbar(); + } + + /** + * API call for get all bank list by country code + */ + private void getReceivingOptions() { + if (NetworkUtil.isOnline(mContext)) { + String locale; + locale = getResources().getConfiguration().locale.getCountry(); + progressBar.setVisibility(View.VISIBLE); + SellingAPIClient.createService(interceptor, mContext).getReceivingOptions("").enqueue(new Callback>() { + + @Override + public void onResponse(Call> call, Response> response) { + progressBar.setVisibility(View.GONE); + if (response.body() != null) { + Log.e(TAG, "onResponse: " + response.body().size()); + progressBar.setVisibility(View.GONE); + //set data in drop down list + setPaymentOptNames(response.body()); + } + + } + + @Override + public void onFailure(Call> call, Throwable t) { + progressBar.setVisibility(View.GONE); + showToast(t.getMessage()); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + private void handleArgs() { + + if (getArguments() != null) { + addressVo = (AddressVo) + getArguments().getSerializable(SellingConstants.ARGUMENT_ADDRESS_DETAILS_VO); + } + } + + /** + * Set Payment option name for Payment options + * + * @param receivingOptionsResps + */ + private void setPaymentOptNames(final List receivingOptionsResps) { + bankList = receivingOptionsResps; + + final ArrayList names = new ArrayList(); + GetReceivingOptionsResp optionsRespDefaultName = new GetReceivingOptionsResp(); + Collections.sort(bankList, new ContactComparator()); + + optionsRespDefaultName.name = getString(R.string.label_select_payment_center); + bankList.add(0, optionsRespDefaultName); + + for (GetReceivingOptionsResp receivingOptionsResp : bankList) { + names.add((receivingOptionsResp.name)); + } + ArrayAdapter adapter = new ArrayAdapter(mContext, android.R.layout.simple_spinner_dropdown_item, names); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner_banks.setAdapter(adapter); + + } + + private class ContactComparator implements Comparator { + public int compare(GetReceivingOptionsResp optionsResp1, GetReceivingOptionsResp optionsResp2) { + //In the following line you set the criterion, + //which is the name of Contact in my example scenario + return optionsResp1.name.compareTo(optionsResp2.name); + } + } + + @Override + public void onClick(View view) { + + switch (view.getId()) { + case R.id.button_continue: + if (isValidDetails()) { + Bundle bundle = new Bundle(); + bundle.putSerializable(SellingConstants.ARGUMENT_ADDRESS_DETAILS_VO, getSellingDetails()); + PriceFragment fragment = new PriceFragment(); + fragment.setArguments(bundle); + ((SellingBaseActivity) mContext).replaceFragment(fragment, + true, true); + } + break; + } + } + + private AddressVo getSellingDetails() { + addressVo.setName(edit_holder_name.getText().toString().trim()); + addressVo.setNumber(edit_account_number.getText().toString().trim()); + addressVo.setNumber2(edit_confirm_account_number.getText().toString().trim()); + addressVo.setBankBusiness(mBankId); + return addressVo; + } +} \ No newline at end of file diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/common/PhoneUtil.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/common/PhoneUtil.java new file mode 100644 index 000000000..eb952a746 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/common/PhoneUtil.java @@ -0,0 +1,81 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.common; + +import android.util.Log; + +import java.util.ArrayList; + +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.PhoneListVO; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.storage.SharedPreferenceUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.ObjectSerializer; + +/** + * Created on 04-Apr-18. + */ + +public class PhoneUtil { + + private static final String PREF_SELLING_SESSION_DETAILS = "PREF_SELLING_SESSION_DETAILS"; + + public static void addPhone(String phone, String deviceId) { + ArrayList voArrayList; + + try { + voArrayList = (ArrayList) ObjectSerializer.deserialize( + SharedPreferenceUtil.getString(PREF_SELLING_SESSION_DETAILS, + ObjectSerializer.serialize(new ArrayList()))); + PhoneListVO createHoldResp = new PhoneListVO(); + createHoldResp.setDeviceId(deviceId); + createHoldResp.setPhoneNumber(phone); + + voArrayList.add(createHoldResp); + + + SharedPreferenceUtil.putValue(PREF_SELLING_SESSION_DETAILS, + ObjectSerializer.serialize(voArrayList)); + + + for (PhoneListVO vo : voArrayList) { + Log.e("Auth id list", vo.getDeviceId()); + Log.e("phone no list", vo.getPhoneNumber()); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static ArrayList getStoredPhoneList() { + ArrayList voArrayList = new ArrayList<>(); + + try { + voArrayList = (ArrayList) ObjectSerializer.deserialize( + SharedPreferenceUtil.getString(PREF_SELLING_SESSION_DETAILS, + ObjectSerializer.serialize(new ArrayList()))); + } catch (Exception e) { + e.printStackTrace(); + } + return voArrayList; + } + + public String getDeviceIdFromPhone(String phone) { + String deviceId = ""; + ArrayList voArrayList; + + try { + voArrayList = (ArrayList) ObjectSerializer. + deserialize(SharedPreferenceUtil.getString(PREF_SELLING_SESSION_DETAILS, + ObjectSerializer.serialize(new ArrayList()))); + + for (PhoneListVO vo : voArrayList) { + Log.e("Stored phone", vo.getPhoneNumber() + "---" + "Stored deviceId" + vo.getDeviceId()); + if (vo.getPhoneNumber().equalsIgnoreCase(phone)) { + deviceId = vo.getDeviceId(); + break; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return deviceId; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/contact_details/ContactDetailsFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/contact_details/ContactDetailsFragment.java new file mode 100644 index 000000000..414fd2498 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/contact_details/ContactDetailsFragment.java @@ -0,0 +1,285 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.contact_details; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.Spinner; + +import com.google.gson.Gson; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.response.CountryData; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.adapters.CountryAdapter; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.RetrofitErrorUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingAPIClient; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingApiConstants; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.cash_deposit.CashDepositFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.common.PhoneUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AddressVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.SignUpResponseVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.storage.SharedPreferenceUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.SellingConstants; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 03-Apr-18. + */ + +public class ContactDetailsFragment extends SellingBaseFragment implements View.OnClickListener { + + + private View rootView; + private Button button_continue; + private EditText edit_mobile, edit_email, edit_confirm_email, edit_password; + private final String TAG = "ContactDetailsFragment"; + private CountryData countryData; + private Spinner spinner_country; + private ProgressBar progressBar; + private String mCountryCode = ""; + private RelativeLayout layout_password; + private boolean isLoggedIn; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_contact_details, container, false); + init(); + setListeners(); + setTopbar(); + addCountryCodeList(); + handleArgs(); + + return rootView; + } else + return rootView; + } + + + private void init() { + + edit_mobile = (EditText) rootView.findViewById(R.id.edit_mobile); + edit_email = (EditText) rootView.findViewById(R.id.edit_email); + edit_confirm_email = (EditText) rootView.findViewById(R.id.edit_confirm_email); + edit_password = (EditText) rootView.findViewById(R.id.edit_password); + spinner_country = (Spinner) rootView.findViewById(R.id.spinner_country); + button_continue = (Button) rootView.findViewById(R.id.button_continue); + progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); + layout_password = (RelativeLayout) rootView.findViewById(R.id.layout_password); + } + + private void setListeners() { + button_continue.setOnClickListener(this); + spinner_country.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView adapterView, View view, int i, long l) { + mCountryCode = countryData.countries.get(i).code; + } + + @Override + public void onNothingSelected(AdapterView adapterView) { + + } + }); + + } + + private void setTopbar() { + + ((SellingBaseActivity) mContext).setTopbarTitle( + mContext.getString(R.string.title_contact_details)); + } + + private void addCountryCodeList() { + String json; + try { + InputStream is = getActivity().getAssets().open("countries.json"); + int size = is.available(); + byte[] buffer = new byte[size]; + is.read(buffer); + is.close(); + json = new String(buffer, "UTF-8"); + } catch (IOException ex) { + ex.printStackTrace(); + return; + } + + countryData = new Gson().fromJson(json, CountryData.class); + + List stringList = new ArrayList<>(); + + for (CountryData.CountriesBean bean : countryData.countries) { + stringList.add(bean.name + " (" + bean.code + ")"); + } + CountryAdapter customAdapter = new CountryAdapter(getActivity(), R.layout.spinner_row_country, countryData.countries); + customAdapter.setDropDownViewResource(R.layout.spinner_row_country); + spinner_country.setAdapter(customAdapter); + } + + private void handleArgs() { + if (!TextUtils.isEmpty(SharedPreferenceUtil.getString(SellingConstants.PREF_TOKEN_ID, ""))) { + layout_password.setVisibility(View.GONE); + spinner_country.setVisibility(View.GONE); + isLoggedIn = true; + edit_mobile.setEnabled(false); + spinner_country.setEnabled(false); + edit_mobile.setText(SharedPreferenceUtil.getString(SellingConstants.PREF_LOGGED_IN_PHONE, "")); + String email=SharedPreferenceUtil.getString(SellingConstants.PREF_LOGGED_IN_EMAIL, ""); + edit_email.setText(email); + Log.e("Email------",email); + + } + } + + private boolean checkDetails() { + String email; + email = edit_email.getText().toString().trim(); + + if (email.isEmpty()) { + showToast(getString(R.string.enter_email)); + return false; + } else if (!isValidEmail(email)) { + showToast(getString(R.string.enter_valid_email)); + return false; + } + return true; + } + + private boolean isValidDetails() { + String email, confirmEmail; + email = edit_email.getText().toString().trim(); + confirmEmail = edit_confirm_email.getText().toString().trim(); + + if (edit_mobile.getText().toString().trim().isEmpty()) { + showToast(getString(R.string.enter_mo_no)); + return false; + } else if (mCountryCode.isEmpty()) { + showToast(getString(R.string.enter_country_code)); + return false; + } else if (email.isEmpty()) { + showToast(getString(R.string.enter_email)); + return false; + } else if (!isValidEmail(email)) { + showToast(getString(R.string.enter_valid_email)); + return false; + } else if (confirmEmail.isEmpty()) { + showToast(getString(R.string.enter_confirm_email)); + return false; + } else if (!isValidEmail(confirmEmail)) { + showToast(getString(R.string.enter_valid_confirm_email)); + return false; + } else if (!email.equalsIgnoreCase(confirmEmail)) { + showToast(getString(R.string.email_not_matched)); + return false; + } else if (edit_password.getText().toString().trim().isEmpty()) { + showToast(getString(R.string.enter_pass)); + return false; + } + return true; + } + + private void registerUser() { + if (NetworkUtil.isOnline(mContext)) { + progressBar.setVisibility(View.VISIBLE); + HashMap signUpHashMap = new HashMap(); + signUpHashMap.put(SellingApiConstants.KEY_PHONE, mCountryCode + edit_mobile.getText().toString().trim()); + signUpHashMap.put(SellingApiConstants.KEY_EMAIL, edit_email.getText().toString().trim()); + signUpHashMap.put(SellingApiConstants.KEY_PASSWORD, edit_password.getText().toString().trim()); + + SellingAPIClient.createService(interceptor, mContext) + .signUp(signUpHashMap) + .enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + progressBar.setVisibility(View.GONE); + if (response.body() != null && response.code() == 200 || + response.body() != null && response.code() == 201) { + SignUpResponseVo signUpVo = response.body(); + PhoneUtil.addPhone(signUpVo.getPhone(), ""); + ((SellingBaseActivity) mContext).popBackDirect(); + } else { + String error = RetrofitErrorUtil.parseError(response); + if (error != null && !error.isEmpty()) + showToast(error); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + progressBar.setVisibility(View.GONE); + showToast(t.getMessage()); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + @Override + public void onResume() { + super.onResume(); + setTopbar(); + } + + @Override + public void onClick(View view) { + + switch (view.getId()) { + case R.id.button_continue: + + if (isLoggedIn) { + if (checkDetails()) { + + Bundle bundle = new Bundle(); + bundle.putSerializable(SellingConstants.ARGUMENT_ADDRESS_DETAILS_VO, getSellingDetails()); + CashDepositFragment fragment = new CashDepositFragment(); + fragment.setArguments(bundle); + + ((SellingBaseActivity) mContext).replaceFragment(fragment, true, true); + } + } else { + if (isValidDetails()) + registerUser(); + } + + break; + } + } + + //if user is logged in + private AddressVo getSellingDetails() { + AddressVo detailsVo = new AddressVo(); + detailsVo.setEmail(edit_email.getText().toString().trim()); + detailsVo.setPhone(edit_mobile.getText().toString().trim()); + detailsVo.setPhoneCode(mCountryCode); + + return detailsVo; + } +} \ No newline at end of file diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/create_pass/CreatePasswordFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/create_pass/CreatePasswordFragment.java new file mode 100644 index 000000000..ad032a065 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/create_pass/CreatePasswordFragment.java @@ -0,0 +1,81 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.create_pass; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; + +/** + * Created on 06-Apr-18. + */ + +public class CreatePasswordFragment extends SellingBaseFragment { + private View rootView; + private ProgressBar progressBar; + private EditText edit_mobile, edit_new_password, edit_confirm_new_password; + private Button button_set_password; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_create_password, container, false); + init(); + setTopbar(); + return rootView; + } else + return rootView; + } + + private void init() { + edit_mobile = (EditText) rootView.findViewById(R.id.edit_mobile); + edit_new_password = (EditText) rootView.findViewById(R.id.edit_new_password); + edit_confirm_new_password = (EditText) rootView.findViewById(R.id.edit_confirm_new_password); + progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); + button_set_password = (Button) rootView.findViewById(R.id.button_set_password); + } + + private void setTopbar() { + + ((SellingBaseActivity) mContext).setTopbarTitle( + getString(R.string.title_create_pass)); + } + + private boolean isValidDetails() { + String pass, confirmPass; + pass = edit_new_password.getText().toString().trim(); + confirmPass = edit_confirm_new_password.getText().toString().trim(); + + if (edit_mobile.getText().toString().trim().isEmpty()) { + showToast(getString(R.string.enter_mo_no)); + return false; + } else if (pass.isEmpty()) { + showToast(getString(R.string.enter_new_pass)); + edit_new_password.requestFocus(); + return false; + } else if (confirmPass.isEmpty()) { + showToast(getString(R.string.enter_confirm_pass)); + edit_confirm_new_password.requestFocus(); + return false; + } else if (!pass.equalsIgnoreCase(confirmPass)) { + showToast(getString(R.string.pass_not_matched)); + return false; + } + return true; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/instruction/InstructionFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/instruction/InstructionFragment.java new file mode 100644 index 000000000..8ad030ee4 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/instruction/InstructionFragment.java @@ -0,0 +1,142 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.instruction; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; + +/** + * Created on 11-Apr-18. + */ + +public class InstructionFragment extends SellingBaseFragment implements View.OnClickListener { + + private View rootView; + private EditText edit_current_rate; + private Button button_edit_rate; + private TextView text_cancle, text_save, text_edit_current_rate, text_bank_name, + text_holder_name, text_acc_number, text_piv_avail, + text_advanced_option; + private LinearLayout layout_cancel; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_instruction, container, false); + init(); + setListeners(); + setTopbar(); + return rootView; + } else + return rootView; + } + + private void init() { + + text_cancle = (TextView) rootView.findViewById(R.id.text_cancle); + text_bank_name = (TextView) rootView.findViewById(R.id.text_bank_name); + text_holder_name = (TextView) rootView.findViewById(R.id.text_holder_name); + text_acc_number = (TextView) rootView.findViewById(R.id.text_acc_number); + text_piv_avail = (TextView) rootView.findViewById(R.id.text_piv_avail); + edit_current_rate = (EditText) rootView.findViewById(R.id.edit_current_rate); + text_advanced_option = (TextView) rootView.findViewById(R.id.text_advanced_option); + + button_edit_rate = (Button) rootView.findViewById(R.id.button_edit_rate); + + text_cancle = (TextView) rootView.findViewById(R.id.text_cancle); + text_save = (TextView) rootView.findViewById(R.id.text_save); + text_edit_current_rate = (TextView) rootView.findViewById(R.id.text_edit_current_rate); + layout_cancel = (LinearLayout) rootView.findViewById(R.id.layout_cancel); + } + + private void setListeners() { + button_edit_rate.setOnClickListener(this); + text_cancle.setOnClickListener(this); + text_save.setOnClickListener(this); + text_edit_current_rate.setOnClickListener(this); + text_advanced_option.setOnClickListener(this); + } + + private void setTopbar() { + ((SellingBaseActivity) mContext).setTopbarTitle( + mContext.getString(R.string.title_selling)); + } + + @Override + public void onClick(View view) { + + switch (view.getId()) { + case R.id.button_edit_rate: + + break; + case R.id.text_advanced_option: + showOptionsDialog(); + break; + + case R.id.text_save: + edit_current_rate.setEnabled(false); + layout_cancel.setVisibility(View.GONE); + text_edit_current_rate.setVisibility(View.VISIBLE); + break; + case R.id.text_cancle: + layout_cancel.setVisibility(View.GONE); + text_edit_current_rate.setVisibility(View.VISIBLE); + break; + case R.id.text_edit_current_rate: + edit_current_rate.setEnabled(true); + layout_cancel.setVisibility(View.VISIBLE); + text_edit_current_rate.setVisibility(View.GONE); + break; + } + } + + private void showOptionsDialog() { + final Dialog dialog = new Dialog(mContext); + dialog.setContentView(R.layout.dialog_selling_options); + + + EditText edit_min_payment, edit_max_payment; + edit_min_payment = (EditText) dialog.findViewById(R.id.edit_min_payment); + edit_max_payment = (EditText) dialog.findViewById(R.id.edit_max_payment); + + Button button_cancle, button_save; + + button_cancle = (Button) dialog.findViewById(R.id.button_cancle); + button_save = (Button) dialog.findViewById(R.id.button_save); + button_cancle.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dialog.dismiss(); + } + }); + button_save.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dialog.dismiss(); + } + }); + dialog.show(); + } + +} + + + diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AddressListRespVo.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AddressListRespVo.java new file mode 100644 index 000000000..569af88c3 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AddressListRespVo.java @@ -0,0 +1,170 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +import com.google.gson.annotations.SerializedName; + +/** + * Created on 06-Apr-18. + */ + +public class AddressListRespVo { + + + /** + * publicBalance : 0E-8 + * secondaryMarket : None + * verified : false + * sellCrypto : DASH + * primaryMarket : None + * currentPrice : 10.00 + * buyCurrency : USD + * fundingAddress : (Not Available - Needs Verification) + * sellerFee : None + * published : false + * onHold : 0E-8 + * balance : 0E-8 + * id : 863 + * dynamicPrice : false + */ + + @SerializedName("publicBalance") + private String publicBalance; + @SerializedName("secondaryMarket") + private String secondaryMarket; + @SerializedName("verified") + private boolean verified; + @SerializedName("sellCrypto") + private String sellCrypto; + @SerializedName("primaryMarket") + private String primaryMarket; + @SerializedName("currentPrice") + private String currentPrice; + @SerializedName("buyCurrency") + private String buyCurrency; + @SerializedName("fundingAddress") + private String fundingAddress; + @SerializedName("sellerFee") + private String sellerFee; + @SerializedName("published") + private boolean published; + @SerializedName("onHold") + private String onHold; + @SerializedName("balance") + private String balance; + @SerializedName("id") + private int id; + @SerializedName("dynamicPrice") + private boolean dynamicPrice; + + public String getPublicBalance() { + return publicBalance; + } + + public void setPublicBalance(String publicBalance) { + this.publicBalance = publicBalance; + } + + public String getSecondaryMarket() { + return secondaryMarket; + } + + public void setSecondaryMarket(String secondaryMarket) { + this.secondaryMarket = secondaryMarket; + } + + public boolean isVerified() { + return verified; + } + + public void setVerified(boolean verified) { + this.verified = verified; + } + + public String getSellCrypto() { + return sellCrypto; + } + + public void setSellCrypto(String sellCrypto) { + this.sellCrypto = sellCrypto; + } + + public String getPrimaryMarket() { + return primaryMarket; + } + + public void setPrimaryMarket(String primaryMarket) { + this.primaryMarket = primaryMarket; + } + + public String getCurrentPrice() { + return currentPrice; + } + + public void setCurrentPrice(String currentPrice) { + this.currentPrice = currentPrice; + } + + public String getBuyCurrency() { + return buyCurrency; + } + + public void setBuyCurrency(String buyCurrency) { + this.buyCurrency = buyCurrency; + } + + public String getFundingAddress() { + return fundingAddress; + } + + public void setFundingAddress(String fundingAddress) { + this.fundingAddress = fundingAddress; + } + + public String getSellerFee() { + return sellerFee; + } + + public void setSellerFee(String sellerFee) { + this.sellerFee = sellerFee; + } + + public boolean isPublished() { + return published; + } + + public void setPublished(boolean published) { + this.published = published; + } + + public String getOnHold() { + return onHold; + } + + public void setOnHold(String onHold) { + this.onHold = onHold; + } + + public String getBalance() { + return balance; + } + + public void setBalance(String balance) { + this.balance = balance; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public boolean isDynamicPrice() { + return dynamicPrice; + } + + public void setDynamicPrice(boolean dynamicPrice) { + this.dynamicPrice = dynamicPrice; + } +} + diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AddressVo.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AddressVo.java new file mode 100644 index 000000000..a5f76e0ce --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AddressVo.java @@ -0,0 +1,281 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +import java.io.Serializable; + +/** + * Created on 04-Apr-18. + */ + +public class AddressVo implements Serializable { + + //for create add + private String number; + private String number2; + private String phone; + private String email; + private String phoneCode; + private String bankBusiness; + private String sellerFee; + private String name; + + //for response add + private String sellCrypto; + + private String account_id; + + private String currentPrice; + + private String totalReceived; + + private String buyCurrency; + + private String id; + + private String fee; + + private String minPayment; + + private boolean dynamicPrice; + + private String createdIp; + + private String secondaryMarket; + + private String verified; + + private String maxPayment; + + private String publicBalance; + + private boolean userEnabled; + + private String published; + + private String success; + + private String primaryMarket; + + private String onHold; + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + public String getNumber2() { + return number2; + } + + public void setNumber2(String number2) { + this.number2 = number2; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhoneCode() { + return phoneCode; + } + + public void setPhoneCode(String phoneCode) { + this.phoneCode = phoneCode; + } + + public String getBankBusiness() { + return bankBusiness; + } + + public void setBankBusiness(String bankBusiness) { + this.bankBusiness = bankBusiness; + } + + public String getSellerFee() { + return sellerFee; + } + + public void setSellerFee(String sellerFee) { + this.sellerFee = sellerFee; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + + public String getSellCrypto() { + return sellCrypto; + } + + public void setSellCrypto(String sellCrypto) { + this.sellCrypto = sellCrypto; + } + + public String getAccount_id() { + return account_id; + } + + public void setAccount_id(String account_id) { + this.account_id = account_id; + } + + public String getCurrentPrice() { + return currentPrice; + } + + public void setCurrentPrice(String currentPrice) { + this.currentPrice = currentPrice; + } + + public String getTotalReceived() { + return totalReceived; + } + + public void setTotalReceived(String totalReceived) { + this.totalReceived = totalReceived; + } + + public String getBuyCurrency() { + return buyCurrency; + } + + public void setBuyCurrency(String buyCurrency) { + this.buyCurrency = buyCurrency; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getFee() { + return fee; + } + + public void setFee(String fee) { + this.fee = fee; + } + + public String getMinPayment() { + return minPayment; + } + + public void setMinPayment(String minPayment) { + this.minPayment = minPayment; + } + + public boolean getDynamicPrice() { + return dynamicPrice; + } + + public void setDynamicPrice(boolean dynamicPrice) { + this.dynamicPrice = dynamicPrice; + } + + public String getCreatedIp() { + return createdIp; + } + + public void setCreatedIp(String createdIp) { + this.createdIp = createdIp; + } + + public String getSecondaryMarket() { + return secondaryMarket; + } + + public void setSecondaryMarket(String secondaryMarket) { + this.secondaryMarket = secondaryMarket; + } + + public String getVerified() { + return verified; + } + + public void setVerified(String verified) { + this.verified = verified; + } + + public String getMaxPayment() { + return maxPayment; + } + + public void setMaxPayment(String maxPayment) { + this.maxPayment = maxPayment; + } + + public String getPublicBalance() { + return publicBalance; + } + + public void setPublicBalance(String publicBalance) { + this.publicBalance = publicBalance; + } + + public boolean getUserEnabled() { + return userEnabled; + } + + public void setUserEnabled(boolean userEnabled) { + this.userEnabled = userEnabled; + } + + public String getPublished() { + return published; + } + + public void setPublished(String published) { + this.published = published; + } + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public String getPrimaryMarket() { + return primaryMarket; + } + + public void setPrimaryMarket(String primaryMarket) { + this.primaryMarket = primaryMarket; + } + + public String getOnHold() { + return onHold; + } + + public void setOnHold(String onHold) { + this.onHold = onHold; + } + + @Override + public String toString() { + return "ClassPojo [sellCrypto = " + sellCrypto + ", account_id = " + account_id + ", currentPrice = " + currentPrice + ", totalReceived = " + totalReceived + ", buyCurrency = " + buyCurrency + ", id = " + id + ", fee = " + fee + ", minPayment = " + minPayment + ", dynamicPrice = " + dynamicPrice + ", createdIp = " + createdIp + ", secondaryMarket = " + secondaryMarket + ", verified = " + verified + ", maxPayment = " + maxPayment + ", publicBalance = " + publicBalance + ", userEnabled = " + userEnabled + ", published = " + published + ", success = " + success + ", primaryMarket = " + primaryMarket + ", onHold = " + onHold + "]"; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AuthVo.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AuthVo.java new file mode 100644 index 000000000..4d27d2e40 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/AuthVo.java @@ -0,0 +1,84 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +/** + * Created on 04-Apr-18. + */ + +public class AuthVo { + + private String createdOn; + + private String phone; + + private String email; + + private String token; + + private String authSource; + + private String tokenExpiresAt; + + private String accessedOn; + + public String getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(String createdOn) { + this.createdOn = createdOn; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getAuthSource() { + return authSource; + } + + public void setAuthSource(String authSource) { + this.authSource = authSource; + } + + public String getTokenExpiresAt() { + return tokenExpiresAt; + } + + public void setTokenExpiresAt(String tokenExpiresAt) { + this.tokenExpiresAt = tokenExpiresAt; + } + + public String getAccessedOn() { + return accessedOn; + } + + public void setAccessedOn(String accessedOn) { + this.accessedOn = accessedOn; + } + + @Override + public String toString() { + return "ClassPojo [createdOn = " + createdOn + ", phone = " + phone + ", email = " + email + ", token = " + token + ", authSource = " + authSource + ", tokenExpiresAt = " + tokenExpiresAt + ", accessedOn = " + accessedOn + "]"; + } +} + diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/CreateDeviceVo.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/CreateDeviceVo.java new file mode 100644 index 000000000..41af52ed9 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/CreateDeviceVo.java @@ -0,0 +1,42 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +/** + * Created on 04-Apr-18. + */ + +public class CreateDeviceVo { + /** + * id : 4 + * name : New iPhone + * createdOn : 2015-01-20T17:13:34.154Z + */ + + private int id; + private String name; + private String createdOn; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(String createdOn) { + this.createdOn = createdOn; + } +} + diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/GetReceivingOptionsResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/GetReceivingOptionsResp.java new file mode 100644 index 000000000..39b8c7c64 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/GetReceivingOptionsResp.java @@ -0,0 +1,110 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +/** + * Created on 04-Apr-18. + */ + +public class GetReceivingOptionsResp { + + /** + * id : 19 + * name : Axis Bank + * url : https://www.axisbank.com/ + * logo : https://woc.reference.genitrust.com/static/logos/logo_in_Axis%20Bank.png + * logoHq : https://woc.reference.genitrust.com/static/logos/logo_in_Axis%20Bank%402x.png + * icon : https://woc.reference.genitrust.com/static/logos/icon_in_Axis%20Bank.png + * iconHq : https://woc.reference.genitrust.com/static/logos/icon_in_Axis%20Bank%402x.png + * country : in + * payFields : {"payFields":[{"name":"birthCountry","label":"Country of Birth","parse":"","displaySort":2,"paymentDestination_id":17,"id":7},{"name":"pickupState","label":"Pick-up State","parse":"","displaySort":0.5,"paymentDestination_id":17,"id":6},{"name":"lastName","label":"Last Name","parse":"","displaySort":1,"paymentDestination_id":17,"id":5},{"name":"firstName","label":"First Name","parse":"","displaySort":0,"paymentDestination_id":17,"id":4}],"confirmFields":[{"name":"receiveCode","label":"Receive Code (Confirm)","parse":"","displaySort":0,"paymentDestination_id":17,"id":3}],"trigger":"Check here if this is a biller account (Business)","dynamicFields":[{"name":"accountNumber","label":"Customer Account #","parse":"","displaySort":2,"paymentDestination_id":17,"id":4},{"name":"receiveCode","label":"Receive Code","parse":"","displaySort":1.5,"paymentDestination_id":17,"id":3},{"name":"businessCity","label":"Business City/State","parse":"","displaySort":1,"paymentDestination_id":17,"id":2},{"name":"businessName","label":"Business Name","parse":"","displaySort":0,"paymentDestination_id":17,"id":1}]} + */ + + public int id; + public String name; + public String url; + public String logo; + public String logoHq; + public String icon; + public String iconHq; + public String country; + public pivx.org.pivxwallet.wallofcoins.response.GetReceivingOptionsResp.PayFieldsBeanX payFields; + + + public static class PayFieldsBeanX { + /** + * payFields : [{"name":"birthCountry","label":"Country of Birth","parse":"","displaySort":2,"paymentDestination_id":17,"id":7},{"name":"pickupState","label":"Pick-up State","parse":"","displaySort":0.5,"paymentDestination_id":17,"id":6},{"name":"lastName","label":"Last Name","parse":"","displaySort":1,"paymentDestination_id":17,"id":5},{"name":"firstName","label":"First Name","parse":"","displaySort":0,"paymentDestination_id":17,"id":4}] + * confirmFields : [{"name":"receiveCode","label":"Receive Code (Confirm)","parse":"","displaySort":0,"paymentDestination_id":17,"id":3}] + * trigger : Check here if this is a biller account (Business) + * dynamicFields : [{"name":"accountNumber","label":"Customer Account #","parse":"","displaySort":2,"paymentDestination_id":17,"id":4},{"name":"receiveCode","label":"Receive Code","parse":"","displaySort":1.5,"paymentDestination_id":17,"id":3},{"name":"businessCity","label":"Business City/State","parse":"","displaySort":1,"paymentDestination_id":17,"id":2},{"name":"businessName","label":"Business Name","parse":"","displaySort":0,"paymentDestination_id":17,"id":1}] + */ + + + public String trigger; + @SerializedName("payFields") + public List payFieldsX; + public List confirmFields; + public List dynamicFields; + public Boolean payFieldsB; + + public static class PayFieldsBean { + /** + * name : birthCountry + * label : Country of Birth + * parse : + * displaySort : 2 + * paymentDestination_id : 17 + * id : 7 + */ + + @SerializedName("name") + public String nameX; + public String label; + public String parse; + public float displaySort; + public int paymentDestination_id; + @SerializedName("id") + public int idX; + + + @Override + public String toString() { + return "PayFieldsBean{" + + "nameX='" + nameX + '\'' + + ", label='" + label + '\'' + + ", parse='" + parse + '\'' + + ", displaySort=" + displaySort + + ", paymentDestination_id=" + paymentDestination_id + + ", idX=" + idX + + '}'; + } + } + + @Override + public String toString() { + return "PayFieldsBeanX{" + + "trigger='" + trigger + '\'' + + ", payFieldsX=" + payFieldsX + + ", confirmFields=" + confirmFields + + ", dynamicFields=" + dynamicFields + + '}'; + } + } + + @Override + public String toString() { + return "GetReceivingOptionsResp{" + + "id=" + id + + ", name='" + name + '\'' + + ", url='" + url + '\'' + + ", logo='" + logo + '\'' + + ", logoHq='" + logoHq + '\'' + + ", icon='" + icon + '\'' + + ", iconHq='" + iconHq + '\'' + + ", country='" + country + '\'' + + ", payFields=" + payFields + + '}'; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/MarketsVo.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/MarketsVo.java new file mode 100644 index 000000000..7eaa89b2d --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/MarketsVo.java @@ -0,0 +1,113 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +/** + * Created on 04-Apr-18. + */ + +public class MarketsVo { + + private String id; + + private String price; + + private String domain; + + private String lastUpdated; + + private String priceUnits; + + private String label; + + private String fiat; + + private String crypto; + + private String url; + + private String online; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getPrice() { + return price; + } + + public void setPrice(String price) { + this.price = price; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getLastUpdated() { + return lastUpdated; + } + + public void setLastUpdated(String lastUpdated) { + this.lastUpdated = lastUpdated; + } + + public String getPriceUnits() { + return priceUnits; + } + + public void setPriceUnits(String priceUnits) { + this.priceUnits = priceUnits; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getFiat() { + return fiat; + } + + public void setFiat(String fiat) { + this.fiat = fiat; + } + + public String getCrypto() { + return crypto; + } + + public void setCrypto(String crypto) { + this.crypto = crypto; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getOnline() { + return online; + } + + public void setOnline(String online) { + this.online = online; + } + + @Override + public String toString() { + return "ClassPojo [id = " + id + ", price = " + price + ", domain = " + domain + ", lastUpdated = " + lastUpdated + ", priceUnits = " + priceUnits + ", label = " + label + ", fiat = " + fiat + ", crypto = " + crypto + ", url = " + url + ", online = " + online + "]"; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/PhoneListVO.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/PhoneListVO.java new file mode 100644 index 000000000..44769817b --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/PhoneListVO.java @@ -0,0 +1,32 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +import java.io.Serializable; + +/** + * Created on 12-Mar-18. + */ + +public class PhoneListVO implements Serializable { + + private String phoneNumber = ""; + private String deviceId = ""; + private String emailId=""; + + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/SendVerificationRespVo.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/SendVerificationRespVo.java new file mode 100644 index 000000000..59fb170c6 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/SendVerificationRespVo.java @@ -0,0 +1,12 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +public class SendVerificationRespVo { + + /** + * __CASH_CODE : LWHUG + * success : true + */ + + public String __CASH_CODE; + public boolean success; +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/SignUpResponseVo.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/SignUpResponseVo.java new file mode 100644 index 000000000..5d336a0db --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/SignUpResponseVo.java @@ -0,0 +1,73 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +/** + * Created on 04-Apr-18. + */ + +public class SignUpResponseVo { + + private String createdOn; + + private String phone; + + private String email; + + private String phoneVerified; + + private String accessedOn; + + private String lastVerified; + + public String getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(String createdOn) { + this.createdOn = createdOn; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhoneVerified() { + return phoneVerified; + } + + public void setPhoneVerified(String phoneVerified) { + this.phoneVerified = phoneVerified; + } + + public String getAccessedOn() { + return accessedOn; + } + + public void setAccessedOn(String accessedOn) { + this.accessedOn = accessedOn; + } + + public String getLastVerified() { + return lastVerified; + } + + public void setLastVerified(String lastVerified) { + this.lastVerified = lastVerified; + } + + @Override + public String toString() { + return "ClassPojo [createdOn = " + createdOn + ", phone = " + phone + ", email = " + email + ", phoneVerified = " + phoneVerified + ", accessedOn = " + accessedOn + ", lastVerified = " + lastVerified + "]"; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/VerifyAdResp.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/VerifyAdResp.java new file mode 100644 index 000000000..5e64fb798 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/models/VerifyAdResp.java @@ -0,0 +1,13 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.models; + +public class VerifyAdResp { + + + /** + * fundingAddress : myQnXbaTi7HYj98T7ozYn3gK2Prv7uJvTj + * success : true + */ + + public String fundingAddress; + public boolean success; +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/phone_list/PhoneListFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/phone_list/PhoneListFragment.java new file mode 100644 index 000000000..284099ad6 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/phone_list/PhoneListFragment.java @@ -0,0 +1,367 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.phone_list; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.adapters.PhoneListAdapter; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.RetrofitErrorUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingAPIClient; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingApiConstants; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.common.PhoneUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.contact_details.ContactDetailsFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AuthVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.CreateDeviceVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.PhoneListVO; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.storage.SharedPreferenceUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.SellingConstants; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 19-Mar-18. + */ + +public class PhoneListFragment extends SellingBaseFragment implements View.OnClickListener { + + private final String TAG = "PhoneListFragment"; + private View rootView; + private RecyclerView recycler_phone_list; + private Button button_sign_up, button_existing_sign_in; + private PhoneListFragment fragment; + private TextView text_no_data; + private ProgressBar progressBar; + private String mPassword = "", mSelectedPhone = ""; + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + rootView = inflater.inflate(R.layout.fragment_selling_phone_list, container, false); + init(); + setListeners(); + setPhoneList(); + return rootView; + } + + private void init() { + fragment = this; + recycler_phone_list = (RecyclerView) rootView.findViewById(R.id.recycler_phone_list); + button_sign_up = (Button) rootView.findViewById(R.id.button_sign_up); + button_existing_sign_in = (Button) rootView.findViewById(R.id.button_existing_sign_in); + text_no_data = (TextView) rootView.findViewById(R.id.text_no_data); + recycler_phone_list.setLayoutManager(new LinearLayoutManager(mContext)); + progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); + } + + private void setListeners() { + button_existing_sign_in.setOnClickListener(this); + button_sign_up.setOnClickListener(this); + } + + private void setPhoneList() { + + ArrayList phoneListVOS = PhoneUtil.getStoredPhoneList(); + + HashSet hashSet = new HashSet<>(); + hashSet.addAll(phoneListVOS); + phoneListVOS.clear(); + phoneListVOS.addAll(hashSet); + + if (phoneListVOS != null & phoneListVOS.size() > 0) { + recycler_phone_list.setAdapter(new PhoneListAdapter(mContext, phoneListVOS, fragment)); + text_no_data.setVisibility(View.GONE); + } else + text_no_data.setVisibility(View.VISIBLE); + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.button_existing_sign_in: + /* Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.SCREEN_TYPE, "PhoneListFragment"); + EmailAndPhoneFragment phoneFragment = new EmailAndPhoneFragment(); + phoneFragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(phoneFragment, true, true);*/ + break; + case R.id.button_sign_up: + ((SellingBaseActivity) mContext).replaceFragment(new ContactDetailsFragment(), + true, true); + break; + } + } + + public void onItemClick(String phone) { + mSelectedPhone = phone; + checkAuth(); + } + + /** + * Method for check authentication type + */ + private void checkAuth() { + if (NetworkUtil.isOnline(mContext)) { + progressBar.setVisibility(View.VISIBLE); + + SellingAPIClient.createService(interceptor, mContext).getAuthToken(mSelectedPhone, + SellingApiConstants.WALLOFCOINS_PUBLISHER_ID).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + progressBar.setVisibility(View.GONE); + if (response.code() == 200) { + if (response.body() != null) { + + /* if (response.body().getAuthSource().equals("password")) {//from wesite + showUserPasswordAuthenticationDialog(); + }*/ + showUserPasswordAuthenticationDialog(); + } + } else { + String error = RetrofitErrorUtil.parseError(response); + if (error != null && !error.isEmpty()) + showToast(error); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + progressBar.setVisibility(View.GONE); + showToast(t.getMessage()); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } + + /** + * User authentication custom dialog for authenticate user using password + */ + private void showUserPasswordAuthenticationDialog() { + + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View dialogView = inflater.inflate(R.layout.layout_authenticate_password_wallet_dialog, null); + dialogBuilder.setView(dialogView); + + final EditText edtPassword = (EditText) dialogView.findViewById(R.id.edt_woc_authenticaion_password); + TextView txtTitle = (TextView) dialogView.findViewById(R.id.txt_existing_user_dialog_message); + Button btnLogin = (Button) dialogView.findViewById(R.id.btnLogin); + Button btnForgotPassword = (Button) dialogView.findViewById(R.id.btnForgotPassword); + + txtTitle.setMovementMethod(LinkMovementMethod.getInstance()); + + final AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.show(); + + ImageView imgClose = (ImageView) dialogView.findViewById(R.id.imgClose); + + imgClose.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + alertDialog.dismiss(); + } + }); + + btnForgotPassword.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + goToUrl(WOCConstants.KEY_FORGOT_PASSWORD_URL); + } + }); + + btnLogin.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mPassword = edtPassword.getText().toString().trim(); + if (mPassword.length() > 0) { + authorize(mPassword); + alertDialog.dismiss(); + } else { + showToast(mContext.getString(R.string.password_alert)); + } + } + }); + + } + + /** + * Authorized user using password or device code + * + * @param password + */ + private void authorize(final String password) { + if (NetworkUtil.isOnline(mContext)) { + HashMap hashMap = new HashMap(); + + if (!TextUtils.isEmpty(password)) { + hashMap.put(SellingApiConstants.KEY_PASSWORD, password); + } else { + hashMap.put(SellingApiConstants.KEY_DEVICECODE, getDeviceCode(mContext)); + } + if (!TextUtils.isEmpty(SharedPreferenceUtil.getString(SellingConstants.PREF_DEVICE_ID, ""))) { + hashMap.put(WOCConstants.KEY_DEVICEID, SharedPreferenceUtil.getString(SellingConstants.PREF_DEVICE_ID, "")); + } + hashMap.put(SellingApiConstants.KEY_PUBLISHER_ID, SellingApiConstants.WALLOFCOINS_PUBLISHER_ID); + + progressBar.setVisibility(View.VISIBLE); + SellingAPIClient.createService(interceptor, mContext).authorize(mSelectedPhone, hashMap). + enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + progressBar.setVisibility(View.GONE); + + if (response.body() == null) { + try { + if (!TextUtils.isEmpty(password)) { + showAlertPasswordDialog(); + } else { + createDevice(); + } + } catch (Exception e) { + e.printStackTrace(); + showToast(mContext.getString(R.string.try_again)); + } + return; + } + + + if (!TextUtils.isEmpty(response.body().getToken())) { + + SharedPreferenceUtil.putValue(SellingConstants.PREF_TOKEN_ID, response.body().getToken()); + SharedPreferenceUtil.putValue(SellingConstants.PREF_LOGGED_IN_PHONE, mSelectedPhone); + + } + if (response.body().getEmail() != null) + SharedPreferenceUtil.putValue(SellingConstants.PREF_LOGGED_IN_EMAIL, response.body().getEmail()); + if (!TextUtils.isEmpty(password) && + TextUtils.isEmpty(SharedPreferenceUtil.getString(SellingConstants.PREF_DEVICE_ID, ""))) { + getDevice(); + } else { + ((SellingBaseActivity) mContext).popBackDirect(); + } + + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(t.getMessage()); + progressBar.setVisibility(View.GONE); + } + }); + + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } + + /** + * Get Devices for Register user with password + */ + private void getDevice() { + progressBar.setVisibility(View.VISIBLE); + SellingAPIClient.createService(interceptor, mContext).getDevice().enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + progressBar.setVisibility(View.GONE); + if (response.code() == 200 && response.body() != null) { + + List deviceList = response.body(); + if (deviceList.size() > 0) { + SharedPreferenceUtil.putValue(SellingConstants.PREF_DEVICE_ID, deviceList.get(deviceList.size() - 1).getId() + ""); + authorize(""); + } else { + createDevice(); + } + } else { + String error = RetrofitErrorUtil.parseError(response); + if (error != null && !error.isEmpty()) + showToast(error); + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + progressBar.setVisibility(View.GONE); + showToast(t.getMessage()); + } + }); + + } + + /** + * Method for register new device + */ + private void createDevice() { + final HashMap hashMap = new HashMap(); + hashMap.put(SellingApiConstants.KEY_DEVICE_NAME, SellingApiConstants.DEVICE_NAME); + hashMap.put(SellingApiConstants.KEY_CODE, getDeviceCode(mContext)); + hashMap.put(SellingApiConstants.KEY_PUBLISHER_ID, SellingApiConstants.WALLOFCOINS_PUBLISHER_ID); + progressBar.setVisibility(View.VISIBLE); + SellingAPIClient.createService(interceptor, mContext).createDevice(hashMap).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + progressBar.setVisibility(View.GONE); + if (null != response.body() && response.code() < 299) { + SharedPreferenceUtil.putValue(SellingConstants.PREF_DEVICE_ID, response.body().getId() + ""); + + authorize(""); + } else { + String error = RetrofitErrorUtil.parseError(response); + if (error != null && !error.isEmpty()) + showToast(error); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + progressBar.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + }); + } + + //this method remove animation when user want to clear whole back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } +} \ No newline at end of file diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/price/PriceFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/price/PriceFragment.java new file mode 100644 index 000000000..2066b2efb --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/price/PriceFragment.java @@ -0,0 +1,273 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.price; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatCheckBox; +import android.support.v7.widget.AppCompatSpinner; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.Toast; + +import java.util.ArrayList; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.advanced_options.AdvanceOptionsFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.RetrofitErrorUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingAPIClient; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AddressVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.MarketsVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.SellingConstants; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 04-Apr-18. + */ + +public class PriceFragment extends SellingBaseFragment implements View.OnClickListener { + + + private View rootView; + private Button button_continue; + private EditText edit_static_price, edit_min_payment, edit_max_payment, edit_seller_price; + private final String TAG = "PriceFragment"; + private ProgressBar progressBar; + private AddressVo addressVo; + private AppCompatSpinner spinner_primary_market, spinner_secondary_market; + private AppCompatCheckBox chekbox_dynamic_pricing; + private LinearLayout layout_static_price; + private RelativeLayout layout_dynamic_price; + private ArrayList marketsVoArrayList; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_price, container, false); + init(); + setListeners(); + setTopbar(); + handleArgs(); + return rootView; + } else + return rootView; + } + + private void init() { + + edit_static_price = (EditText) rootView.findViewById(R.id.edit_static_price); + edit_min_payment = (EditText) rootView.findViewById(R.id.edit_min_payment); + edit_max_payment = (EditText) rootView.findViewById(R.id.edit_max_payment); + edit_seller_price = (EditText) rootView.findViewById(R.id.edit_seller_price); + chekbox_dynamic_pricing = (AppCompatCheckBox) rootView.findViewById(R.id.chekbox_dynamic_pricing); + + spinner_primary_market = (AppCompatSpinner) rootView.findViewById(R.id.spinner_primary_market); + spinner_secondary_market = (AppCompatSpinner) rootView.findViewById(R.id.spinner_secondary_market); + + button_continue = (Button) rootView.findViewById(R.id.button_continue); + progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); + + layout_static_price = (LinearLayout) rootView.findViewById(R.id.layout_static_price); + layout_dynamic_price = (RelativeLayout) rootView.findViewById(R.id.layout_dynamic_price); + + marketsVoArrayList = new ArrayList<>(); + + } + + private void setListeners() { + button_continue.setOnClickListener(this); + chekbox_dynamic_pricing.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { + if (isChecked) { + if (marketsVoArrayList.size() == 0) + getMarkes(); + layout_static_price.setVisibility(View.GONE); + layout_dynamic_price.setVisibility(View.VISIBLE); + } else { + layout_dynamic_price.setVisibility(View.GONE); + layout_static_price.setVisibility(View.VISIBLE); + } + } + }); + } + + private void setTopbar() { + + ((SellingBaseActivity) mContext).setTopbarTitle( + mContext.getString(R.string.title_price)); + } + + private void handleArgs() { + + if (getArguments() != null) { + addressVo = (AddressVo) + getArguments().getSerializable(SellingConstants.ARGUMENT_ADDRESS_DETAILS_VO); + } + } + + @Override + public void onResume() { + super.onResume(); + setTopbar(); + } + + @Override + public void onClick(View view) { + + switch (view.getId()) { + case R.id.button_continue: + //if (chkBoxdynamicPricing.isChecked()) { + /*if (isValidDetails()) { + Bundle bundle = new Bundle(); + bundle.putSerializable(SellingConstants.ADDRESS_DETAILS_VO, getSellingDetails()); + VerifySellingDetailsFragment fragment = new VerifySellingDetailsFragment(); + fragment.setArguments(bundle); + + ((SellingBaseActivity) mContext).replaceFragment(fragment, true, true); + }*/ + // if (isValidDetails()) { + + if (isValid()) + { + Bundle bundle = new Bundle(); + bundle.putSerializable(SellingConstants.ARGUMENT_ADDRESS_DETAILS_VO, getSellingDetails()); + AdvanceOptionsFragment fragment = new AdvanceOptionsFragment(); + fragment.setArguments(bundle); + + ((SellingBaseActivity) mContext).replaceFragment(fragment, true, true); + } + + //} + + // } + + break; + } + } + private boolean isValid() + { + if (edit_static_price.getText().toString().trim().isEmpty()) { + showToast(getString(R.string.enter_price)); + edit_static_price.requestFocus(); + return false; + } + return true; + } + private boolean isValidDetails() { + + if (chekbox_dynamic_pricing.isChecked()) { + if (spinner_primary_market.getSelectedItemPosition() == 0) { + showToast(getString(R.string.primary_empty)); + return false; + } else if (spinner_secondary_market.getSelectedItemPosition() == 0) { + showToast(getString(R.string.secondary_empty)); + return false; + } else if (spinner_primary_market.getSelectedItemPosition() == spinner_secondary_market.getSelectedItemPosition()) { + showToast(getString(R.string.error_primary_secondry_same)); + return false; + } + } else { + if (edit_static_price.getText().toString().trim().isEmpty()) { + showToast(getString(R.string.all_field_required)); + edit_static_price.requestFocus(); + return false; + } + } + + return true; + } + + private AddressVo getSellingDetails() { + + addressVo.setDynamicPrice(true); + + if (chekbox_dynamic_pricing.isChecked()) { + int priMarketPos, secMarketPos; + priMarketPos = spinner_primary_market.getSelectedItemPosition(); + secMarketPos = spinner_secondary_market.getSelectedItemPosition(); + addressVo.setPrimaryMarket(marketsVoArrayList.get(priMarketPos - 1).getId()); + addressVo.setSecondaryMarket(marketsVoArrayList.get(secMarketPos - 1).getId()); + + addressVo.setSellerFee(edit_seller_price.getText().toString().trim()); + addressVo.setMinPayment(edit_min_payment.getText().toString().trim()); + addressVo.setMaxPayment(edit_max_payment.getText().toString().trim()); + + } else { + + //null other fields + addressVo.setPrimaryMarket(null); + addressVo.setSecondaryMarket(null); + addressVo.setSellerFee(null); + addressVo.setMinPayment(null); + addressVo.setMaxPayment(null); + } + addressVo.setCurrentPrice(edit_static_price.getText().toString().trim()); + return addressVo; + } + + private void getMarkes() { + if (NetworkUtil.isOnline(mContext)) { + SellingAPIClient.createService(mContext).getMarkets("DASH", "USD").enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + + if (response.code() == 200) { + marketsVoArrayList = response.body(); + handleMarkesReponse(marketsVoArrayList); + } else { + String error = RetrofitErrorUtil.parseError(response); + if (error != null && !error.isEmpty()) + showToast(error); + } + + } + + @Override + public void onFailure(Call> call, Throwable t) { + Toast.makeText(getContext(), R.string.try_again, Toast.LENGTH_LONG).show(); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + private void handleMarkesReponse(ArrayList arrayList) { + ArrayList primaryList = new ArrayList(); + ArrayList secondaryList = new ArrayList(); + primaryList.add(0, "Select Primary market"); + secondaryList.add(0, "Select Secondary market"); + for (MarketsVo marketsVo : arrayList) { + primaryList.add(marketsVo.getLabel()); + secondaryList.add(marketsVo.getLabel()); + } + + ArrayAdapter primaryAdapter = new ArrayAdapter(mContext, android.R.layout.simple_spinner_dropdown_item, primaryList); + primaryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner_primary_market.setAdapter(primaryAdapter); + + ArrayAdapter secondaryAdapter = new ArrayAdapter(mContext, android.R.layout.simple_spinner_dropdown_item, secondaryList); + secondaryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner_secondary_market.setAdapter(secondaryAdapter); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/selling_home/SellingHomeFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/selling_home/SellingHomeFragment.java new file mode 100644 index 000000000..86538cd1f --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/selling_home/SellingHomeFragment.java @@ -0,0 +1,175 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.selling_home; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.response.CheckAuthResp; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.add_listing.AddressListingFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.RetrofitErrorUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingAPIClient; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.contact_details.ContactDetailsFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.phone_list.PhoneListFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.storage.SharedPreferenceUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.SellingConstants; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.WOCLogUtil; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 03-Apr-18. + */ + +public class SellingHomeFragment extends SellingBaseFragment implements View.OnClickListener { + + + private View rootView; + private Button button_sign_here, button_list, button_sign_out_woc, button_sell_piv; + private final String TAG = "SellingHomeFragment"; + private LinearLayout layout_sign_out, layout_sign_in; + private TextView text_message_sign_out; + private ProgressBar progressBar; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_home, container, false); + init(); + setListeners(); + setTopbar(); + return rootView; + } else + return rootView; + } + + private void init() { + button_sign_here = (Button) rootView.findViewById(R.id.button_sign_here); + button_list = (Button) rootView.findViewById(R.id.button_list); + button_sign_out_woc = (Button) rootView.findViewById(R.id.button_sign_out_woc); + progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); + text_message_sign_out = (TextView) rootView.findViewById(R.id.text_message_sign_out); + + layout_sign_out = (LinearLayout) rootView.findViewById(R.id.layout_sign_out); + layout_sign_in = (LinearLayout) rootView.findViewById(R.id.layout_sign_in); + button_sell_piv = (Button) rootView.findViewById(R.id.button_sell_piv); + } + + private void setListeners() { + button_sign_here.setOnClickListener(this); + button_list.setOnClickListener(this); + button_sign_out_woc.setOnClickListener(this); + button_sell_piv.setOnClickListener(this); + } + + private void setTopbar() { + ((SellingBaseActivity) mContext).setTopbarTitle( + mContext.getString(R.string.title_selling)); + } + + @Override + public void onResume() { + super.onResume(); + setTopbar(); + if (!TextUtils.isEmpty(SharedPreferenceUtil.getString(SellingConstants.PREF_TOKEN_ID, ""))) { + layout_sign_out.setVisibility(View.VISIBLE); + layout_sign_in.setVisibility(View.GONE); + WOCLogUtil.showLogError("------------", SharedPreferenceUtil.getString(SellingConstants.PREF_LOGGED_IN_PHONE, "")); + text_message_sign_out.setText(mContext.getString(R.string.wallet_is_signed_msg, + SharedPreferenceUtil.getString(SellingConstants.PREF_LOGGED_IN_PHONE, ""))); + } else { + layout_sign_out.setVisibility(View.GONE); + layout_sign_in.setVisibility(View.VISIBLE); + } + } + + @Override + public void onClick(View view) { + + switch (view.getId()) { + case R.id.button_sign_here: + ((SellingBaseActivity) mContext).replaceFragment(new PhoneListFragment(), + true, true); + break; + case R.id.button_list: + ((SellingBaseActivity) mContext).replaceFragment(new AddressListingFragment(), + true, true); + break; + case R.id.button_sign_out_woc: + deleteAuthCall(); + break; + case R.id.button_sell_piv: + //if (!TextUtils.isEmpty(SharedPreferenceUtil.getString(SellingConstants.TOKEN_ID, ""))) + ((SellingBaseActivity) mContext).replaceFragment(new ContactDetailsFragment(), + true, true); + /* else + showToast("Please Sign in first"); + break;*/ + + } + } + + /** + * Method for singout user + */ + public void deleteAuthCall() { + if (NetworkUtil.isOnline(mContext)) { + final String phone = SharedPreferenceUtil.getString(SellingConstants.PREF_LOGGED_IN_PHONE, ""); + progressBar.setVisibility(View.VISIBLE); + SellingAPIClient.createService(interceptor, mContext) + .deleteAuth(phone, getString(R.string.WALLOFCOINS_PUBLISHER_ID)) + .enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Log.d(TAG, "onResponse: response code==>>" + response.code()); + progressBar.setVisibility(View.GONE); + if (response.code() < 299) { + SharedPreferenceUtil.putValue(SellingConstants.PREF_LOGGED_IN_PHONE, ""); + SharedPreferenceUtil.putValue(SellingConstants.PREF_TOKEN_ID, ""); + SharedPreferenceUtil.putValue(SellingConstants.PREF_DEVICE_ID, ""); + SharedPreferenceUtil.putValue(SellingConstants.PREF_DEVICE_CODE, ""); + + showToast(mContext.getString(R.string.alert_sign_out)); + layout_sign_in.setVisibility(View.VISIBLE); + layout_sign_out.setVisibility(View.GONE); + } else { + String error = RetrofitErrorUtil.parseError(response); + if (error != null && !error.isEmpty()) + showToast(error); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + progressBar.setVisibility(View.GONE); + showToast(t.getMessage()); + } + }); + + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/sign_in/SignInFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/sign_in/SignInFragment.java new file mode 100644 index 000000000..686e8dc88 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/sign_in/SignInFragment.java @@ -0,0 +1,646 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.sign_in; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.Gson; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.CustomAdapter; +import pivx.org.pivxwallet.wallofcoins.WOCConstants; +import pivx.org.pivxwallet.wallofcoins.api.WallofCoins; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseActivity; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.order_history.OrderHistoryFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.BuyDashPhoneListPref; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.verification_otp.VerifycationOtpFragment; +import pivx.org.pivxwallet.wallofcoins.response.CheckAuthResp; +import pivx.org.pivxwallet.wallofcoins.response.CountryData; +import pivx.org.pivxwallet.wallofcoins.response.CreateDeviceResp; +import pivx.org.pivxwallet.wallofcoins.response.CreateHoldResp; +import pivx.org.pivxwallet.wallofcoins.response.GetAuthTokenResp; +import pivx.org.pivxwallet.wallofcoins.response.GetHoldsResp; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 04-Apr-18. + */ + +public class SignInFragment extends BuyDashBaseFragment implements View.OnClickListener, SharedPreferences.OnSharedPreferenceChangeListener { + + private final String TAG = "EmailAndPhoneFragment"; + private View rootView; + private LinearLayout linearProgress, linear_email, linear_phone, layout_hold; + private CountryData countryData; + private Spinner sp_country; + private Button btn_next_phone, btn_next_email, btn_sign_in; + private String country_code = "", phone_no = "", email = "", password = "", offerId = ""; + private EditText edit_buy_dash_phone, edit_buy_dash_email; + private TextView tv_skip_email; + private CreateDeviceResp createDeviceResp; + private CreateHoldResp createHoldResp; + private BuyDashPhoneListPref credentilasPref; + private String fromScreen = ""; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_signin, container, false); + init(); + addCountryCodeList(); + setListeners(); + handleArgs(); + return rootView; + } else + return rootView; + } + + private void init() { + credentilasPref = new BuyDashPhoneListPref(PreferenceManager.getDefaultSharedPreferences(mContext)); + + linearProgress = (LinearLayout) rootView.findViewById(R.id.linear_progress); + linear_email = (LinearLayout) rootView.findViewById(R.id.linear_email); + sp_country = (Spinner) rootView.findViewById(R.id.sp_country); + btn_next_phone = (Button) rootView.findViewById(R.id.btn_next_phone); + edit_buy_dash_phone = (EditText) rootView.findViewById(R.id.edit_buy_dash_phone); + btn_next_email = (Button) rootView.findViewById(R.id.btn_next_email); + edit_buy_dash_email = (EditText) rootView.findViewById(R.id.edit_buy_dash_email); + linear_phone = (LinearLayout) rootView.findViewById(R.id.linear_phone); + layout_hold = (LinearLayout) rootView.findViewById(R.id.layout_hold); + tv_skip_email = (TextView) rootView.findViewById(R.id.tv_skip_email); + btn_sign_in = (Button) rootView.findViewById(R.id.btn_sign_in); + } + + private void setListeners() { + btn_next_phone.setOnClickListener(this); + btn_next_email.setOnClickListener(this); + tv_skip_email.setOnClickListener(this); + btn_sign_in.setOnClickListener(this); + } + + /** + * handle the arguments according to user come from previos screen + */ + private void handleArgs() { + if (getArguments() != null) { + if (getArguments().containsKey(WOCConstants.OFFER_ID)) { + offerId = getArguments().getString(WOCConstants.OFFER_ID); + } + if (getArguments().containsKey(WOCConstants.SCREEN_TYPE)) { + fromScreen = getArguments().getString(WOCConstants.SCREEN_TYPE); + } + } + } + + public void changeView() { + if (linear_email.getVisibility() == View.VISIBLE) + ((BuyDashBaseActivity) mContext).popBackDirect(); + else if (linear_phone.getVisibility() == View.GONE) { + layout_hold.setVisibility(View.GONE); + linear_phone.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + + } else if (linear_email.getVisibility() == View.GONE) { + linear_email.setVisibility(View.VISIBLE); + linear_phone.setVisibility(View.GONE); + layout_hold.setVisibility(View.GONE); + } + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.btn_next_phone: + if (isValidPhone()) { + hideKeyBoard(); + // if (!offerId.isEmpty()) { + country_code = countryData.countries.get(sp_country.getSelectedItemPosition()).code; + phone_no = edit_buy_dash_phone.getText().toString().trim(); + String phone = country_code + edit_buy_dash_phone.getText().toString().trim(); + ((BuyDashBaseActivity) mContext).buyDashPref.setPhone(phone); + + checkAuth(); + } + break; + + case R.id.btn_next_email: + if (!edit_buy_dash_email.getText().toString().isEmpty() && isValidEmail(edit_buy_dash_email.getText().toString())) { + email = edit_buy_dash_email.getText().toString(); + linear_phone.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + } else { + showToast(mContext.getString(R.string.alert_enter_valid_email)); + } + break; + case R.id.tv_skip_email: + + linear_phone.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + break; + case R.id.btn_sign_in: + goToUrl("https://wallofcoins.com/signin/" + country_code.replace("+", "") + "-" + phone_no + "/"); + break; + } + } + + private boolean isValidPhone() { + if (edit_buy_dash_phone.getText().toString().trim().isEmpty()) { + edit_buy_dash_phone.requestFocus(); + showToast(mContext.getString(R.string.please_enter_phone_no)); + return false; + } else if (edit_buy_dash_phone.getText().toString().trim().length() < 10) { + edit_buy_dash_phone.requestFocus(); + showToast(mContext.getString(R.string.please_enter_10_digits_phone_no)); + return false; + } + return true; + } + + //add country code list for phone + private void addCountryCodeList() { + String json; + try { + InputStream is = getActivity().getAssets().open("countries.json"); + int size = is.available(); + byte[] buffer = new byte[size]; + is.read(buffer); + is.close(); + json = new String(buffer, "UTF-8"); + } catch (IOException ex) { + ex.printStackTrace(); + return; + } + + countryData = new Gson().fromJson(json, CountryData.class); + + List stringList = new ArrayList<>(); + + for (CountryData.CountriesBean bean : countryData.countries) { + stringList.add(bean.name + " (" + bean.code + ")"); + } + CustomAdapter customAdapter = new CustomAdapter(getActivity(), R.layout.spinner_row_country, countryData.countries); + customAdapter.setDropDownViewResource(R.layout.spinner_row_country); + sp_country.setAdapter(customAdapter); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + + } + + /** + * Method for check authentication type + */ + private void checkAuth() { + if (NetworkUtil.isOnline(mContext)) { + String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + if (!TextUtils.isEmpty(phone)) { + linearProgress.setVisibility(View.VISIBLE); + + WallofCoins.createService(interceptor, mContext).checkAuth(phone, getString(R.string.WALLOFCOINS_PUBLISHER_ID)).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Log.d(TAG, "onResponse: response code==>>" + response.code()); + linearProgress.setVisibility(View.GONE); + if (response.code() == 200) { + if (response.body() != null + && response.body().getAvailableAuthSources() != null + && response.body().getAvailableAuthSources().size() > 0) { + + if (response.body().getAvailableAuthSources().get(0).equals("password")) {//from wesite + showUserPasswordAuthenticationDialog(); + return; + } else if ((response.body().getAvailableAuthSources().size() >= 2//from mobile + && response.body().getAvailableAuthSources().get(1).equals("device")) + || (response.body().getAvailableAuthSources().get(0).equals("device"))) { + hideKeyBoard(); + createHold(); + } + } + } else if (response.code() == 404) { + hideKeyBoard(); + createHold(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + showToast(mContext.getString(R.string.try_again)); + } + }); + } else { + showToast(mContext.getString(R.string.alert_phone)); + } + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } + + /** + * User authentication custom dialog for authenticate user using password + */ + private void showUserPasswordAuthenticationDialog() { + + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View dialogView = inflater.inflate(R.layout.layout_authenticate_password_wallet_dialog, null); + dialogBuilder.setView(dialogView); + + final EditText edtPassword = (EditText) dialogView.findViewById(R.id.edt_woc_authenticaion_password); + TextView txtTitle = (TextView) dialogView.findViewById(R.id.txt_existing_user_dialog_message); + Button btnLogin = (Button) dialogView.findViewById(R.id.btnLogin); + Button btnForgotPassword = (Button) dialogView.findViewById(R.id.btnForgotPassword); + + txtTitle.setMovementMethod(LinkMovementMethod.getInstance()); + + final AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.show(); + + ImageView imgClose = (ImageView) dialogView.findViewById(R.id.imgClose); + + imgClose.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + alertDialog.dismiss(); + } + }); + + btnForgotPassword.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + goToUrl(WOCConstants.KEY_FORGOT_PASSWORD_URL); + } + }); + + btnLogin.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + password = edtPassword.getText().toString().trim(); + if (password.length() > 0) { + getAuthTokenCall(password); + alertDialog.dismiss(); + } else { + showToast(mContext.getString(R.string.password_alert)); + } + } + }); + + } + + /** + * Authorized user using password or device code + * + * @param password + */ + private void getAuthTokenCall(final String password) { + if (NetworkUtil.isOnline(mContext)) { + String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + + if (!TextUtils.isEmpty(phone)) { + + HashMap getAuthTokenReq = new HashMap(); + if (!TextUtils.isEmpty(password)) { + getAuthTokenReq.put(WOCConstants.KEY_PASSWORD, password); + } else { + getAuthTokenReq.put(WOCConstants.KEY_DEVICECODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + } + + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId())) { + getAuthTokenReq.put(WOCConstants.KEY_DEVICEID, ((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()); + } + + getAuthTokenReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).getAuthToken(phone, getAuthTokenReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + linearProgress.setVisibility(View.GONE); + int code = response.code(); + + if (code >= 400 && response.body() == null) { + try { + if (!TextUtils.isEmpty(password)) { + showAlertPasswordDialog(); + } else { + createDevice(); + } + } catch (Exception e) { + e.printStackTrace(); + showToast(mContext.getString(R.string.try_again)); + } + return; + } + + if (!TextUtils.isEmpty(response.body().token)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(response.body().token); + } + if (!TextUtils.isEmpty(password) && TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId())) { + getDevice(); + } else { + credentilasPref.addPhone(country_code + edit_buy_dash_phone.getText().toString().trim(), ((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()); + if (fromScreen.equalsIgnoreCase("PhoneListFragment")) + ((BuyDashBaseActivity) mContext).popBackAllFragmentsExcept("pivx.org.pivxwallet.wallofcoins.buyingwizard.phone_list.PhoneListFragment"); + else + createHold(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(mContext.getString(R.string.try_again)); + linearProgress.setVisibility(View.GONE); + } + }); + + } else { + showToast(mContext.getString(R.string.alert_phone_password_required)); + } + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } + + /** + * Method for create new hold + */ + public void createHold() { + if (NetworkUtil.isOnline(mContext)) { + String phone = ((BuyDashBaseActivity) mContext).buyDashPref.getPhone(); + + final HashMap createHoldPassReq = new HashMap(); + + if (TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + createHoldPassReq.put(WOCConstants.KEY_PHONE, phone); + createHoldPassReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + createHoldPassReq.put(WOCConstants.KEY_EMAIL, email); + createHoldPassReq.put(WOCConstants.KEY_deviceName, WOCConstants.KEY_DEVICE_NAME_VALUE); + createHoldPassReq.put(WOCConstants.KEY_DEVICECODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + } + createHoldPassReq.put(WOCConstants.KEY_OFFER, offerId); + + linearProgress.setVisibility(View.VISIBLE); + + WallofCoins.createService(interceptor, getActivity()).createHold(createHoldPassReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + linearProgress.setVisibility(View.GONE); + + if (null != response.body() && response.code() < 299) { + + createHoldResp = response.body(); + ((BuyDashBaseActivity) mContext).buyDashPref.setHoldId(createHoldResp.id); + ((BuyDashBaseActivity) mContext).buyDashPref.setCreateHoldResp(createHoldResp); + if (TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()) + && !TextUtils.isEmpty(createHoldResp.deviceId)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(createHoldResp.deviceId); + + //added + String phone = country_code + edit_buy_dash_phone.getText().toString().trim(); + credentilasPref.addPhone(phone, ((BuyDashBaseActivity) mContext).buyDashPref.getDeviceId()); + } + if (!TextUtils.isEmpty(response.body().token)) { + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(createHoldResp.token); + } + navigateToVerifyOtp(createHoldResp.__PURCHASE_CODE); + //hideViewExcept(binding.layoutVerifyOtp); + //clearForm((ViewGroup) binding.getRoot()); + //binding.etOtp.setText(createHoldResp.__PURCHASE_CODE); + + } else if (null != response.errorBody()) { + if (response.code() == 403 && TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + + /* String token = credentilasPref.getAuthTokenFromPhoneNum(phone_no); + ((BuyDashBaseActivity) mContext).buyDashPref.setAuthToken(token); + getHolds();*/ + layout_hold.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + linear_phone.setVisibility(View.GONE); + //hideViewExcept(binding.layoutHold); + //clearForm((ViewGroup) binding.getRoot()); + } else if (response.code() == 403 && !TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + getHolds(); + } else if (response.code() == 400) { + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + navigateToOrderList(false); + } else { + layout_hold.setVisibility(View.VISIBLE); + linear_email.setVisibility(View.GONE); + linear_phone.setVisibility(View.GONE); + // hideViewExcept(binding.layoutHold); + //clearForm((ViewGroup) binding.getRoot()); + } + } else { + try { + if (!TextUtils.isEmpty(((BuyDashBaseActivity) mContext).buyDashPref.getAuthToken())) { + navigateToOrderList(false); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } else { + //clearForm((ViewGroup) binding.getRoot()); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Toast.makeText(getContext(), R.string.try_again, Toast.LENGTH_SHORT).show(); + } + }); + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + + } + + /** + * navigate to otp code screen with code + * + * @param otp + */ + private void navigateToVerifyOtp(String otp) { + Bundle bundle = new Bundle(); + bundle.putString(WOCConstants.VERIFICATION_OTP, otp); + VerifycationOtpFragment otpFragment = new VerifycationOtpFragment(); + otpFragment.setArguments(bundle); + + ((BuyDashBaseActivity) mContext).replaceFragment(otpFragment, true, true); + } + + /** + * Get all holds for delete active hold + */ + private void getHolds() { + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).getHolds().enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (response.code() == 200 && response.body() != null) { + linearProgress.setVisibility(View.GONE); + List holdsList = response.body(); + int holdCount = 0; + if (holdsList.size() > 0) { + for (int i = 0; i < holdsList.size(); i++) { + if (null != holdsList.get(i).status && holdsList.get(i).status.equals("AC")) { + deleteHold(holdsList.get(i).id); + holdCount++; + } + } + if (holdCount == 0) { + //getOrderList(false); + navigateToOrderList(false); + } + } else { + //getOrderList(false); + navigateToOrderList(false); + } + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + } + + private void navigateToOrderList(boolean isFromCreateHold) { + OrderHistoryFragment historyFragment = new OrderHistoryFragment(); + Bundle bundle = new Bundle(); + bundle.putBoolean("isFromCreateHold", isFromCreateHold); + historyFragment.setArguments(bundle); + ((BuyDashBaseActivity) mContext).replaceFragment(historyFragment, true, true); + } + + /** + * Method call for delete for provide holdId + * + * @param holdId + */ + private void deleteHold(String holdId) { + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).deleteHold(holdId).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + createHold(); + } + + @Override + public void onFailure(Call call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + } + + /** + * Get Devices for Register user with password + */ + private void getDevice() { + + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).getDevice().enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (response.code() == 200 && response.body() != null) { + linearProgress.setVisibility(View.GONE); + List deviceList = response.body(); + if (deviceList.size() > 0) { + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(deviceList.get(deviceList.size() - 1).getId() + ""); + getAuthTokenCall(""); + } else { + createDevice(); + } + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + linearProgress.setVisibility(View.GONE); + Log.e(TAG, "onFailure: ", t); + showToast(mContext.getString(R.string.try_again)); + } + }); + + } + + /** + * Method for register new device + */ + private void createDevice() { + final HashMap createDeviceReq = new HashMap(); + createDeviceReq.put(WOCConstants.KEY_DEVICE_NAME, mContext.getString(R.string.pivx_wallet_name)); + createDeviceReq.put(WOCConstants.KEY_DEVICE_CODE, getDeviceCode(mContext, ((BuyDashBaseActivity) mContext).buyDashPref)); + createDeviceReq.put(WOCConstants.KEY_PUBLISHER_ID, getString(R.string.WALLOFCOINS_PUBLISHER_ID)); + linearProgress.setVisibility(View.VISIBLE); + WallofCoins.createService(interceptor, getActivity()).createDevice(createDeviceReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (null != response.body() && response.code() < 299) { + createDeviceResp = response.body(); + ((BuyDashBaseActivity) mContext).buyDashPref.setDeviceId(createDeviceResp.getId() + ""); + getAuthTokenCall(""); + } else { + showToast(mContext.getString(R.string.try_again)); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(mContext.getString(R.string.try_again)); + } + }); + } + + //this method remove animation when user want to clear whole back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } +} + diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/storage/SharedPreferenceUtil.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/storage/SharedPreferenceUtil.java new file mode 100644 index 000000000..ab614bde0 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/storage/SharedPreferenceUtil.java @@ -0,0 +1,149 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.storage; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import java.util.Map; + +/** + * Creates SharedPreference for the application. and provides access to it + */ +public class SharedPreferenceUtil { + + private static SharedPreferences sharedPreferences = null; + + private static SharedPreferences.Editor editor = null; + + /** + * Initialize the SharedPreferences instance for the app. + * This method must be called before using any + * other methods of this class. + * + * @param context {@link Context} + */ + @SuppressLint("CommitPrefEdits") + public static void init(Context mcontext) { + + if (sharedPreferences == null) { + sharedPreferences = PreferenceManager + .getDefaultSharedPreferences(mcontext); + editor = sharedPreferences.edit(); + } + + } + + /** + * Puts new Key and its Values into SharedPreference map. + * + * @param key + * @param value + */ + public static void putValue(String key, String value) { + editor.putString(key, value); + editor.commit(); + + } + + /** + * Puts new Key and its Values into SharedPreference map. + * + * @param key + * @param value + */ + public static void putValue(String key, int value) { + editor.putInt(key, value); + editor.commit(); + } + + /** + * Puts new Key and its Values into SharedPreference map. + * + * @param key + * @param value + */ + public static void putValue(String key, long value) { + editor.putLong(key, value); + editor.commit(); + } + + /** + * Puts new Key and its Values into SharedPreference map. + * + * @param key + * @param value + */ + public static void putValue(String key, boolean value) { + editor.putBoolean(key, value); + editor.commit(); + } + + public static void remove(String key) { + editor.remove(key); + editor.commit(); + } + + /** + * returns a values associated with a Key default value "" + * + * @return String + */ + public static String getString(String key, String defValue) { + return sharedPreferences.getString(key, defValue); + } + + /** + * returns a values associated with a Key default value -1 + * + * @return String + */ + public static int getInt(String key, int defValue) { + return sharedPreferences.getInt(key, defValue); + } + + /** + * returns a values associated with a Key default value -1 + * + * @return String + */ + public static long getLong(String key, long defValue) { + return sharedPreferences.getLong(key, defValue); + } + + /** + * returns a values associated with a Key default value false + * + * @return String + */ + public static boolean getBoolean(String key, boolean defValue) { + return sharedPreferences.getBoolean(key, defValue); + } + + /** + * Checks if key is exist in SharedPreference + * + * @param key + * @return boolean + */ + public static boolean contains(String key) { + return sharedPreferences.contains(key); + } + + /** + * returns map of all the key value pair available in SharedPreference + * + * @return Map + */ + public static Map getAll() { + return sharedPreferences.getAll(); + } + + /** + * clear all available sharedPreference + */ + public static void clearAll() { + editor.clear().commit(); + } + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/BuyDashAddressPref.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/BuyDashAddressPref.java new file mode 100644 index 000000000..1347edca9 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/BuyDashAddressPref.java @@ -0,0 +1,32 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.utils; + +import android.content.SharedPreferences; + +/** + * Created on 13-Mar-18. + */ + +public class BuyDashAddressPref { + private final SharedPreferences prefs; + private static final String BUY_DASH_ADDRESS = "addres"; + + public BuyDashAddressPref(final SharedPreferences prefs) { + this.prefs = prefs; + } + + public void setBuyDashAddress(String address) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(BUY_DASH_ADDRESS, address); + editor.commit(); + } + + public String getBuyDashAddress() { + return prefs.getString(BUY_DASH_ADDRESS, ""); + } + + public void clearBuyDashAddress() { + SharedPreferences.Editor editor = prefs.edit(); + editor.clear(); + editor.commit(); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/FragmentUtils.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/FragmentUtils.java new file mode 100644 index 000000000..1cdc609be --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/FragmentUtils.java @@ -0,0 +1,9 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.utils; + +/** + * Created on 09-Mar-18. + */ + +public class FragmentUtils { + public static boolean sDisableFragmentAnimations = false; +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/ObjectSerializer.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/ObjectSerializer.java new file mode 100644 index 000000000..38d3f5bb0 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/ObjectSerializer.java @@ -0,0 +1,52 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * Created on 12-Mar-18. + */ + +public class ObjectSerializer { + public static String serialize(Serializable obj) throws IOException { + if (obj == null) return ""; + ByteArrayOutputStream serialObj = new ByteArrayOutputStream(); + ObjectOutputStream objStream = new ObjectOutputStream(serialObj); + objStream.writeObject(obj); + objStream.close(); + return encodeBytes(serialObj.toByteArray()); + } + + public static Object deserialize(String str) throws IOException, ClassNotFoundException { + if (str == null || str.length() == 0) return null; + ByteArrayInputStream serialObj = new ByteArrayInputStream(decodeBytes(str)); + ObjectInputStream objStream = new ObjectInputStream(serialObj); + return objStream.readObject(); + } + + public static String encodeBytes(byte[] bytes) { + StringBuffer strBuf = new StringBuffer(); + + for (int i = 0; i < bytes.length; i++) { + strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a'))); + strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a'))); + } + + return strBuf.toString(); + } + + public static byte[] decodeBytes(String str) { + byte[] bytes = new byte[str.length() / 2]; + for (int i = 0; i < str.length(); i += 2) { + char c = str.charAt(i); + bytes[i / 2] = (byte) ((c - 'a') << 4); + c = str.charAt(i + 1); + bytes[i / 2] += (c - 'a'); + } + return bytes; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/SellingConstants.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/SellingConstants.java new file mode 100644 index 000000000..52b09c090 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/SellingConstants.java @@ -0,0 +1,18 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.utils; + +/** + * Created on 03-Apr-18. + */ + +public class SellingConstants { + + public static String PREF_TOKEN_ID = "tokenId"; + public static String PREF_DEVICE_CODE = "deviceCode"; + public static String PREF_DEVICE_ID = "deviceID"; + public static String PREF_LOGGED_IN_PHONE = "phoneNum"; + public static String PREF_LOGGED_IN_EMAIL = "loggedemail"; + public static String ARGUMENT_ADDRESS_DETAILS_VO = "ARGUMENT_ADDRESS_DETAILS_VO"; + public static String ARGUMENT_VERIFICATION_CODE = "ARGUMENT_VERIFICATION_CODE"; + public static String ARGUMENT_PHONE_NUMBER = "ARGUMENT_PHONE_NUMBER"; + public static String ARGUMENT_ADDRESS_ID = "address_id"; +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/WOCLogUtil.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/WOCLogUtil.java new file mode 100644 index 000000000..a8b2bd418 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/utils/WOCLogUtil.java @@ -0,0 +1,33 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.utils; + +import android.util.Log; + +import pivx.org.pivxwallet.BuildConfig; + +/** + * Created on 05-Apr-18. + */ + +public class WOCLogUtil { + + + public static void showLogError(String tag, String log) { + if (BuildConfig.DEBUG) + Log.e(tag, log); + } + + public static void showLogWarning(String tag, String log) { + if (BuildConfig.DEBUG) + Log.w(tag, log); + } + + public static void showLogInfo(String tag, String log) { + if (BuildConfig.DEBUG) + Log.i(tag, log); + } + + public static void showLogDebug(String tag, String log) { + if (BuildConfig.DEBUG) + Log.d(tag, log); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/verification_otp/VerifycationCodeFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/verification_otp/VerifycationCodeFragment.java new file mode 100644 index 000000000..ea9115df5 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/verification_otp/VerifycationCodeFragment.java @@ -0,0 +1,163 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.verification_otp; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.TextView; + +import java.util.HashMap; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.BuyDashBaseFragment; +import pivx.org.pivxwallet.wallofcoins.buyingwizard.utils.FragmentUtils; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingAPIClient; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingApiConstants; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.instruction.InstructionFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.VerifyAdResp; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.storage.SharedPreferenceUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.SellingConstants; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 08-Mar-18. + */ + +public class VerifycationCodeFragment extends BuyDashBaseFragment implements View.OnClickListener { + + + private View rootView; + private Button button_verify_add, button_resend_otp; + private EditText edit_code; + private final String TAG = "VerifycationOtpFragment"; + private String mVerificationCode = "", mPhone = "", mAddressId = ""; + private ProgressBar progressBar; + private TextView text_msg; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_verification_code, container, false); + init(); + setListeners(); + handleArgs(); + return rootView; + } else + return rootView; + } + + private void init() { + button_verify_add = (Button) rootView.findViewById(R.id.button_verify_add); + button_resend_otp = (Button) rootView.findViewById(R.id.button_resend_otp); + edit_code = (EditText) rootView.findViewById(R.id.edit_code); + progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); + text_msg = (TextView) rootView.findViewById(R.id.text_msg); + + text_msg.setText(getString(R.string.verification_code_msg, + SharedPreferenceUtil.getString(SellingConstants.PREF_LOGGED_IN_PHONE, ""))); + } + + private void setListeners() { + button_resend_otp.setOnClickListener(this); + button_verify_add.setOnClickListener(this); + } + + private void handleArgs() { + if (getArguments() != null) { + mVerificationCode = getArguments().getString(SellingConstants.ARGUMENT_VERIFICATION_CODE); + mPhone = getArguments().getString(SellingConstants.ARGUMENT_PHONE_NUMBER); + mAddressId = getArguments().getString(SellingConstants.ARGUMENT_ADDRESS_ID); + edit_code.setText(mVerificationCode); + } + } + + @Override + public void onClick(View view) { + + switch (view.getId()) { + case R.id.button_resend_otp: + showToast("Under Implementation"); + // verifyOTP(); + break; + case R.id.button_verify_add: + navigateToLocation(); + //verifyAd(); + break; + } + } + + + private void verifyAd() { + + if (NetworkUtil.isOnline(mContext)) { + + HashMap verifyAdReq = new HashMap(); + + verifyAdReq.put(SellingApiConstants.AD_ID, mAddressId); + verifyAdReq.put(SellingApiConstants.KEY_CODE, mVerificationCode); + verifyAdReq.put(SellingApiConstants.KEY_PHONE, mPhone); + + SellingAPIClient.createService(interceptor, mContext).verifyAd(verifyAdReq).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (null != response && null != response.body()) { + + if (null != response.body().fundingAddress) { + navigateToLocation(); + + } else { + showToast(getString(R.string.try_again)); + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(t.getMessage()); + } + }); + + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } + + /** + * create hold screen + * + * @param + */ + private void navigateToLocation() { + InstructionFragment instructionFragment = new InstructionFragment(); + ((SellingBaseActivity) mContext).replaceFragment(instructionFragment, true, true); + } + + + //this method remove animation when user want to clear back stack + @Override + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { + if (FragmentUtils.sDisableFragmentAnimations) { + Animation a = new Animation() { + }; + a.setDuration(0); + return a; + } + return super.onCreateAnimation(transit, enter, nextAnim); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/verify_details/VerifySellingDetailsFragment.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/verify_details/VerifySellingDetailsFragment.java new file mode 100644 index 000000000..d0b0c9d6a --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/selling_wizard/verify_details/VerifySellingDetailsFragment.java @@ -0,0 +1,249 @@ +package pivx.org.pivxwallet.wallofcoins.selling_wizard.verify_details; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; + +import java.util.HashMap; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseActivity; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.SellingBaseFragment; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.RetrofitErrorUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingAPIClient; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.api.SellingApiConstants; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.AddressVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.models.SendVerificationRespVo; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.SellingConstants; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.utils.WOCLogUtil; +import pivx.org.pivxwallet.wallofcoins.selling_wizard.verification_otp.VerifycationCodeFragment; +import pivx.org.pivxwallet.wallofcoins.utils.NetworkUtil; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created on 05-Apr-18. + */ + +public class VerifySellingDetailsFragment extends SellingBaseFragment implements View.OnClickListener { + private View rootView; + private Button button_continue; + private ProgressBar progressBar; + private EditText edit_account, edit_price, edit_email, edit_phone; + private AddressVo addressVo; + private String mAddressId, mPhone; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mContext = context; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (rootView == null) { + rootView = inflater.inflate(R.layout.fragment_selling_verify_details, container, false); + init(); + setListeners(); + setTopbar(); + handleArgs(); + return rootView; + } else + return rootView; + } + + private void init() { + button_continue = (Button) rootView.findViewById(R.id.button_continue); + progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); + edit_account = (EditText) rootView.findViewById(R.id.edit_account); + edit_price = (EditText) rootView.findViewById(R.id.edit_price); + edit_email = (EditText) rootView.findViewById(R.id.edit_email); + edit_phone = (EditText) rootView.findViewById(R.id.edit_phone); + } + + private void setListeners() { + button_continue.setOnClickListener(this); + } + + private void setTopbar() { + + ((SellingBaseActivity) mContext).setTopbarTitle( + mContext.getString(R.string.title_verify_selling_details)); + } + + private void handleArgs() { + + if (getArguments() != null) { + addressVo = (AddressVo) + getArguments().getSerializable(SellingConstants.ARGUMENT_ADDRESS_DETAILS_VO); + mPhone = addressVo.getNumber(); + edit_account.setText(addressVo.getNumber()); + edit_price.setText(addressVo.getCurrentPrice()); + edit_email.setText(addressVo.getEmail()); + edit_phone.setText(addressVo.getPhone()); + addressVo.setUserEnabled(true); + } + } + + @Override + public void onResume() { + super.onResume(); + setTopbar(); + } + + @Override + public void onClick(View view) { + + switch (view.getId()) { + case R.id.button_continue: + // createAddress(); + navigateToCodeScreen("52015"); + break; + } + } + + private void createAddress() { + if (NetworkUtil.isOnline(mContext)) { +/** + * { + "phone": "9417972681", + "email": "demo@geni.to", + "phoneCode": "1", + "bankBusiness": "2", + "sellCrypto": "DASH", + "userEnabled": true, + "dynamicPrice": true, + "primaryMarket": "5", + "secondaryMarket": "4", + "minPayment": "10", + "maxPayment": "1000", + "sellerFee": "111", + "currentPrice": "11", + "name": "a", + "number": "1", + "number2": "1" + } + + number=123&dynamicPrice=true& + number2=123&primaryMarket=5& + bankBusiness=null& + email=abc%40gmail.com&phone=%2B123977765& + minPayment=10&phoneCode=1&sellCrypto=DASH& + maxPayment=11&name=abc&sellerFee=12&secondaryMarket=4¤tPrice=10&userEnabled=true + + + + */ + HashMap hashMap = new HashMap(); + hashMap.put(SellingApiConstants.KEY_PHONE, "2397776543"); + hashMap.put(SellingApiConstants.KEY_EMAIL, addressVo.getEmail()); + hashMap.put(SellingApiConstants.KEY_PHONE_CODE, "1"); + hashMap.put(SellingApiConstants.KEY_BANK_BUSINESS, "" + addressVo.getBankBusiness());//bank id + hashMap.put(SellingApiConstants.KEY_SELL_CRYPTO, "DASH"); + hashMap.put(SellingApiConstants.KEY_USER_ENABLED, "true"); + hashMap.put(SellingApiConstants.KEY_DYNAMIC_PRICE, "" + addressVo.getDynamicPrice()); + //hashMap.put(SellingApiConstants.KEY_USER_PAY_FIELDS, "" + (receivingOptionsResp.payFields.payFieldsB == null)); + + if (addressVo.getDynamicPrice()) { + + hashMap.put(SellingApiConstants.KEY_PRIMARY_MARKETS, addressVo.getPrimaryMarket()); + hashMap.put(SellingApiConstants.KEY_SECONDARY_MARKETS, addressVo.getSecondaryMarket()); + + hashMap.put(SellingApiConstants.KEY_MIN_PAYMETS, addressVo.getMinPayment()); + hashMap.put(SellingApiConstants.KEY_MAX_PAYMETS, addressVo.getMaxPayment()); + hashMap.put(SellingApiConstants.KEY_SELLER_FEE, addressVo.getSellerFee()); + } + + hashMap.put(SellingApiConstants.KEY_CURRENT_PRICE, addressVo.getCurrentPrice()); + + hashMap.put(SellingApiConstants.KEY_NAME, addressVo.getName());//acc holder name + hashMap.put(SellingApiConstants.KEY_NUMBER, addressVo.getNumber());//acc number + hashMap.put(SellingApiConstants.KEY_NUMBER2, addressVo.getNumber2());//acc confirm number + + + progressBar.setVisibility(View.VISIBLE); + SellingAPIClient.createService(interceptor, mContext).createAddress(hashMap). + enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + progressBar.setVisibility(View.GONE); + + if (response.code() == 200) { + AddressVo addressVo = response.body(); + mAddressId = addressVo.getId(); + WOCLogUtil.showLogError("Address Id:", addressVo.getId()); + sendVerificationCode(addressVo.getPhone(), addressVo.getId()); + } else { + String error = RetrofitErrorUtil.parseError(response); + if (error != null && !error.isEmpty()) + showToast(error); + } + + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(t.getMessage()); + progressBar.setVisibility(View.GONE); + } + }); + + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } + + private void sendVerificationCode(String phone, String addId) { + if (NetworkUtil.isOnline(mContext)) { + HashMap hashMap = new HashMap(); + hashMap.put(SellingApiConstants.KEY_PUBLISHER_ID, SellingApiConstants.WALLOFCOINS_PUBLISHER_ID); + hashMap.put(SellingApiConstants.KEY_PHONE, phone); + hashMap.put(SellingApiConstants.AD_ID, addId); + + progressBar.setVisibility(View.VISIBLE); + SellingAPIClient.createService(interceptor, mContext).sendVerificationCode(hashMap). + enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + progressBar.setVisibility(View.GONE); + + if (response.code() == 200) { + navigateToCodeScreen(response.body().__CASH_CODE); + + } else { + String error = RetrofitErrorUtil.parseError(response); + if (error != null && !error.isEmpty()) + showToast(error); + } + + } + + @Override + public void onFailure(Call call, Throwable t) { + showToast(t.getMessage()); + progressBar.setVisibility(View.GONE); + } + }); + + } else + showToast(mContext.getString(R.string.network_not_avaialable)); + } + + private void navigateToCodeScreen(String code) { + Bundle bundle = new Bundle(); + bundle.putSerializable(SellingConstants.ARGUMENT_VERIFICATION_CODE, code); + bundle.putSerializable(SellingConstants.ARGUMENT_PHONE_NUMBER, mPhone); + bundle.putSerializable(SellingConstants.ARGUMENT_ADDRESS_ID, mAddressId); + VerifycationCodeFragment fragment = new VerifycationCodeFragment(); + fragment.setArguments(bundle); + + ((SellingBaseActivity) mContext).replaceFragment(fragment, true, true); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencyAmountView.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencyAmountView.java new file mode 100644 index 000000000..bfb68fb57 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencyAmountView.java @@ -0,0 +1,363 @@ +/* + * Copyright 2011-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.ui; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Parcelable; +import android.text.Editable; +import android.text.InputType; +import android.text.Spannable; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.bitcoinj.core.Coin; +import org.bitcoinj.core.Monetary; +import org.bitcoinj.utils.MonetaryFormat; + +import javax.annotation.Nullable; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.utils.Constants; +import pivx.org.pivxwallet.wallofcoins.utils.GenericUtils; +import pivx.org.pivxwallet.wallofcoins.utils.MonetarySpannable; + + +/** + * @author Andreas Schildbach + */ +public final class CurrencyAmountView extends FrameLayout { + public static interface Listener { + void changed(); + + void focusChanged(final boolean hasFocus); + } + + private int significantColor, lessSignificantColor, errorColor; + private Drawable deleteButtonDrawable, contextButtonDrawable; + private Drawable currencySymbolDrawable; + private String localCurrencyCode = null; + private MonetaryFormat inputFormat; + private Monetary hint = null; + private MonetaryFormat hintFormat = new MonetaryFormat().noCode(); + private boolean amountSigned = false; + private boolean validateAmount = true; + + private TextView textView; + private View contextButton; + private Listener listener; + private OnClickListener contextButtonClickListener; + + public CurrencyAmountView(final Context context) { + super(context); + init(context); + } + + public CurrencyAmountView(final Context context, final AttributeSet attrs) { + super(context, attrs); + init(context); + } + + private void init(final Context context) { + final Resources resources = context.getResources(); + significantColor = resources.getColor(R.color.fg_significant); + lessSignificantColor = resources.getColor(R.color.fg_less_significant); + errorColor = resources.getColor(R.color.fg_error); + deleteButtonDrawable = resources.getDrawable(R.drawable.ic_clear_grey600_24dp); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + final Context context = getContext(); + + textView = (TextView) getChildAt(0); + textView.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL); + textView.setHintTextColor(lessSignificantColor); + textView.setHorizontalFadingEdgeEnabled(true); + textView.setSingleLine(); + setValidateAmount(textView instanceof EditText); + textView.addTextChangedListener(textViewListener); + textView.setOnFocusChangeListener(textViewListener); + + contextButton = new View(context) { + @Override + protected void onMeasure(final int wMeasureSpec, final int hMeasureSpec) { + setMeasuredDimension(textView.getCompoundPaddingRight(), textView.getMeasuredHeight()); + } + }; + final LayoutParams chooseViewParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + chooseViewParams.gravity = Gravity.RIGHT; + contextButton.setLayoutParams(chooseViewParams); + this.addView(contextButton); + + updateAppearance(); + } + + public void setCurrencySymbol(@Nullable final String currencyCode) { + if (MonetaryFormat.CODE_BTC.equals(currencyCode)) { + currencySymbolDrawable = getResources().getDrawable(R.drawable.currency_symbol_btc); + localCurrencyCode = null; + } else if (MonetaryFormat.CODE_MBTC.equals(currencyCode)) { + currencySymbolDrawable = getResources().getDrawable(R.drawable.currency_symbol_mbtc); + localCurrencyCode = null; + } else if (MonetaryFormat.CODE_UBTC.equals(currencyCode)) { + currencySymbolDrawable = getResources().getDrawable(R.drawable.currency_symbol_ubtc); + localCurrencyCode = null; + } else if (currencyCode != null) // fiat + { + final String currencySymbol = GenericUtils.currencySymbol(currencyCode); + final float textSize = textView.getTextSize(); + final float smallerTextSize = textSize * (20f / 24f); + currencySymbolDrawable = new CurrencySymbolDrawable(currencySymbol, smallerTextSize, lessSignificantColor, + textSize * 0.37f); + localCurrencyCode = currencyCode; + } else { + currencySymbolDrawable = null; + localCurrencyCode = null; + } + + updateAppearance(); + } + + public void setInputFormat(final MonetaryFormat inputFormat) { + this.inputFormat = inputFormat.noCode(); + } + + public void setHintFormat(final MonetaryFormat hintFormat) { + this.hintFormat = hintFormat.noCode(); + updateAppearance(); + } + + public void setHint(@Nullable final Monetary hint) { + this.hint = hint; + updateAppearance(); + } + + public void setAmountSigned(final boolean amountSigned) { + this.amountSigned = amountSigned; + } + + public void setValidateAmount(final boolean validateAmount) { + this.validateAmount = validateAmount; + } + + public void setContextButton(final int contextButtonResId, final OnClickListener contextButtonClickListener) { + this.contextButtonDrawable = getContext().getResources().getDrawable(contextButtonResId); + this.contextButtonClickListener = contextButtonClickListener; + + updateAppearance(); + } + + public void setListener(final Listener listener) { + this.listener = listener; + } + + @Nullable + public Monetary getAmount() { + if (!isValidAmount(false)) + return null; + + final String amountStr = textView.getText().toString().trim(); + if (localCurrencyCode == null) + return inputFormat.parse(amountStr); + else + return inputFormat.parseFiat(localCurrencyCode, amountStr); + } + + public void setAmount(@Nullable final Monetary amount, final boolean fireListener) { + if (!fireListener) + textViewListener.setFire(false); + + if (amount != null) + textView.setText(new MonetarySpannable(inputFormat, amountSigned, amount)); + else + textView.setText(null); + + if (!fireListener) + textViewListener.setFire(true); + } + + @Override + public void setEnabled(final boolean enabled) { + super.setEnabled(enabled); + + textView.setEnabled(enabled); + + updateAppearance(); + } + + public void setTextColor(final int color) { + significantColor = color; + + updateAppearance(); + } + + public void setStrikeThru(final boolean strikeThru) { + if (strikeThru) + textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); + else + textView.setPaintFlags(textView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); + } + + public TextView getTextView() { + return textView; + } + + public void setNextFocusId(final int nextFocusId) { + textView.setNextFocusDownId(nextFocusId); + textView.setNextFocusForwardId(nextFocusId); + } + + private boolean isValidAmount(final boolean zeroIsValid) { + final String str = textView.getText().toString().trim(); + + try { + if (!str.isEmpty()) { + final Monetary amount; + if (localCurrencyCode == null) { + amount = inputFormat.parse(str); + if (((Coin) amount).isGreaterThan(Constants.NETWORK_PARAMETERS.getMaxMoney())) + return false; + } else { + amount = inputFormat.parseFiat(localCurrencyCode, str); + } + + // exactly zero + return zeroIsValid || amount.signum() > 0; + } + } catch (final Exception x) { + } + + return false; + } + + private final OnClickListener deleteClickListener = new OnClickListener() { + @Override + public void onClick(final View v) { + setAmount(null, true); + textView.requestFocus(); + } + }; + + private void updateAppearance() { + final boolean enabled = textView.isEnabled(); + + contextButton.setEnabled(enabled); + + final String amount = textView.getText().toString().trim(); + + if (enabled && !amount.isEmpty()) { + textView.setCompoundDrawablesWithIntrinsicBounds(currencySymbolDrawable, null, deleteButtonDrawable, null); + contextButton.setOnClickListener(deleteClickListener); + } else if (enabled && contextButtonDrawable != null) { + textView.setCompoundDrawablesWithIntrinsicBounds(currencySymbolDrawable, null, contextButtonDrawable, null); + contextButton.setOnClickListener(contextButtonClickListener); + } else { + textView.setCompoundDrawablesWithIntrinsicBounds(currencySymbolDrawable, null, null, null); + contextButton.setOnClickListener(null); + } + + contextButton.requestLayout(); + + textView.setTextColor(!validateAmount || isValidAmount(true) ? significantColor : errorColor); + + final Spannable hintSpannable = new MonetarySpannable(hintFormat, hint != null ? hint : Coin.ZERO) + .applyMarkup(null, MonetarySpannable.STANDARD_INSIGNIFICANT_SPANS); + textView.setHint(hintSpannable); + } + + @Override + protected Parcelable onSaveInstanceState() { + final Bundle state = new Bundle(); + state.putParcelable("super_state", super.onSaveInstanceState()); + state.putParcelable("child_textview", textView.onSaveInstanceState()); + state.putSerializable("amount", getAmount()); + return state; + } + + @Override + protected void onRestoreInstanceState(final Parcelable state) { + if (state instanceof Bundle) { + final Bundle bundle = (Bundle) state; + super.onRestoreInstanceState(bundle.getParcelable("super_state")); + textView.onRestoreInstanceState(bundle.getParcelable("child_textview")); + setAmount((Monetary) bundle.getSerializable("amount"), false); + } else { + super.onRestoreInstanceState(state); + } + } + + private final TextViewListener textViewListener = new TextViewListener(); + + private final class TextViewListener implements TextWatcher, OnFocusChangeListener { + private boolean fire = true; + + public void setFire(final boolean fire) { + this.fire = fire; + } + + @Override + public void afterTextChanged(final Editable s) { + // workaround for German keyboards + final String original = s.toString(); + final String replaced = original.replace(',', '.'); + if (!replaced.equals(original)) { + s.clear(); + s.append(replaced); + } + + MonetarySpannable.applyMarkup(s, null, MonetarySpannable.STANDARD_SIGNIFICANT_SPANS, + MonetarySpannable.STANDARD_INSIGNIFICANT_SPANS); + } + + @Override + public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) { + } + + @Override + public void onTextChanged(final CharSequence s, final int start, final int before, final int count) { + updateAppearance(); + if (listener != null && fire) + listener.changed(); + } + + @Override + public void onFocusChange(final View v, final boolean hasFocus) { + if (!hasFocus) { + final Monetary amount = getAmount(); + if (amount != null) + setAmount(amount, false); + } + + if (listener != null && fire) + listener.focusChanged(hasFocus); + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencySymbolDrawable.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencySymbolDrawable.java new file mode 100644 index 000000000..e2574ccb7 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencySymbolDrawable.java @@ -0,0 +1,67 @@ +/* + * Copyright 2011-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.ui; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; + +import pivx.org.pivxwallet.wallofcoins.utils.Constants; + + +/** + * @author Andreas Schildbach + */ +public final class CurrencySymbolDrawable extends Drawable { + private final Paint paint = new Paint(); + private final String symbol; + private final float y; + + public CurrencySymbolDrawable(final String symbol, final float textSize, final int color, final float y) { + paint.setColor(color); + paint.setAntiAlias(true); + paint.setTextSize(textSize); + + this.symbol = symbol + Constants.CHAR_HAIR_SPACE; + this.y = y; + } + + @Override + public void draw(final Canvas canvas) { + canvas.drawText(symbol, 0, y, paint); + } + + @Override + public int getIntrinsicWidth() { + return (int) paint.measureText(symbol); + } + + @Override + public int getOpacity() { + return 0; + } + + @Override + public void setAlpha(final int alpha) { + } + + @Override + public void setColorFilter(final ColorFilter cf) { + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencyTextView.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencyTextView.java new file mode 100644 index 000000000..45d6843b5 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/CurrencyTextView.java @@ -0,0 +1,119 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.ui; + +import android.content.Context; +import android.graphics.Paint; +import android.support.v7.widget.AppCompatTextView; +import android.text.style.ForegroundColorSpan; +import android.text.style.RelativeSizeSpan; +import android.text.style.ScaleXSpan; +import android.util.AttributeSet; + +import org.bitcoinj.core.Monetary; +import org.bitcoinj.utils.MonetaryFormat; + +import pivx.org.pivxwallet.R; +import pivx.org.pivxwallet.wallofcoins.utils.Constants; +import pivx.org.pivxwallet.wallofcoins.utils.MonetarySpannable; + +/** + * @author Andreas Schildbach + */ +public class CurrencyTextView extends AppCompatTextView { + private Monetary amount = null; + private MonetaryFormat format = null; + private boolean alwaysSigned = false; + private RelativeSizeSpan prefixRelativeSizeSpan = null; + private ScaleXSpan prefixScaleXSpan = null; + private ForegroundColorSpan prefixColorSpan = null; + private RelativeSizeSpan insignificantRelativeSizeSpan = null; + + public CurrencyTextView(final Context context) { + super(context); + } + + public CurrencyTextView(final Context context, final AttributeSet attrs) { + super(context, attrs); + } + + public void setAmount(final Monetary amount) { + this.amount = amount; + updateView(); + } + + public void setFormat(final MonetaryFormat format) { + this.format = format.codeSeparator(Constants.CHAR_HAIR_SPACE); + updateView(); + } + + public void setAlwaysSigned(final boolean alwaysSigned) { + this.alwaysSigned = alwaysSigned; + updateView(); + } + + public void setStrikeThru(final boolean strikeThru) { + if (strikeThru) + setPaintFlags(getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); + else + setPaintFlags(getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); + } + + public void setInsignificantRelativeSize(final float insignificantRelativeSize) { + if (insignificantRelativeSize != 1) { + this.prefixRelativeSizeSpan = new RelativeSizeSpan(insignificantRelativeSize); + this.insignificantRelativeSizeSpan = new RelativeSizeSpan(insignificantRelativeSize); + } else { + this.prefixRelativeSizeSpan = null; + this.insignificantRelativeSizeSpan = null; + } + } + + public void setPrefixColor(final int prefixColor) { + this.prefixColorSpan = new ForegroundColorSpan(prefixColor); + updateView(); + } + + public void setPrefixScaleX(final float prefixScaleX) { + this.prefixScaleXSpan = new ScaleXSpan(prefixScaleX); + updateView(); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + setPrefixColor(getResources().getColor(R.color.fg_less_significant)); + setPrefixScaleX(1); + setInsignificantRelativeSize(0.85f); + setSingleLine(); + } + + private void updateView() { + final MonetarySpannable text; + + if (amount != null) + text = new MonetarySpannable(format, alwaysSigned, amount).applyMarkup( + new Object[]{prefixRelativeSizeSpan, prefixScaleXSpan, prefixColorSpan}, + new Object[]{insignificantRelativeSizeSpan}); + else + text = null; + + setText(text); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/DividerItemDecoration.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/DividerItemDecoration.java new file mode 100644 index 000000000..b477963e6 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/DividerItemDecoration.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package pivx.org.pivxwallet.wallofcoins.ui; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +public class DividerItemDecoration extends RecyclerView.ItemDecoration { + private static final int[] ATTRS = new int[] { android.R.attr.listDivider }; + + public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; + public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; + + private final Drawable mDivider; + private int mOrientation; + + public DividerItemDecoration(final Context context, final int orientation) { + final TypedArray a = context.obtainStyledAttributes(ATTRS); + mDivider = a.getDrawable(0); + a.recycle(); + setOrientation(orientation); + } + + public void setOrientation(final int orientation) { + if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) + throw new IllegalArgumentException("invalid orientation"); + + mOrientation = orientation; + } + + @Override + public void onDraw(final Canvas c, final RecyclerView parent) { + if (mOrientation == VERTICAL_LIST) + drawVertical(c, parent); + else + drawHorizontal(c, parent); + } + + public void drawVertical(final Canvas c, final RecyclerView parent) { + final int left = parent.getPaddingLeft(); + final int right = parent.getWidth() - parent.getPaddingRight(); + final int childCount = parent.getChildCount(); + + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int top = child.getBottom() + params.bottomMargin + Math.round(child.getTranslationY()); + final int bottom = top + mDivider.getIntrinsicHeight(); + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + } + + public void drawHorizontal(final Canvas c, final RecyclerView parent) { + final int top = parent.getPaddingTop(); + final int bottom = parent.getHeight() - parent.getPaddingBottom(); + final int childCount = parent.getChildCount(); + + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int left = child.getRight() + params.rightMargin + Math.round(child.getTranslationX()); + final int right = left + mDivider.getIntrinsicHeight(); + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + } + + @Override + public void getItemOffsets(final Rect outRect, final int itemPosition, final RecyclerView parent) { + if (mOrientation == VERTICAL_LIST) + outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); + else + outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/ToolbarCurrencyTextView.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/ToolbarCurrencyTextView.java new file mode 100644 index 000000000..2fa218420 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/ui/ToolbarCurrencyTextView.java @@ -0,0 +1,76 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.ui; + +import android.content.Context; +import android.support.v4.content.ContextCompat; +import android.util.AttributeSet; + +import pivx.org.pivxwallet.R; + + +public class ToolbarCurrencyTextView extends CurrencyTextView +{ + + public ToolbarCurrencyTextView(final Context context) + { + super(context); + } + + public ToolbarCurrencyTextView(final Context context, final AttributeSet attrs) + { + super(context, attrs); + } + + @Override + protected void onFinishInflate() + { + super.onFinishInflate(); + + setPrefixColor(ContextCompat.getColor(getContext(), R.color.white)); + } + + /*@Override + protected void setTextFormat(CharSequence text) + { + if (text == null) + { + setText(null); + } + else + { + String textStr = text.toString(); + if (textStr.contains(MonetaryFormat.CODE_UBTC)) + { + textStr = textStr.replace(MonetaryFormat.CODE_UBTC, ""); + setCompoundDrawablesWithIntrinsicBounds(R.drawable.balance_prefix_micro, 0, 0, 0); + } + else if (textStr.contains(MonetaryFormat.CODE_MBTC)) + { + textStr = textStr.replace(MonetaryFormat.CODE_MBTC, ""); + setCompoundDrawablesWithIntrinsicBounds(R.drawable.balance_prefix_milli, 0, 0, 0); + } + else if (textStr.contains(MonetaryFormat.CODE_BTC)) + { + textStr = textStr.replace(MonetaryFormat.CODE_BTC, ""); + setCompoundDrawablesWithIntrinsicBounds(R.drawable.balance_prefix, 0, 0, 0); + } + setText(textStr); + } + }*/ +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Configuration.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Configuration.java new file mode 100644 index 000000000..2885dc001 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Configuration.java @@ -0,0 +1,301 @@ +/* + * Copyright 2014-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.utils; + +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.content.res.Resources; +import android.net.Uri; +import android.text.format.DateUtils; + +import com.google.common.base.Strings; + +import org.bitcoinj.core.Coin; +import org.bitcoinj.utils.MonetaryFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import pivx.org.pivxwallet.R; + + +/** + * @author Andreas Schildbach + */ +public class Configuration { + public final int lastVersionCode; + + private final SharedPreferences prefs; + private final Resources res; + + public static final String PREFS_KEY_BTC_PRECISION = "btc_precision"; + public static final String PREFS_KEY_OWN_NAME = "own_name"; + public static final String PREFS_KEY_SEND_COINS_AUTOCLOSE = "send_coins_autoclose"; + public static final String PREFS_KEY_CONNECTIVITY_NOTIFICATION = "connectivity_notification"; + public static final String PREFS_KEY_EXCHANGE_CURRENCY = "exchange_currency"; + public static final String PREFS_KEY_TRUSTED_PEER = "trusted_peer"; + public static final String PREFS_KEY_TRUSTED_PEER_ONLY = "trusted_peer_only"; + public static final String PREFS_KEY_BLOCK_EXPLORER = "block_explorer"; + public static final String PREFS_KEY_DATA_USAGE = "data_usage"; + public static final String PREFS_KEY_REMIND_BALANCE = "remind_balance"; + public static final String PREFS_KEY_DISCLAIMER = "disclaimer"; + private static final String PREFS_KEY_LABS_QR_PAYMENT_REQUEST = "labs_qr_payment_request"; + private static final String PREFS_KEY_LOOK_UP_WALLET_NAMES = "look_up_wallet_names"; + + private static final String PREFS_KEY_LAST_VERSION = "last_version"; + private static final String PREFS_KEY_LAST_USED = "last_used"; + private static final String PREFS_KEY_BEST_CHAIN_HEIGHT_EVER = "best_chain_height_ever"; + private static final String PREFS_KEY_CACHED_EXCHANGE_CURRENCY = "cached_exchange_currency"; + private static final String PREFS_KEY_CACHED_EXCHANGE_RATE_COIN = "cached_exchange_rate_coin"; + private static final String PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT = "cached_exchange_rate_fiat"; + private static final String PREFS_KEY_LAST_EXCHANGE_DIRECTION = "last_exchange_direction"; + private static final String PREFS_KEY_CHANGE_LOG_VERSION = "change_log_version"; + public static final String PREFS_KEY_REMIND_BACKUP = "remind_backup"; + private static final String PREFS_KEY_LAST_BACKUP = "last_backup"; + public static final String PREFS_KEY_INSTANTX_ENABLED = "labs_instantx_enabled"; + public static final String PREFS_KEY_LITE_MODE = "labs_lite_mode"; + + private static final int PREFS_DEFAULT_BTC_SHIFT = 0; + private static final int PREFS_DEFAULT_BTC_PRECISION = 2; + + private static final Logger log = LoggerFactory.getLogger(Configuration.class); + + public Configuration(final SharedPreferences prefs, final Resources res) { + this.prefs = prefs; + this.res = res; + + this.lastVersionCode = prefs.getInt(PREFS_KEY_LAST_VERSION, 0); + } + + private int getBtcPrecision() { + final String precision = prefs.getString(PREFS_KEY_BTC_PRECISION, null); + if (precision != null) + return precision.charAt(0) - '0'; + else + return PREFS_DEFAULT_BTC_PRECISION; + } + + public int getBtcShift() { + final String precision = prefs.getString(PREFS_KEY_BTC_PRECISION, null); + if (precision != null) + return precision.length() == 3 ? precision.charAt(2) - '0' : 0; + else + return PREFS_DEFAULT_BTC_SHIFT; + } + + public Coin getBtcBase() { + final int shift = getBtcShift(); + if (shift == 0) + return Coin.COIN; + else if (shift == 3) + return Coin.MILLICOIN; + else if (shift == 6) + return Coin.MICROCOIN; + else + throw new IllegalStateException("cannot handle shift: " + shift); + } + + public MonetaryFormat getFormat() { + final int shift = getBtcShift(); + final int minPrecision = shift <= 3 ? 2 : 0; + final int decimalRepetitions = (getBtcPrecision() - minPrecision) / 2; + return new MonetaryFormat().shift(shift).minDecimals(minPrecision).repeatOptionalDecimals(2, + decimalRepetitions); + } + + public MonetaryFormat getMaxPrecisionFormat() { + final int shift = getBtcShift(); + if (shift == 0) + return new MonetaryFormat().shift(0).minDecimals(2).optionalDecimals(2, 2, 2); + else if (shift == 3) + return new MonetaryFormat().shift(3).minDecimals(2).optionalDecimals(2, 1); + else + return new MonetaryFormat().shift(6).minDecimals(0).optionalDecimals(2); + } + + public String getOwnName() { + return Strings.emptyToNull(prefs.getString(PREFS_KEY_OWN_NAME, "").trim()); + } + + public boolean getSendCoinsAutoclose() { + return prefs.getBoolean(PREFS_KEY_SEND_COINS_AUTOCLOSE, true); + } + + public boolean getConnectivityNotificationEnabled() { + return prefs.getBoolean(PREFS_KEY_CONNECTIVITY_NOTIFICATION, false); + } + + public String getTrustedPeerHost() { + return Strings.emptyToNull(prefs.getString(PREFS_KEY_TRUSTED_PEER, "").trim()); + } + + public boolean getTrustedPeerOnly() { + return prefs.getBoolean(PREFS_KEY_TRUSTED_PEER_ONLY, false); + } + + public Uri getBlockExplorer() { + return Uri.parse(prefs.getString(PREFS_KEY_BLOCK_EXPLORER, + res.getStringArray(Constants.TEST ? R.array.preferences_block_explorer_values_testnet : R.array.preferences_block_explorer_values)[0])); + } + + public boolean remindBalance() { + return prefs.getBoolean(PREFS_KEY_REMIND_BALANCE, true); + } + + public void setRemindBalance(final boolean remindBalance) { + prefs.edit().putBoolean(PREFS_KEY_REMIND_BALANCE, remindBalance).apply(); + } + + public boolean remindBackup() { + return prefs.getBoolean(PREFS_KEY_REMIND_BACKUP, true); + } + + public long getLastBackupTime() { + return prefs.getLong(PREFS_KEY_LAST_BACKUP, 0); + } + + public void armBackupReminder() { + prefs.edit().putBoolean(PREFS_KEY_REMIND_BACKUP, true).apply(); + } + + public void disarmBackupReminder() { + prefs.edit().putBoolean(PREFS_KEY_REMIND_BACKUP, false) + .putLong(PREFS_KEY_LAST_BACKUP, System.currentTimeMillis()).apply(); + } + + public boolean getDisclaimerEnabled() { + return prefs.getBoolean(PREFS_KEY_DISCLAIMER, true); + } + + public String getExchangeCurrencyCode() { + return prefs.getString(PREFS_KEY_EXCHANGE_CURRENCY, null); + } + + public void setExchangeCurrencyCode(final String exchangeCurrencyCode) { + prefs.edit().putString(PREFS_KEY_EXCHANGE_CURRENCY, exchangeCurrencyCode).apply(); + } + + public boolean getQrPaymentRequestEnabled() { + return prefs.getBoolean(PREFS_KEY_LABS_QR_PAYMENT_REQUEST, false); + } + + public boolean getLookUpWalletNames() { + return prefs.getBoolean(PREFS_KEY_LOOK_UP_WALLET_NAMES, false); + } + + public boolean versionCodeCrossed(final int currentVersionCode, final int triggeringVersionCode) { + final boolean wasBelow = lastVersionCode < triggeringVersionCode; + final boolean wasUsedBefore = lastVersionCode > 0; + final boolean isNowAbove = currentVersionCode >= triggeringVersionCode; + + return wasUsedBefore && wasBelow && isNowAbove; + } + + public void updateLastVersionCode(final int currentVersionCode) { + prefs.edit().putInt(PREFS_KEY_LAST_VERSION, currentVersionCode).apply(); + + if (currentVersionCode > lastVersionCode) + log.info("detected app upgrade: " + lastVersionCode + " -> " + currentVersionCode); + else if (currentVersionCode < lastVersionCode) + log.warn("detected app downgrade: " + lastVersionCode + " -> " + currentVersionCode); + } + + public boolean hasBeenUsed() { + return prefs.contains(PREFS_KEY_LAST_USED); + } + + public long getLastUsedAgo() { + final long now = System.currentTimeMillis(); + + return now - prefs.getLong(PREFS_KEY_LAST_USED, 0); + } + + public void touchLastUsed() { + final long prefsLastUsed = prefs.getLong(PREFS_KEY_LAST_USED, 0); + final long now = System.currentTimeMillis(); + prefs.edit().putLong(PREFS_KEY_LAST_USED, now).apply(); + + log.info("just being used - last used {} minutes ago", (now - prefsLastUsed) / DateUtils.MINUTE_IN_MILLIS); + } + + public int getBestChainHeightEver() { + return prefs.getInt(PREFS_KEY_BEST_CHAIN_HEIGHT_EVER, 0); + } + + public void maybeIncrementBestChainHeightEver(final int bestChainHeightEver) { + if (bestChainHeightEver > getBestChainHeightEver()) + prefs.edit().putInt(PREFS_KEY_BEST_CHAIN_HEIGHT_EVER, bestChainHeightEver).apply(); + } + + /*public ExchangeRate getCachedExchangeRate() { + if (prefs.contains(PREFS_KEY_CACHED_EXCHANGE_CURRENCY) && prefs.contains(PREFS_KEY_CACHED_EXCHANGE_RATE_COIN) + && prefs.contains(PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT)) { + final String cachedExchangeCurrency = prefs.getString(PREFS_KEY_CACHED_EXCHANGE_CURRENCY, null); + final Coin cachedExchangeRateCoin = Coin.valueOf(prefs.getLong(PREFS_KEY_CACHED_EXCHANGE_RATE_COIN, 0)); + final Fiat cachedExchangeRateFiat = Fiat.valueOf(cachedExchangeCurrency, + prefs.getLong(PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT, 0)); + return new ExchangeRate(new org.bitcoinj.utils.ExchangeRate(cachedExchangeRateCoin, cachedExchangeRateFiat), + null); + } else { + return null; + } + } + + public void setCachedExchangeRate(final ExchangeRate cachedExchangeRate) { + final Editor edit = prefs.edit(); + edit.putString(PREFS_KEY_CACHED_EXCHANGE_CURRENCY, cachedExchangeRate.getCurrencyCode()); + edit.putLong(PREFS_KEY_CACHED_EXCHANGE_RATE_COIN, cachedExchangeRate.rate.coin.value); + edit.putLong(PREFS_KEY_CACHED_EXCHANGE_RATE_FIAT, cachedExchangeRate.rate.fiat.value); + edit.apply(); + }*/ + + public boolean getLastExchangeDirection() { + return prefs.getBoolean(PREFS_KEY_LAST_EXCHANGE_DIRECTION, true); + } + + public void setLastExchangeDirection(final boolean exchangeDirection) { + prefs.edit().putBoolean(PREFS_KEY_LAST_EXCHANGE_DIRECTION, exchangeDirection).apply(); + } + + public boolean changeLogVersionCodeCrossed(final int currentVersionCode, final int triggeringVersionCode) { + final int changeLogVersion = prefs.getInt(PREFS_KEY_CHANGE_LOG_VERSION, 0); + + final boolean wasBelow = changeLogVersion < triggeringVersionCode; + final boolean wasUsedBefore = changeLogVersion > 0; + final boolean isNowAbove = currentVersionCode >= triggeringVersionCode; + + prefs.edit().putInt(PREFS_KEY_CHANGE_LOG_VERSION, currentVersionCode).apply(); + + return /* wasUsedBefore && */wasBelow && isNowAbove; + } + + public void registerOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener) { + prefs.registerOnSharedPreferenceChangeListener(listener); + } + + public void unregisterOnSharedPreferenceChangeListener(final OnSharedPreferenceChangeListener listener) { + prefs.unregisterOnSharedPreferenceChangeListener(listener); + } + + public boolean getInstantXEnabled() { + return prefs.getBoolean(PREFS_KEY_INSTANTX_ENABLED, true); + } + + public boolean getLiteMode() { + return prefs.getBoolean(PREFS_KEY_LITE_MODE, true); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Constants.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Constants.java new file mode 100644 index 000000000..bde53a650 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Constants.java @@ -0,0 +1,302 @@ +/* + * Copyright 2011-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.utils; + +import android.os.Build; +import android.os.Environment; +import android.text.format.DateUtils; + +import com.google.common.io.BaseEncoding; +import com.squareup.okhttp.HttpUrl; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.logging.HttpLoggingInterceptor; + +import org.bitcoinj.core.CoinDefinition; +import org.bitcoinj.core.Context; +import org.bitcoinj.core.NetworkParameters; +import org.bitcoinj.params.MainNetParams; +import org.bitcoinj.params.TestNet3Params; +import org.bitcoinj.utils.MonetaryFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.concurrent.TimeUnit; + +import pivx.org.pivxwallet.BuildConfig; + + +/** + * @author Andreas Schildbach + */ +public final class Constants { + public static final boolean TEST = BuildConfig.APPLICATION_ID.contains("_test"); + + /** + * Network this wallet is on (e.g. testnet or mainnet). + */ + public static final NetworkParameters NETWORK_PARAMETERS = TEST ? TestNet3Params.get() : MainNetParams.get(); + + /** + * Bitcoinj global context. + */ + public static final Context CONTEXT = new Context(NETWORK_PARAMETERS); + + public final static class Files { + private static final String FILENAME_NETWORK_SUFFIX = NETWORK_PARAMETERS.getId() + .equals(NetworkParameters.ID_MAINNET) ? "" : "-testnet"; + + /** + * Filename of the wallet. + */ + public static final String WALLET_FILENAME_PROTOBUF = "wallet-protobuf" + FILENAME_NETWORK_SUFFIX; + + /** + * How often the wallet is autosaved. + */ + public static final long WALLET_AUTOSAVE_DELAY_MS = 5 * DateUtils.SECOND_IN_MILLIS; + + /** + * Filename of the automatic key backup (old format, can only be read). + */ + public static final String WALLET_KEY_BACKUP_BASE58 = "key-backup-base58" + FILENAME_NETWORK_SUFFIX; + + /** + * Filename of the automatic wallet backup. + */ + public static final String WALLET_KEY_BACKUP_PROTOBUF = "key-backup-protobuf" + FILENAME_NETWORK_SUFFIX; + + /** + * Path to external storage + */ + public static final File EXTERNAL_STORAGE_DIR = Environment.getExternalStorageDirectory(); + + /** + * Manual backups go here. + */ + public static final File EXTERNAL_WALLET_BACKUP_DIR = Environment + .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); + + /** + * Filename of the manual key backup (old format, can only be read). + */ + public static final String EXTERNAL_WALLET_KEY_BACKUP = CoinDefinition.coinName.toLowerCase() + "-wallet-keys" + FILENAME_NETWORK_SUFFIX; + + /** + * Filename of the manual wallet backup. + */ + public static final String EXTERNAL_WALLET_BACKUP = CoinDefinition.coinName + "-wallet-backup" + FILENAME_NETWORK_SUFFIX; + + /** + * Filename of the block store for storing the chain. + */ + public static final String BLOCKCHAIN_FILENAME = "blockchain" + FILENAME_NETWORK_SUFFIX; + + /** + * Filename of the block checkpoints file. + */ + public static final String CHECKPOINTS_FILENAME = "checkpoints" + FILENAME_NETWORK_SUFFIX + ".txt"; + + /** + * Filename of the fees files. + */ + public static final String FEES_FILENAME = "fees" + FILENAME_NETWORK_SUFFIX + ".txt"; + + /** + * Filename of the file containing Electrum servers. + */ + public static final String ELECTRUM_SERVERS_FILENAME = "electrum-servers.txt"; + } + + /** + * Maximum size of backups. Files larger will be rejected. + */ + public static final long BACKUP_MAX_CHARS = 10000000; + + private static final String EXPLORE_BASE_URL_PROD = CoinDefinition.BLOCKEXPLORER_BASE_URL_PROD; + private static final String EXPLORE_BASE_URL_TEST = CoinDefinition.BLOCKEXPLORER_BASE_URL_TEST; + + /** + * Base URL for browsing transactions, blocks or addresses. + */ + public static final String EXPLORE_BASE_URL = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET) ? EXPLORE_BASE_URL_PROD + : EXPLORE_BASE_URL_TEST; + public static final String EXPLORE_ADDRESS_PATH = CoinDefinition.BLOCKEXPLORER_ADDRESS_PATH; + public static final String EXPLORE_TRANSACTION_PATH = CoinDefinition.BLOCKEXPLORER_TRANSACTION_PATH; + public static final String EXPLORE_BLOCK_PATH = CoinDefinition.BLOCKEXPLORER_BLOCK_PATH; + + public static final String MIMETYPE_BACKUP_PRIVATE_KEYS = "x-" + CoinDefinition.coinName.toLowerCase() + "/private-keys"; + + private static final String BITEASY_API_URL_PROD = CoinDefinition.UNSPENT_API_URL;//"https://api.biteasy.com/blockchain/v1/"; + private static final String BITEASY_API_URL_TEST = "https://api.biteasy.com/testnet/v1/"; + /** + * Base URL for blockchain API. + */ + public static final String BITEASY_API_URL = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET) ? BITEASY_API_URL_PROD + : BITEASY_API_URL_TEST; + + /** + * Currency code for the wallet name resolver. + */ + public static final String WALLET_NAME_CURRENCY_CODE = NETWORK_PARAMETERS.getId() + .equals(NetworkParameters.ID_MAINNET) ? "dash" : "tdash"; + + /** + * URL to fetch version alerts from. + */ + public static final HttpUrl VERSION_URL = HttpUrl.parse("https://wallet.schildbach.de/version"); + /** + * URL to fetch dynamic fees from. + */ + public static final HttpUrl DYNAMIC_FEES_URL = HttpUrl.parse("https://wallet.schildbach.de/fees"); + + /** + * MIME type used for transmitting single transactions. + */ + public static final String MIMETYPE_TRANSACTION = "application/x-" + CoinDefinition.coinTicker.toLowerCase() + "tx"; + + /** + * MIME type used for transmitting wallet backups. + */ + public static final String MIMETYPE_WALLET_BACKUP = "application/x-" + CoinDefinition.coinName.toLowerCase() + "-wallet-backup"; + + /** + * Number of confirmations until a transaction is fully confirmed. + */ + public static final int MAX_NUM_CONFIRMATIONS = 6; + + /** + * User-agent to use for network access. + */ + public static final String USER_AGENT = CoinDefinition.coinName + " Wallet"; + + /** + * Default currency to use if all default mechanisms fail. + */ + public static final String DEFAULT_EXCHANGE_CURRENCY = "USD"; + + /** + * Donation address for tip/donate action. + */ + public static final String DONATION_ADDRESS = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET) + ? CoinDefinition.DONATION_ADDRESS : null; + + /** + * Recipient e-mail address for reports. + */ + public static final String REPORT_EMAIL = "hashengineeringsolutions@gmail.com"; + + /** + * Subject line for manually reported issues. + */ + public static final String REPORT_SUBJECT_ISSUE = "Dash Wallet: Reported issue"; + + /** + * Subject line for crash reports. + */ + public static final String REPORT_SUBJECT_CRASH = "Crash report"; + + public static final char CHAR_HAIR_SPACE = '\u200a'; + public static final char CHAR_THIN_SPACE = '\u2009'; + public static final char CHAR_ALMOST_EQUAL_TO = '\u2248'; + public static final char CHAR_CHECKMARK = '\u2713'; + public static final char CURRENCY_PLUS_SIGN = '\uff0b'; + public static final char CURRENCY_MINUS_SIGN = '\uff0d'; + public static final String PREFIX_ALMOST_EQUAL_TO = Character.toString(CHAR_ALMOST_EQUAL_TO) + CHAR_THIN_SPACE; + public static final int ADDRESS_FORMAT_GROUP_SIZE = 4; + public static final int ADDRESS_FORMAT_LINE_SIZE = 12; + + public static final MonetaryFormat LOCAL_FORMAT = new MonetaryFormat().noCode().minDecimals(2).optionalDecimals(); + + public static final BaseEncoding HEX = BaseEncoding.base16().lowerCase(); + + public static final String SOURCE_URL = "https://github.com/HashEngineering/" + CoinDefinition.coinName.toLowerCase() + "-wallet"; + public static final String BINARY_URL = "https://github.com/HashEngineering/" + CoinDefinition.coinName.toLowerCase() + "-wallet/releases"; + public static final String MARKET_APP_URL = "market://details?id=%s"; + public static final String WEBMARKET_APP_URL = "https://play.google.com/store/apps/details?id=%s"; + + public static final int HTTP_TIMEOUT_MS = 15 * (int) DateUtils.SECOND_IN_MILLIS; + public static final int PEER_DISCOVERY_TIMEOUT_MS = 10 * (int) DateUtils.SECOND_IN_MILLIS; + public static final int PEER_TIMEOUT_MS = 15 * (int) DateUtils.SECOND_IN_MILLIS; + + public static final long LAST_USAGE_THRESHOLD_JUST_MS = DateUtils.HOUR_IN_MILLIS; + public static final long LAST_USAGE_THRESHOLD_RECENTLY_MS = 2 * DateUtils.DAY_IN_MILLIS; + public static final long LAST_USAGE_THRESHOLD_INACTIVE_MS = 4 * DateUtils.WEEK_IN_MILLIS; + + public static final long DELAYED_TRANSACTION_THRESHOLD_MS = 2 * DateUtils.HOUR_IN_MILLIS; + + public static final int SDK_DEPRECATED_BELOW = Build.VERSION_CODES.JELLY_BEAN; + + public static final boolean BUG_OPENSSL_HEARTBLEED = Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN + && Build.VERSION.RELEASE.startsWith("4.1.1"); + + public static final int MEMORY_CLASS_LOWEND = 64; + + public static final int NOTIFICATION_ID_CONNECTED = 0; + public static final int NOTIFICATION_ID_COINS_RECEIVED = 1; + public static final int NOTIFICATION_ID_INACTIVITY = 2; + + /** + * Desired number of scrypt iterations for deriving the spending PIN + */ + public static final int SCRYPT_ITERATIONS_TARGET = 65536; + public static final int SCRYPT_ITERATIONS_TARGET_LOWRAM = 32768; + + /** + * Default ports for Electrum servers + */ + public static final int ELECTRUM_SERVER_DEFAULT_PORT_TCP = NETWORK_PARAMETERS.getId() + .equals(NetworkParameters.ID_MAINNET) ? 50001 : 51001; + public static final int ELECTRUM_SERVER_DEFAULT_PORT_TLS = NETWORK_PARAMETERS.getId() + .equals(NetworkParameters.ID_MAINNET) ? 50002 : 51002; + + /** + * Shared HTTP client, can reuse connections + */ + public static final OkHttpClient HTTP_CLIENT = new OkHttpClient(); + + static { + HTTP_CLIENT.setFollowRedirects(false); + HTTP_CLIENT.setFollowSslRedirects(true); + HTTP_CLIENT.setConnectTimeout(15, TimeUnit.SECONDS); + HTTP_CLIENT.setWriteTimeout(15, TimeUnit.SECONDS); + HTTP_CLIENT.setReadTimeout(15, TimeUnit.SECONDS); + + final HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor( + new HttpLoggingInterceptor.Logger() { + @Override + public void log(final String message) { + log.debug(message); + } + }); + loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); + HTTP_CLIENT.interceptors().add(loggingInterceptor); + } + + private static final Logger log = LoggerFactory.getLogger(Constants.class); + + //Dash Specific + public static long EARLIEST_HD_SEED_CREATION_TIME = 1427610960l; + + public static String WALLET_URI_SCHEME = "dashwallet"; + + public static boolean ENABLE_ZERO_FEES = TEST; //Enable Zero Fee's on TestNet only. + + + +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/CurrencyCalculatorLink.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/CurrencyCalculatorLink.java new file mode 100644 index 000000000..8aa511385 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/CurrencyCalculatorLink.java @@ -0,0 +1,209 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.utils; + +import android.view.View; + +import org.bitcoinj.core.Coin; +import org.bitcoinj.utils.ExchangeRate; +import org.bitcoinj.utils.Fiat; + +import javax.annotation.Nullable; + +import pivx.org.pivxwallet.wallofcoins.ui.CurrencyAmountView; + +/** + * @author Andreas Schildbach + */ +public final class CurrencyCalculatorLink { + private final CurrencyAmountView btcAmountView; + private final CurrencyAmountView localAmountView; + + private CurrencyAmountView.Listener listener = null; + private boolean enabled = true; + private ExchangeRate exchangeRate = null; + private boolean exchangeDirection = true; + + private final CurrencyAmountView.Listener btcAmountViewListener = new CurrencyAmountView.Listener() { + @Override + public void changed() { + if (btcAmountView.getAmount() != null) + setExchangeDirection(true); + else + localAmountView.setHint(null); + + if (listener != null) + listener.changed(); + } + + @Override + public void focusChanged(final boolean hasFocus) { + if (listener != null) + listener.focusChanged(hasFocus); + } + }; + + private final CurrencyAmountView.Listener localAmountViewListener = new CurrencyAmountView.Listener() { + @Override + public void changed() { + if (localAmountView.getAmount() != null) + setExchangeDirection(false); + else + btcAmountView.setHint(null); + + if (listener != null) + listener.changed(); + } + + @Override + public void focusChanged(final boolean hasFocus) { + if (listener != null) + listener.focusChanged(hasFocus); + } + }; + + public CurrencyCalculatorLink(final CurrencyAmountView btcAmountView, final CurrencyAmountView localAmountView) { + this.btcAmountView = btcAmountView; + this.btcAmountView.setListener(btcAmountViewListener); + + this.localAmountView = localAmountView; + this.localAmountView.setListener(localAmountViewListener); + + update(); + } + + public void setListener(@Nullable final CurrencyAmountView.Listener listener) { + this.listener = listener; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + + update(); + } + + public void setExchangeRate(final ExchangeRate exchangeRate) { + this.exchangeRate = exchangeRate; + + update(); + } + + public ExchangeRate getExchangeRate() { + return exchangeRate; + } + + @Nullable + public Coin getAmount() { + if (exchangeDirection) { + return (Coin) btcAmountView.getAmount(); + } else if (exchangeRate != null) { + final Fiat localAmount = (Fiat) localAmountView.getAmount(); + if (localAmount == null) + return null; + try { + final Coin btcAmount = exchangeRate.fiatToCoin(localAmount); + if (((Coin) btcAmount).isGreaterThan(Constants.NETWORK_PARAMETERS.getMaxMoney())) + throw new ArithmeticException(); + return btcAmount; + } catch (ArithmeticException x) { + return null; + } + } else { + return null; + } + } + + public boolean hasAmount() { + return getAmount() != null; + } + + private void update() { + btcAmountView.setEnabled(enabled); + + if (exchangeRate != null) { + localAmountView.setEnabled(enabled); + localAmountView.setCurrencySymbol(exchangeRate.fiat.currencyCode); + + if (exchangeDirection) { + final Coin btcAmount = (Coin) btcAmountView.getAmount(); + if (btcAmount != null) { + localAmountView.setAmount(null, false); + try { + localAmountView.setHint(exchangeRate.coinToFiat(btcAmount)); + } catch (ArithmeticException x) { + localAmountView.setHint(null); + } + btcAmountView.setHint(null); + } + } else { + final Fiat localAmount = (Fiat) localAmountView.getAmount(); + if (localAmount != null) { + localAmountView.setHint(null); + btcAmountView.setAmount(null, false); + try { + final Coin btcAmount = exchangeRate.fiatToCoin(localAmount); + if (((Coin) btcAmount).isGreaterThan(Constants.NETWORK_PARAMETERS.getMaxMoney())) + throw new ArithmeticException(); + btcAmountView.setHint(btcAmount); + } catch (final ArithmeticException x) { + btcAmountView.setHint(null); + } + } + } + } else { + localAmountView.setEnabled(false); + localAmountView.setHint(null); + btcAmountView.setHint(null); + } + } + + public void setExchangeDirection(final boolean exchangeDirection) { + this.exchangeDirection = exchangeDirection; + + update(); + } + + public boolean getExchangeDirection() { + return exchangeDirection; + } + + public View activeTextView() { + if (exchangeDirection) + return btcAmountView.getTextView(); + else + return localAmountView.getTextView(); + } + + public void requestFocus() { + activeTextView().requestFocus(); + } + + public void setBtcAmount(final Coin amount) { + final CurrencyAmountView.Listener listener = this.listener; + this.listener = null; + + btcAmountView.setAmount(amount, true); + + this.listener = listener; + } + + public void setNextFocusId(final int nextFocusId) { + btcAmountView.setNextFocusId(nextFocusId); + localAmountView.setNextFocusId(nextFocusId); + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Formats.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Formats.java new file mode 100644 index 000000000..590dae543 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/Formats.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +/** + * @author Andreas Schildbach + */ +public final class Formats { + public static final Pattern PATTERN_MONETARY_SPANNABLE = Pattern.compile("(?:([\\p{Alpha}\\p{Sc}]++)\\s?+)?" // prefix + + "([\\+\\-" + Constants.CURRENCY_PLUS_SIGN + Constants.CURRENCY_MINUS_SIGN + + "]?+(?:\\d*+\\.\\d{0,2}+|\\d++))" // significant + + "(\\d++)?"); // insignificant + + public static int PATTERN_GROUP_PREFIX = 1; // optional + public static int PATTERN_GROUP_SIGNIFICANT = 2; // mandatory + public static int PATTERN_GROUP_INSIGNIFICANT = 3; // optional + + private static final Pattern PATTERN_MEMO = Pattern.compile( + "(?:Payment request for Coinbase order code: (.+)|Payment request for BitPay invoice (.+) for merchant (.+))", + Pattern.CASE_INSENSITIVE); + + @Nullable + public static String[] sanitizeMemo(final @Nullable String memo) { + if (memo == null) + return null; + + final Matcher m = PATTERN_MEMO.matcher(memo); + if (m.matches() && m.group(1) != null) + return new String[] { m.group(1) + " (via Coinbase)" }; + else if (m.matches() && m.group(2) != null) + return new String[] { m.group(2) + " (via BitPay)", m.group(3) }; + else + return new String[] { memo }; + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/GenericUtils.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/GenericUtils.java new file mode 100644 index 000000000..f3b2a6aaa --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/GenericUtils.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.utils; + +import java.util.Currency; + +/** + * @author Andreas Schildbach + */ +public class GenericUtils { + public static boolean startsWithIgnoreCase(final String string, final String prefix) { + return string.regionMatches(true, 0, prefix, 0, prefix.length()); + } + + public static String currencySymbol(final String currencyCode) { + try { + final Currency currency = Currency.getInstance(currencyCode); + return currency.getSymbol(); + } catch (final IllegalArgumentException x) { + return currencyCode; + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/MonetarySpannable.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/MonetarySpannable.java new file mode 100644 index 000000000..fbc3ee6a3 --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/MonetarySpannable.java @@ -0,0 +1,114 @@ +/* + * Copyright 2014-2015 the original author or authors. + * + * 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 + * along with this program. If not, see . + */ + +package pivx.org.pivxwallet.wallofcoins.utils; + +import android.graphics.Typeface; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.RelativeSizeSpan; +import android.text.style.StyleSpan; + +import org.bitcoinj.core.Monetary; +import org.bitcoinj.utils.MonetaryFormat; + +import java.util.regex.Matcher; + +import javax.annotation.Nullable; + + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * @author Andreas Schildbach + */ +public final class MonetarySpannable extends SpannableString { + public MonetarySpannable(final MonetaryFormat format, final boolean signed, @Nullable final Monetary monetary) { + super(format(format, signed, monetary)); + } + + public MonetarySpannable(final MonetaryFormat format, @Nullable final Monetary monetary) { + super(format(format, false, monetary)); + } + + private static CharSequence format(final MonetaryFormat format, final boolean signed, final Monetary monetary) { + if (monetary == null) + return ""; + + checkArgument(monetary.signum() >= 0 || signed); + + if (signed) + return format.negativeSign(Constants.CURRENCY_MINUS_SIGN).positiveSign(Constants.CURRENCY_PLUS_SIGN) + .format(monetary); + else + return format.format(monetary); + } + + public MonetarySpannable applyMarkup(@Nullable final Object[] prefixSpans, + @Nullable final Object[] insignificantSpans) { + applyMarkup(this, prefixSpans, STANDARD_SIGNIFICANT_SPANS, insignificantSpans); + return this; + } + + public static final Object BOLD_SPAN = new StyleSpan(Typeface.BOLD); + public static final RelativeSizeSpan SMALLER_SPAN = new RelativeSizeSpan(0.85f); + + public static final Object[] STANDARD_SIGNIFICANT_SPANS = new Object[] { BOLD_SPAN }; + public static final Object[] STANDARD_INSIGNIFICANT_SPANS = new Object[] { MonetarySpannable.SMALLER_SPAN }; + + public static void applyMarkup(final Spannable spannable, @Nullable final Object[] prefixSpans, + @Nullable final Object[] significantSpans, @Nullable final Object[] insignificantSpans) { + if (prefixSpans != null) + for (final Object span : prefixSpans) + spannable.removeSpan(span); + if (significantSpans != null) + for (final Object span : significantSpans) + spannable.removeSpan(span); + if (insignificantSpans != null) + for (final Object span : insignificantSpans) + spannable.removeSpan(span); + + final Matcher m = Formats.PATTERN_MONETARY_SPANNABLE.matcher(spannable); + if (m.find()) { + int i = 0; + + if (m.group(Formats.PATTERN_GROUP_PREFIX) != null) { + final int end = m.end(Formats.PATTERN_GROUP_PREFIX); + if (prefixSpans != null) + for (final Object span : prefixSpans) + spannable.setSpan(span, i, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + i = end; + } + + if (m.group(Formats.PATTERN_GROUP_SIGNIFICANT) != null) { + final int end = m.end(Formats.PATTERN_GROUP_SIGNIFICANT); + if (significantSpans != null) + for (final Object span : significantSpans) + spannable.setSpan(span, i, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + i = end; + } + + if (m.group(Formats.PATTERN_GROUP_INSIGNIFICANT) != null) { + final int end = m.end(Formats.PATTERN_GROUP_INSIGNIFICANT); + if (insignificantSpans != null) + for (final Object span : insignificantSpans) + spannable.setSpan(span, i, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + i = end; + } + } + } +} diff --git a/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/NetworkUtil.java b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/NetworkUtil.java new file mode 100644 index 000000000..63958072c --- /dev/null +++ b/app/src/main/java/pivx/org/pivxwallet/wallofcoins/utils/NetworkUtil.java @@ -0,0 +1,18 @@ +package pivx.org.pivxwallet.wallofcoins.utils; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * Created on 15-Mar-18. + */ + +public class NetworkUtil { + public static boolean isOnline(Context context) { + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo netInfo = cm.getActiveNetworkInfo(); /* NetworkInfo mWifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI); if(netInfo.equals(mWifi)){ if(mWifi.isAvailable()) return true; else return false; }else{ return true; }*/ + return netInfo != null && netInfo.isConnectedOrConnecting(); + } + +} diff --git a/app/src/main/res/anim/activity_back_out.xml b/app/src/main/res/anim/activity_back_out.xml new file mode 100644 index 000000000..4344ae837 --- /dev/null +++ b/app/src/main/res/anim/activity_back_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_backin.xml b/app/src/main/res/anim/activity_backin.xml new file mode 100644 index 000000000..592e2417a --- /dev/null +++ b/app/src/main/res/anim/activity_backin.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 000000000..515f2d13d --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 000000000..121148922 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_account_balance_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_account_balance_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff265a49172eff0f2b0ede94ab364bbabe33cf2 GIT binary patch literal 216 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 j&;Bk|4Z90QL_=Wx1(=2w%WV8}UQ9&qx2 zYfq9{n@pQH&;NrTEGL|8^EVWBwmDooA&7;ebNhAYlLndxR~FP2J7L5vC8bvG?`phsgi{IPA^_CMXkaEwCNJ zP0;2KM$pI2{f-R)$jJM++t|6nP;9m^M`yS!`~HV^b~a~wS$1P_ZDDP9C76@5njaDd z_0uu1^K-QW*|W>bvB~&=?*!anC>u5(x94zAu#YVJzjVQO^FL-GcD8>(P_DA<{~eTx zwl13z0tsUi7Zeq+69xj=BqRiZV&W1KKz=q6VW5bR@ZBvT02Bj@OMpcr+5Ua8-+4pY zJAm~eD*yI%w~}RdLZRHjLPBUXS`aNNh(J0D0YM4;f1ujE1UzzA6M>RB_zxSg+Ll05YPY4qOKDH zh46GjxU(riCDTpk#4crc<4v}TQQxJ4^wg;=Ihzl!2Bo#zO z#Z-VmWhp5|aY-o=aTSoFm?-eh@HZENu=8?*!BKy6?f-|X_>bH_t>ET<=NSS+I(x(H zRgefbwtpQN?EKHMNd2SUzq$7R91G|lxk7ir2>mJS|0?v~rn~O>GyPB7-Yx#q_%Qfg zw4}uXoX6! zdYt-sZR=9BvE!A5_(naqq~IM^`gyeVC_p)0$)6yVyo`O>);|qw%tdH5j#Ee72#Xx~ zj-XTi966%XWqbsvEDCB|Zpa>!!7LHX=B7owbHXy6z!uXii5kOhF&9XBKqK&^o^!$C zad^9E^UtI|`z=b>Q6m*yOZAZrQbyG;zD=kNQ3Cvv^T(1WgUDs+6%$@>!TqEuGpIK{Y~-O=A{UnU&+2_CAvI@Kbi5E+8$ic zl9a@)1oUuWI29)&90)p=xIjl6Xk#$Nke%48lY|{!Ue{A2q#GwP&q4&`r1`;Qw7zeP z?#YflYjDO?^6}FUFA=m|1x2yBjNg+3=kZ;^s?akR2TAS?KeZ~YW4}YzRhj_>p z6AP>{MpnI-@}=l$TlDmz7=z*;1I8oSA%J7hQym$N6(T&S9cF#N zx=dAXG3i2<&`HiZO!RFs2Xh`}jxWZr{xvqX;IJ;I_vDu??!(0-#lY1Kt>j?yCa%1t zr&Yd!&Q!i=Uj9Ks#q@(QzNzFxi?Z(6%7@l_y0hWXrIkG!Vr&rW&_?DjoBhI2FOf<2 zrhQ_JJb^6Fs4rJPW}G<=OMD*tu$n77*V(KY#1s-(xq^jkqWvR_6i zAa7yiV9Z6>^Gg@ARA4P0h;ZjaPbYQus`(MZ*MlIyY1^0t zX6biQ@v2NyfqXcYabM7@7Ap>9S@QgOem3j+L+X4SR=H27_~_s+tQp1J<8n1qK0P&S zMMRsX@M+hYdnQ(B(Ojlr1P7N5F$pFMI96+vp5=ap#vvm~-MFeAT!|hR=OxHMh>nHm zXGKkTd=U7g7hRyVb8w1--RnTaq?Oeft8MJI%MK7XqS?!;&2zE9mn=?=;ZO9@-zJ9Q zY@H<6M^s|RAj9X|6U{GZi`_oytPaF+MBZy-Z9)}4HMnwar zJav`}IgeKrDPv|?idoHOvZcf~47u(fcRc|nN*zEI6Yjk)v`D8?B@IlXe_H26VF)+K(4h%Q*|1DJ;I$y#Lj zc(f9|()hMvg8j9)^iOFbg?>j^j64WuGMeHfPIc z<|+xcT?T+4*SJ%fD@|9fa91Ak*61IzGo3K1Q^WkhUsL{q%4oK~6*&{MHp~A1i!Qdry%& zNLf`re6caQJvhbjdBVjT9_;Fr>zG#jFluO}Sv7kGoeUz=eVIj*mbHkW_jgMTMPJ59 zk^&<}9s~v|3tBbMqq%91tDg*$AGB63?os=PDclqiaZ_!r2B}jvtD5 z058L|lmb3uQQ}JbUd5l+2|$}o(m7j5-Fk#s2MVCgiKs;e@L}c@TBlUUBPJwB7f_)M zB(R7kJOr%E^GL|oz%Soi1kww9-KMHcxbI#KhlY2R^Dm!tLGX{TkNww5zr9rOEzBm) zuSrpmJrivHNrXHID7_>zEd;nEh3LmE2E1%sP@lm1E4=J0D>OZ<{4h(8H^+SjF~OHk6Q^2{$V-Kt=RVf^CpcAAmQ-uaBdzzPVFp&3wPkb z7`|cCX! _8qR;R5J??rJxI%aN;OUZb}`ZQU%HG%F1{msdpg{jcVF(e}5^bD+mW3 z)n=o6c1UBbWLCJ4q6Ml5QHp7^(#YDBMI|>tWD~KxP@|mz*kpa{ zO2{t=C+iA($J{NCxk#i1&z7~+%?@b%FW2;mv&`KCCSn>b9h?+66F;4pT}6Hem{Jx9 zAeVprxfL+o=K2YOH|5*h&0=ljI0pDZ8DkYpnGm$xjIdp#RXDKJca*>fm=_e=5;M4e zC)n;!z}R=i%+qPj>ZyV~>#_(7pbYwwp9lD-dZ(RZh)cRNO9gYxqrXeNn3urrWB00} z7g#mH?fpz0Yx==Gh|#n+-E4MSOMb|$O^H=3yyaK|8PHdh*iZ?5sN7hvGN?*HKc)n? zRRc5nImm>nz(;6yT9W^YYe@1BdJ-7pKl5mI_QlG)D!s$*FyPY$@uBR~Yx+@Hl1y|GzUUISIYsGr^z`3_oA@Oaf?>Z)Fr#-%|XIVlCq9a$CuiIbVILds=EY2}D z3Asr+#7sIXcuORbY5c73fTVEe_9KSm+q!hkl#xy}$4kvj{Ki>*GR0=}@UFqLNxP~3 zLb;EI^LWN@S=S9^1I*9r9eH9Be}(99=6gBK?HTmqgYRM5$n4Ze?$Pxo+O>#2&W8%o zP8@?qE{7AeE9wSZ>MZwP=;6~Kgl>8b=GTx`XYcb`0RB0Lyo&EBOjm0IY}hmLKK8|E z&z%qZe#^~OEPkkoh2^!$JrwW~2KhYlhIuulU*vV#mKm1_ku9S<;*-;U5QE!%^d|}u z{xb`0=K@UxoV;>C&4)BKU4|_u~19s-j^q_h(>H4QJp>i8X3pX=L`-!`OW-B2<+7nNnJW)*0f|MTM*Sm`933>8R*o*l~Tk`vznyZYutfPVMW)^ zY_Kol9E#QPzwfZ?yzcGhqFC@UdnGxt<`;4jrTMk{Tn7E9P1-)Z6jf@m=VjCYq$LbJ z51Lxg3%!Tc%JWHbATIK{KBY@d5@qBvZNz@clsDw33-)k zof$cZmntmfr;vAu$mj{2K^9dthH*cg8iJ0*P9)$1XrKZJCDj7^6^Aoj}vP>u_Mt~E9yjv zBHUV@y_X%XxP3SrfV7HI*A&;R^&C25w3NH{%VhoN!SI%^oaN;qhp5YY<8(1WopwDv`U-+ZD3|KvC0#Us z$CEl2s}g8Q;jpAn94yKS#wwFG^?IGWd6q$gfAWqM_@yW=6Zv7TT? zK|G{8%epSP7Y$`~RU!^AEvps(MV(UqG)y!H+ZCK%W}PH++g(6ZGHR8YgFWb;6%8Eg zJWtF``%q>(XYQ`Gb1YxjFaX-)fj@0vCfMb0JLIITiGQLh%I}~!<@|M|PQ{7;17mwE&B>C`-uh8hONFAsh5-uq~q zs$t*5VeAUIxMDP{|Bke6YAN}E%rG8k=9>m>Mk;L22O)1ba>KvuJpJm?F#W(@knK(2 zizzF?*J6WfTp$DJRKzxX!}j|AOhTKT zho>~sRJC~>>c#Yvp!ul)p21#1YR&j)a0d>RLQF>~fSJ@88Ik!Wz=h^k^*E=86$_w_h~HoR&- zVq+k6Kpc&hdx2plK z9$aiy2aCyn%rpzf9Xjy!8{61-?s~6MWFBzAr=;Jrfna|k1=8`6mnCV8It@(}=Z}(( z!2)Y<=M+n^#=T|v)r6=2YnS3)_g_U>u6lH9*k@Nx%ba>M4#Msxuj~r{YV7Fgd*-0* z-C;A*E?9S3Yuor!d)UlzuFiW#p+$r)GaNtAlqGo-r{~kNmeuC3H`&02{UnK_VwP-{ zBs#hFnRcgrN&VsvQ$Gd7G@Ray^`vvBUT(iRFM89F;)s=Cc%<1FiI+dRl!&Lz!)H+P zSIcXzi%U(*eMd*=ZqaeY8$IiW+}%SkO$NO^lW^4gZ8tSS%8wl?>Ctv-zob(z3DgI; zfj3D3Pt?7bM*K;(dbqg!EH)`X-hFG48&khgP zw;fc6cDYZ*+|2oi*kzzn=t{uR@A8kQ;oX`tsN;tfi!62i`Wwbj&5X30hRie83AbID z7hl_BbE{6jL?>Q3l}3A7)Xw7bYML?Vx>#uJv6Mpi!F7L4g;Ie&L)x&Mw2shB^Qxiy ztyV|BhZ4-Fh^;NZSXO=C+>EPOkuACzR+RKeuzJ+q9@h8OhMn&fA1|}VN3U?CjBymZ zsBIWNPS)yKj?oo0_?W~JIs&QY$Q)jA=DNVqeg9GA~+5S4!oAXV}ZPf=bu; z4uypgGqowAiP=ksuk$Eh4dp;N@qb**7j=r^tdyA@a-2X;W}L>Ox z2lD&xV|_ndvM%8Mam&83UZWG09lf_tP906!zVwM@zqn{AfI+7>J40~Ay@Hu9 zEL6OXng)anj*c@4)bLo=(QLQ%RfHW2e_q+woZ7E|cw8$k&T5Ouq&*n_q49S~w4uqQ_6B^MrVq4?v8Uwess9Is-dZgM2qtdmAro>M0CC?cgsi&TW=Qd zOLW2A)^X%@5&5KmHtlihQ!2Yzn7|rwsYu&Cvj+t&PFS@BY>8+v%a4+bDI?oCwn20+ zpqog0%H4B~&q~oGTgRswvqygRSJ-o^j!ad-*C{&!(h9ep?|_L2#%5}PgLTt=$BN76 z{i?wYH9s~PbT5<9R(kh$lTW&=ZaN_P4jqrskp_vQWWU>+BXFI>sTqf1o0{>hs)pSj z0U_ITvJ_~Ozg!A}s?+iJ^|NuJd%Gn<=_7sq`o z%1CO0vm)l|KH`CeDsNr#OApPqE1-P8@GNTLKIhGbZt*unfpPcjBO^>=RXfp`k+^Nj zqIC>zNp3AeNl1-6<;tP%u4zQR*t-hl;wjN_sQ-m1GSysK9Q=UPLoCX#6nCWr9Ha_vhI$?g88ES;!QGOMG2 zxN^r*i3WG-MjQ0Is6p{YsM|;9E>?nm%+zGKQ(iY_3EH}SkRehn*=%C*G1YKAuEbb@5ay*ynGo-pKu4bIOon(EYYP_>b69X7-wwOyZ-Pq& zN3(zjcvSpMH*9T2T^#0Atx&u^aX4$d--u7JmZInR`4lLMrj~_HxVtf8v!~+Z*=pH7 zJ#zN}#gg2uKXG&AO5Z+*mkRl+f%k45UBMA`v8YUJa)m@%P=oO^`q(|lk-fiWUG)*b z?^X28&?8ApTU$pxx+urbF63Z{#nD^NM&q&&?I`uv`X(w&M(7Bhio3~DKHCy7qbh0sbbB?<6 z32C?Q-B+vn2HtblqxmqIk%(&AD#=jbwr9VyPo4)?c4WRMvfc2yLFagj#w(z`R*9H% zUUNXL$2#xf=*I|;P#UV0trR>W=NKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0004yNkl(v}vqF)ha+Rb|%7H{VI!QUWN;xSmN)Ad%dr&Bc zJyY5(S0@K?*^^CC3I`5aJ1%cC*1R`wGBa)ZeQRo(-|M~4d%y3z-|MAZ*QH*Rrj8^q z0wXX2BQOFZFajem{}raO`qHtSH?>;@9H0{6*iFDAkOkgKo1@<_22B9#F)qjwFb))L z(liruc6xvl8_%SHu>|bWX9F__v?Tyj{$XH^E`g~Cj9UgWz>#Lm2OF3h^+cg|!+1GA zmiZI8NDz4+^uRz>x%D<>boX%NhX+MwdrcF^IfKOvA?U?m7KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0007sNkls_pr2JrBFcyEA^;?TJWF;PwGKERFp1)g4$KrKWTUKyo|8MCe2C`u*?sZ$>x{L z%r`T6dC9J*Dhp8!EKpf63ueJAm<6+77R-WKFbihEESLqeU>3}RS+M^|i{h+o&B^;= z_GzFI@M3H-1H1=DfN#bA&Sbzsv==y=VExB|-N0npOYuO$^|u1o)4s+UfL$rH)0Q^a zAz*b1?NkyA9szm`?2jR6RDfpSYCyl=r49DneBw|`NT0|50PF4TJt87oMPxIu4#=u% zMnpcU>ceWadR|qh9LG5(B6~z+qpHq`$SdGRxm?Z<4-fwUXgP5Yzya1roS{ZD($f*a zE`)fOYrjY?mka$JNmV@&ae<})|52q<=_nKmGX`u3=&55C)&j){$29|A0=y5vs$zeq z7dd!{NJ9{m@!K<*Oi#@W9IXTDNkk}s9UD;5fculam_+Vi|VpVc%lFz{?}aPZR{-X>EH)fo(~)NyP_ z!2Y+uMC4qtR4TpBX0x@svLW6IQ=VCZoB2s&d7e%#2BzwO>IRkvcy|De3^qDC>gIAe zf5JJZCn65O!RoD>fQ~s`Zp^ogeIed>;@Lg00eET3*11NqPI;z}K`Ge`a63sbt(jE? z9+;bH(#oguJT~TZJq5O<1oZ+qmGl#|)NJoe0csLxPvh0VZ?L7nxrCuE0$YGmYOe-N z=5Y!59z)>p58P*S?M_5G!T#mQf>|&N_AmN10JsaX!(;IZ6951J07*qoM6N<$g4VfM AZ~y=R literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/currency_symbol_ubtc.png b/app/src/main/res/drawable-xhdpi/currency_symbol_ubtc.png new file mode 100644 index 0000000000000000000000000000000000000000..680316a7bba6cae9ed479138fd67e2c6bfab698d GIT binary patch literal 728 zcmV;}0w?{6P)-wJvQpGQICy!Y}8|;9vk)8sK-V#^eEVwCBZ z-rinDeDYtud|{b2Yt~<|t)+WF6f+Pj5*b76(2#ylq{n*k$StI59^>Zb=F82^WkwR3 z48*sA_%0C`6q7teS_MjmVL0U80Pz*7dW?~g@e?a6s{&FCq>-Tg0uVnYQmq{xxw+^m zgkp~Ylj`69h}lCcXi{XLLefG9DR|^|Q?;!Kj4c@RE0pdh(TF7^sCC34{uGG!(WA~tR;+M7g!@2IAt0bGqzso>v9qlgdu;?ZYwnscL;!eYmJStmF)97;dWoB8q--~2$EpsXj}rkZliXKn^5+OE1`aJa+! z5Ub$}pC)g8zHGk}4Sj10UI+v$DQk89)L7)86C!ZYOJ^DLT;Dm9!k3lHUSI^F84OGN fr}IgeYQExQm|)DeRKEEQ(De+Su6{1-oD!M004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_00E9kL_t(o!|j;QN&-O~$5-&Aii={2fjLA`+}b}f8^ zFrkmd{vF%~Dx>kt&_;g&Ajegze#WzUbGh?i`s3epo^&S*ZE zQxlxxHODG~%$Swq7R!A-xeICzOp7cr;^b&Mx{AD@;lL+`UDBbrloxaaMAp{kh4x8a z&=(LfTWbpKm%QLpK*T2sdh&ut0gsY33@|c(u9C)b7 z3zm?{qRLj$@{Dh)?L{Tef*mzMf_G2&w~=pL@;o^3B-mF!aAtU&ihmhdz6wX??o>g^ z-XWH2s^Bg(Q%C*2mYH?owKQP>#OP= zek0Uv_&O2Y<9mwxA^wh35ch)>x_=|@a!?nLO)M-5LEdo6l*2okfq`m5fj&X_E8#x{ YzxHNbhFXLe-v9sr07*qoM6N<$f|+075dZ)H literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/wall_of_coins.png b/app/src/main/res/drawable-xhdpi/wall_of_coins.png new file mode 100644 index 0000000000000000000000000000000000000000..c4160e6b44f9ad5516cd5e4c5e015119d5ebbb54 GIT binary patch literal 16707 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 Jk~R004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN 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 Q{(yu$UHx3vIVCg!0B7EYTL1t6 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/wall_of_coins.png b/app/src/main/res/drawable-xxxhdpi/wall_of_coins.png new file mode 100644 index 0000000000000000000000000000000000000000..722734d3dde1b822d01833f744631f907f27e924 GIT binary patch literal 36571 zcmaI7byQnX(=Uumao0i!?(XhVyc8)8p}4!dYk<-gD=wv2ptwUJK#>+GUL;71yUQ2a z=Xvk<$9->B*2>9Qvu9?{{PxW3edfe#YbxVBqkM*dfPkZ_qM(a_fP{^JfEb2>2EWrw zEyfG~q3}{P^m^&~#>>~z!v;YX zPXD!{ww&g0;UPD7n)y31x(#6_FRY4L6=fGue4-!-4 z6%i2-Q4-|m7f|BmRTPmG?vmhE-f zWV5ms4#08hy<1#fUap>tj<1N*wJNaEQ8NUjtIb|Y`Tn}6p3PepC2DVIpE$kk+=EpzxEU42~MED9Ig+jFrKJXWX ztVHUeEIN#csBl0WvC(ff+SCN6gByQCIQ`VT7>aD>GyNxe7Kq#DprCvu(y#}o=Mexk z%xNBc1)d^pc_|ls(V=2!pc7*RK!qG5qUFT~D79OIGTuf$z$81G z1L1J?Gj(GGry@QICbDcMw~>g7R1H+eiN`nrfI)~B!D0?U@Ewi~CVoEt6Zlu9kqnOM ztW+`u%1surmmqB8q|-F@{1VLuDuK;S=lTkgpgK082pJ z2|bpd@&Q@ppVPG3IR_NkG`PmsYbf9`j*$!=d=%L}8T`#CxMrWNJleI}>J2xTo2dVB zGZQf`d8>HsF366~Y1=^Xm((T#PAULS<>$c5>B*x1ryW+XBBe3SDSb}zKfQ=JsD2cu z1m%*hPMXgJ{70lkDEJjJ^(9qK%0D8+ifwtWT>PUm>4s>`2$ok*{;-iF*3U{ERTLtf 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 S_K6n&0000hup literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/bg_selling_btn_selected.xml b/app/src/main/res/drawable/bg_selling_btn_selected.xml new file mode 100644 index 000000000..5146b9dea --- /dev/null +++ b/app/src/main/res/drawable/bg_selling_btn_selected.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_selling_btns_deselected.xml b/app/src/main/res/drawable/bg_selling_btns_deselected.xml new file mode 100644 index 000000000..19d8dfd2b --- /dev/null +++ b/app/src/main/res/drawable/bg_selling_btns_deselected.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/border_selling_edttxt.xml b/app/src/main/res/drawable/border_selling_edttxt.xml new file mode 100644 index 000000000..3183dd6d6 --- /dev/null +++ b/app/src/main/res/drawable/border_selling_edttxt.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/divider_currency.xml b/app/src/main/res/drawable/divider_currency.xml new file mode 100644 index 000000000..340fe36e6 --- /dev/null +++ b/app/src/main/res/drawable/divider_currency.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/download.png b/app/src/main/res/drawable/download.png new file mode 100644 index 0000000000000000000000000000000000000000..bc5de272d234c56da6d5040dbf7e2649da131b40 GIT binary patch literal 373 zcmV-*0gC>KP)YKj3`8F-0V(xwMBOa#&Ge7r0~nyn0Q{H~yLOXJQe{~<>@>{~)Q}vSco5giBNV;{ zi~^vAGgi~BLY_4Vx+EZR_H2@(tW;(b=-YlAu&qCV@(=KMl~#*qQvL?svqOI>0h-xIjZ>?rEud#oI*h2I_(U5vsLz!PtQ!i(k!3TG(s9J-5SRMq63 zjHJYyR*SM3dmZS_`kvo{%jOd(ABMtns7c^0U?}T;C-EFh61c)!UGFsAwVFdMsOue? zBrS$+(k)bMa@s))>^Rx;I!b43IG}Ka7tPogwwYN6hJen=o<$q*=GjiYO*=@u=yy6` zIMCluIPKq4{uR!lrVmqH=^odoKPk*aT0o9<9kigxQGeb$NUKHRF1G*I=r8dTdHd9E T@g#%900000NkvXXu0mjfW}~P} literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/flags.png b/app/src/main/res/drawable/flags.png new file mode 100644 index 0000000000000000000000000000000000000000..471e6f74afc360702afb9a2a638da967591a1dba GIT binary patch literal 77098 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↑*2zJSi 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⪼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�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 Q?;syJDP_qTanq3h0W2oU1poj5 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_action_search.xml b/app/src/main/res/drawable/ic_action_search.xml new file mode 100644 index 000000000..47432c174 --- /dev/null +++ b/app/src/main/res/drawable/ic_action_search.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_back_white_24dp.xml b/app/src/main/res/drawable/ic_arrow_back_white_24dp.xml new file mode 100644 index 000000000..38fbc261b --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_back_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_clear_grey600_24dp.xml b/app/src/main/res/drawable/ic_clear_grey600_24dp.xml new file mode 100644 index 000000000..01752ddab --- /dev/null +++ b/app/src/main/res/drawable/ic_clear_grey600_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_dash_d_white_bottom.xml b/app/src/main/res/drawable/ic_dash_d_white_bottom.xml new file mode 100644 index 000000000..2503914b8 --- /dev/null +++ b/app/src/main/res/drawable/ic_dash_d_white_bottom.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/ic_menu_sell_dash.xml b/app/src/main/res/drawable/ic_menu_sell_dash.xml new file mode 100644 index 000000000..cd5b80da1 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_sell_dash.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_more_vert_grey600_18dp.xml b/app/src/main/res/drawable/ic_more_vert_grey600_18dp.xml new file mode 100644 index 000000000..9baa3357d --- /dev/null +++ b/app/src/main/res/drawable/ic_more_vert_grey600_18dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_warning.xml b/app/src/main/res/drawable/ic_warning.xml new file mode 100644 index 000000000..12817b42c --- /dev/null +++ b/app/src/main/res/drawable/ic_warning.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/selectable_item_background.xml b/app/src/main/res/drawable/selectable_item_background.xml new file mode 100644 index 000000000..e59b30091 --- /dev/null +++ b/app/src/main/res/drawable/selectable_item_background.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_edit_btn.xml b/app/src/main/res/drawable/selector_edit_btn.xml new file mode 100644 index 000000000..3ef048e0d --- /dev/null +++ b/app/src/main/res/drawable/selector_edit_btn.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/selector_selling_btn.xml b/app/src/main/res/drawable/selector_selling_btn.xml new file mode 100644 index 000000000..5df93ecf2 --- /dev/null +++ b/app/src/main/res/drawable/selector_selling_btn.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/stat_notify_received_24dp.xml b/app/src/main/res/drawable/stat_notify_received_24dp.xml new file mode 100644 index 000000000..cb96bd1ff --- /dev/null +++ b/app/src/main/res/drawable/stat_notify_received_24dp.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/src/main/res/drawable/white_progress.xml b/app/src/main/res/drawable/white_progress.xml new file mode 100644 index 000000000..e30c0fec1 --- /dev/null +++ b/app/src/main/res/drawable/white_progress.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_base_selling_wizard.xml b/app/src/main/res/layout/activity_base_selling_wizard.xml new file mode 100644 index 000000000..d29c5ddcb --- /dev/null +++ b/app/src/main/res/layout/activity_base_selling_wizard.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/app/src/main/res/layout/activity_buy_dash_base.xml b/app/src/main/res/layout/activity_buy_dash_base.xml new file mode 100644 index 000000000..be5647d53 --- /dev/null +++ b/app/src/main/res/layout/activity_buy_dash_base.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/app/src/main/res/layout/buy_dash_offers_item.xml b/app/src/main/res/layout/buy_dash_offers_item.xml new file mode 100644 index 000000000..26c61fa73 --- /dev/null +++ b/app/src/main/res/layout/buy_dash_offers_item.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +