diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 97faf649..b2692466 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 34 - versionCode = 202503031 - versionName = "v4.3.1" + versionCode = 202503221 + versionName = "v4.4.0" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") diff --git a/app/src/main/java/com/brainwallet/data/model/AppSetting.kt b/app/src/main/java/com/brainwallet/data/model/AppSetting.kt index 0c471167..6510f7c2 100644 --- a/app/src/main/java/com/brainwallet/data/model/AppSetting.kt +++ b/app/src/main/java/com/brainwallet/data/model/AppSetting.kt @@ -5,7 +5,8 @@ data class AppSetting( val languageCode: String = Language.ENGLISH.code, val currency: CurrencyEntity = CurrencyEntity( "USD", - "USD", - -1f + "US Dollar", + -1f, + "$" ) ) \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java index 769df269..f0c31051 100644 --- a/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java +++ b/app/src/main/java/com/brainwallet/data/model/CurrencyEntity.java @@ -11,11 +11,13 @@ public class CurrencyEntity implements Serializable { public String code; public String name; public float rate; + public String symbol; - public CurrencyEntity(String code, String name, float rate) { + public CurrencyEntity(String code, String name, float rate, String symbol) { this.code = code; this.name = name; this.rate = rate; + this.symbol = symbol; } public CurrencyEntity() { diff --git a/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt b/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt index 024aa52b..2e4b3388 100644 --- a/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt +++ b/app/src/main/java/com/brainwallet/data/repository/SettingRepository.kt @@ -86,8 +86,9 @@ interface SettingRepository { currencyDataSource.getCurrencyByIso(it) ?: return@let CurrencyEntity( "USD", - "USD", - -1f + "US Dollar", + -1f, + "$" ) } diff --git a/app/src/main/java/com/brainwallet/di/Module.kt b/app/src/main/java/com/brainwallet/di/Module.kt index 152ec64a..69371158 100644 --- a/app/src/main/java/com/brainwallet/di/Module.kt +++ b/app/src/main/java/com/brainwallet/di/Module.kt @@ -7,6 +7,7 @@ import com.brainwallet.data.repository.SettingRepository import com.brainwallet.data.source.RemoteConfigSource import com.brainwallet.tools.manager.BRApiManager import com.brainwallet.tools.sqlite.CurrencyDataSource +import com.brainwallet.ui.screens.home.SettingsViewModel import com.brainwallet.ui.screens.inputwords.InputWordsViewModel import com.brainwallet.ui.screens.setpasscode.SetPasscodeViewModel import com.brainwallet.ui.screens.unlock.UnLockViewModel @@ -36,6 +37,7 @@ val dataModule = module { val viewModelModule = module { viewModelOf(::WelcomeViewModel) + viewModelOf(::SettingsViewModel) viewModel { InputWordsViewModel() } viewModel { SetPasscodeViewModel() } viewModel { UnLockViewModel() } diff --git a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt index 854ceec3..b50bef17 100644 --- a/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt +++ b/app/src/main/java/com/brainwallet/navigation/LegacyNavigation.kt @@ -5,7 +5,6 @@ import android.content.Context import android.content.Intent import com.brainwallet.R import com.brainwallet.presenter.activities.BreadActivity -import com.brainwallet.presenter.activities.LoginActivity import com.brainwallet.ui.BrainwalletActivity import timber.log.Timber @@ -25,7 +24,7 @@ object LegacyNavigation { auth: Boolean ) { Timber.i("timber: startBreadActivity: %s", from.javaClass.name) - val intent = if (auth) BrainwalletActivity.createIntent(from, Route.UnLock) + val intent = if (auth) BrainwalletActivity.createIntent(from, Route.UnLock()) else Intent(from, BreadActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) from.startActivity(intent) @@ -35,6 +34,17 @@ object LegacyNavigation { } } + @JvmStatic + fun restartBreadActivity( + context: Context + ) { + Intent(context, BreadActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) + }.also { + context.startActivity(it) + } + } + //open compose from old activity @JvmStatic @JvmOverloads diff --git a/app/src/main/java/com/brainwallet/navigation/MainNav.kt b/app/src/main/java/com/brainwallet/navigation/MainNav.kt index 1d1fa5e1..f6e2e091 100644 --- a/app/src/main/java/com/brainwallet/navigation/MainNav.kt +++ b/app/src/main/java/com/brainwallet/navigation/MainNav.kt @@ -74,7 +74,10 @@ fun NavGraphBuilder.mainNavGraph( composable { navBackStackEntry -> val route: Route.SetPasscode = navBackStackEntry.toRoute() - SetPasscodeScreen(onNavigate = onNavigate, passcode = route.passcode) + SetPasscodeScreen( + onNavigate = onNavigate, + passcode = route.passcode, + ) } composable { navBackStackEntry -> val route: Route.InputWords = navBackStackEntry.toRoute() @@ -98,7 +101,6 @@ fun NavGraphBuilder.mainNavGraph( ) } - /** * for now, still using old activity & fragment [com.brainwallet.presenter.activities.BreadActivity] */ @@ -106,8 +108,9 @@ fun NavGraphBuilder.mainNavGraph( // HomeScreen(onNavigate = onNavigate) // } - composable { - UnLockScreen(onNavigate = onNavigate) + composable { navBackStackEntry -> + val route: Route.UnLock = navBackStackEntry.toRoute() + UnLockScreen(onNavigate = onNavigate, isUpdatePin = route.isUpdatePin) } //todo add more composable screens diff --git a/app/src/main/java/com/brainwallet/navigation/Route.kt b/app/src/main/java/com/brainwallet/navigation/Route.kt index 905d1bb8..2e0e71a8 100644 --- a/app/src/main/java/com/brainwallet/navigation/Route.kt +++ b/app/src/main/java/com/brainwallet/navigation/Route.kt @@ -15,9 +15,13 @@ sealed class Route : JavaSerializable { @Serializable object TopUp : Route() + @Serializable + object Settings : Route() + @Serializable data class SetPasscode( - val passcode: List = emptyList() + val passcode: List = emptyList(), + val isUpdatePin: Boolean = false, ) : Route() @Serializable @@ -39,6 +43,6 @@ sealed class Route : JavaSerializable { // object Home : Route() @Serializable - object UnLock : Route() + data class UnLock(val isUpdatePin: Boolean = false) : Route() } \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java b/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java index b72234b7..a0f6e980 100644 --- a/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java +++ b/app/src/main/java/com/brainwallet/presenter/activities/BreadActivity.java @@ -28,16 +28,21 @@ import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; import androidx.core.app.ActivityCompat; +import androidx.drawerlayout.widget.DrawerLayout; import androidx.transition.ChangeBounds; import androidx.transition.Fade; import androidx.transition.TransitionManager; import androidx.transition.TransitionSet; -import com.brainwallet.BrainwalletApp; import com.brainwallet.R; +import com.brainwallet.navigation.LegacyNavigation; +import com.brainwallet.navigation.Route; +import com.brainwallet.presenter.activities.settings.SettingsActivity; +import com.brainwallet.presenter.activities.settings.SyncBlockchainActivity; import com.brainwallet.presenter.activities.util.BRActivity; import com.brainwallet.presenter.customviews.BRNotificationBar; import com.brainwallet.presenter.fragments.BuyTabFragment; +import com.brainwallet.presenter.fragments.FragmentMoonpay; import com.brainwallet.presenter.history.HistoryFragment; import com.brainwallet.tools.animation.BRAnimator; import com.brainwallet.tools.animation.TextSizeTransition; @@ -46,6 +51,7 @@ import com.brainwallet.tools.manager.InternetManager; import com.brainwallet.tools.manager.SyncManager; import com.brainwallet.tools.security.BitcoinUrlHandler; +import com.brainwallet.tools.security.PostAuth; import com.brainwallet.tools.sqlite.TransactionDataSource; import com.brainwallet.tools.threads.BRExecutor; import com.brainwallet.tools.util.BRConstants; @@ -53,11 +59,15 @@ import com.brainwallet.tools.util.BRExchange; import com.brainwallet.tools.util.ExtensionKt; import com.brainwallet.tools.util.Utils; +import com.brainwallet.ui.BrainwalletActivity; +import com.brainwallet.ui.screens.home.SettingsViewModel; +import com.brainwallet.ui.screens.home.composable.HomeSettingDrawerComposeView; import com.brainwallet.util.PermissionUtil; import com.brainwallet.wallet.BRPeerManager; import com.brainwallet.wallet.BRWalletManager; import com.google.android.gms.tasks.Task; import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.android.material.navigation.NavigationView; import com.google.android.play.core.review.ReviewInfo; import com.google.android.play.core.review.ReviewManager; import com.google.android.play.core.review.ReviewManagerFactory; @@ -90,6 +100,9 @@ public class BreadActivity extends BRActivity implements BRWalletManager.OnBalan private BottomNavigationView bottomNav; private Handler mHandler = new Handler(); + private NavigationView navigationDrawer; + private DrawerLayout drawerLayout; + private HomeSettingDrawerComposeView homeSettingDrawerComposeView; public static BreadActivity getApp() { return app; @@ -220,7 +233,7 @@ private void setListeners() { secondaryPrice.setOnClickListener(v -> swap()); menuBut.setOnClickListener(v -> { if (BRAnimator.isClickAllowed()) { - BRAnimator.showMenuFragment(BreadActivity.this); + drawerLayout.open(); } }); } @@ -228,6 +241,7 @@ private void setListeners() { public boolean handleNavigationItemSelected(int menuItemId) { if (mSelectedBottomNavItem == menuItemId) return true; mSelectedBottomNavItem = menuItemId; + //TODO: revisit // we are using compose, that's why commented, will remove it after fully migrated to compose if (menuItemId == R.id.nav_history) { @@ -242,8 +256,12 @@ public boolean handleNavigationItemSelected(int menuItemId) { BRAnimator.showReceiveFragment(BreadActivity.this, true); } mSelectedBottomNavItem = 0; - } else if (menuItemId == R.id.nav_buy) { - ExtensionKt.replaceFragment(BreadActivity.this, new BuyTabFragment(), false, R.id.fragment_container); + } + else if (menuItemId == R.id.nav_buy) { + if (BRAnimator.isClickAllowed()) { + BRAnimator.showMoonpayFragment(BreadActivity.this); + } + mSelectedBottomNavItem = 0; } return true; } @@ -366,6 +384,33 @@ protected void onDestroy() { private void initializeViews() { menuBut = findViewById(R.id.menuBut); + + navigationDrawer = findViewById(R.id.navigationDrawer); + drawerLayout = findViewById(R.id.drawerLayout); + homeSettingDrawerComposeView = findViewById(R.id.homeDrawerComposeView); + homeSettingDrawerComposeView.observeBus(message -> { + drawerLayout.close(); + if (SettingsViewModel.LEGACY_EFFECT_ON_LOCK.equals(message.getMessage())) { + LegacyNavigation.startBreadActivity(this, true); + } else if (SettingsViewModel.LEGACY_EFFECT_ON_TOGGLE_DARK_MODE.equals(message.getMessage())) { + LegacyNavigation.restartBreadActivity(this); + } else if (SettingsViewModel.LEGACY_EFFECT_ON_SEC_UPDATE_PIN.equals(message.getMessage())) { + Intent intent = BrainwalletActivity.createIntent(this, new Route.UnLock(true)); + intent.putExtra("noPin", true); + startActivity(intent); + } else if (SettingsViewModel.LEGACY_EFFECT_ON_SEED_PHRASE.equals(message.getMessage())) { + PostAuth.getInstance().onPhraseCheckAuth(this, true); + } else if (SettingsViewModel.LEGACY_EFFECT_ON_SHARE_ANALYTICS_DATA_TOGGLE.equals(message.getMessage())) { + boolean currentShareAnalyticsDataEnabled = BRSharedPrefs.getShareData(this); + BRSharedPrefs.putShareData(this, !currentShareAnalyticsDataEnabled); + } else if (SettingsViewModel.LEGACY_EFFECT_ON_SYNC.equals(message.getMessage())) { + Intent intent = new Intent(this, SyncBlockchainActivity.class); + startActivity(intent); + overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left); + } + return null; + }); //since we are still using this BreadActivity, need to observe EventBus e.g. lock from [HomeSettingDrawerSheet] + bottomNav = findViewById(R.id.bottomNav); bottomNav.getMenu().clear(); bottomNav.inflateMenu(isInUsa() ? R.menu.bottom_nav_menu_us : R.menu.bottom_nav_menu); diff --git a/app/src/main/java/com/brainwallet/presenter/activities/settings/SettingsActivity.java b/app/src/main/java/com/brainwallet/presenter/activities/settings/SettingsActivity.java index 0f2e5cd2..7f33f632 100644 --- a/app/src/main/java/com/brainwallet/presenter/activities/settings/SettingsActivity.java +++ b/app/src/main/java/com/brainwallet/presenter/activities/settings/SettingsActivity.java @@ -140,6 +140,7 @@ private void populateItems() { //toggle dark mode boolean isDarkMode = settingRepository.isDarkMode(); + items.add(new BRSettingsItem(getString(R.string.toggle_dark_mode), getString(isDarkMode ? androidx.appcompat.R.string.abc_capital_on : androidx.appcompat.R.string.abc_capital_off), v -> { settingRepository.toggleDarkMode(!isDarkMode); LegacyNavigation.openComposeScreen(SettingsActivity.this); diff --git a/app/src/main/java/com/brainwallet/presenter/activities/settings/SyncBlockchainActivity.java b/app/src/main/java/com/brainwallet/presenter/activities/settings/SyncBlockchainActivity.java index 7d52f3cf..8ec82627 100644 --- a/app/src/main/java/com/brainwallet/presenter/activities/settings/SyncBlockchainActivity.java +++ b/app/src/main/java/com/brainwallet/presenter/activities/settings/SyncBlockchainActivity.java @@ -118,6 +118,7 @@ public void onClick(BRDialogView brDialogView) { BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @Override public void run() { + ///Dev: This is the structure to do full sync BRSharedPrefs.putStartHeight(SyncBlockchainActivity.this, 0); BRSharedPrefs.putAllowSpend(SyncBlockchainActivity.this, false); BRPeerManager.getInstance().rescan(); diff --git a/app/src/main/java/com/brainwallet/presenter/entities/Partner.java b/app/src/main/java/com/brainwallet/presenter/entities/Partner.java deleted file mode 100644 index 984c7778..00000000 --- a/app/src/main/java/com/brainwallet/presenter/entities/Partner.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.brainwallet.presenter.entities; - -import com.brainwallet.presenter.fragments.FragmentBuy; - -public class Partner { - private int logo; - private int title; - private int details; - private FragmentBuy.Partner code; - - public Partner(int logo, int title, int details, FragmentBuy.Partner code) { - this.logo = logo; - this.title = title; - this.details = details; - this.code = code; - } - - public int getLogo() { - return logo; - } - - public void setLogo(int logo) { - this.logo = logo; - } - - public int getTitle() { - return title; - } - - public void setTitle(int title) { - this.title = title; - } - - public int getDetails() { - return details; - } - - public void setDetails(int details) { - this.details = details; - } - - public FragmentBuy.Partner getCode() { - return code; - } -} diff --git a/app/src/main/java/com/brainwallet/presenter/fragments/BuyPartnersAdapter.java b/app/src/main/java/com/brainwallet/presenter/fragments/BuyPartnersAdapter.java deleted file mode 100644 index 32a40f35..00000000 --- a/app/src/main/java/com/brainwallet/presenter/fragments/BuyPartnersAdapter.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.brainwallet.presenter.fragments; - -import android.content.Context; -import android.net.Uri; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.HorizontalScrollView; -import android.widget.ImageView; -import android.widget.RadioGroup; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; -import androidx.browser.customtabs.CustomTabColorSchemeParams; -import androidx.browser.customtabs.CustomTabsIntent; -import androidx.fragment.app.FragmentActivity; -import androidx.recyclerview.widget.RecyclerView; - -import com.brainwallet.R; -import com.brainwallet.presenter.entities.Partner; -import com.brainwallet.presenter.fragments.FragmentBuy; -import com.brainwallet.tools.animation.BRAnimator; -import com.brainwallet.tools.util.BRConstants; - -import java.util.List; - -class BuyPartnersAdapter extends RecyclerView.Adapter { - - private final LayoutInflater inflater; - private List partners; - - BuyPartnersAdapter(Context context, @NonNull List partners) { - inflater = LayoutInflater.from(context); - this.partners = partners; - } - - @NonNull - @Override - public PartnerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new PartnerViewHolder(inflater.inflate(R.layout.buy_partner_item, parent, false)); - } - - @Override - public void onBindViewHolder(@NonNull final PartnerViewHolder holder, int position) { - final Partner partner = partners.get(position); - holder.logo.setImageResource(partner.getLogo()); - holder.title.setText(partner.getTitle()); - holder.detail.setText(partner.getDetails()); - holder.fiatOptionHScrollView.post(() -> { - int checkId = holder.fiatOptions.getCheckedRadioButtonId(); - View option = holder.fiatOptions.findViewById(checkId); - holder.fiatOptionHScrollView.scrollTo((int) option.getX(), (int) option.getY()); - }); - - if (partner.getCode() == FragmentBuy.Partner.BITREFILL) { - holder.fiatOptionHScrollView.setVisibility(View.INVISIBLE); - holder.fiatOptions.setVisibility(View.INVISIBLE); - } - - holder.buyPartnerWrapper.setOnClickListener(v -> { - int currencyResId = getCurrencyResId(holder.fiatOptions.getCheckedRadioButtonId()); - final Context context = v.getContext(); - String currency = context.getString(currencyResId); - if (partner.getCode() == FragmentBuy.Partner.MOONPAY) { - CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder() - .setDefaultColorSchemeParams(new CustomTabColorSchemeParams.Builder().setToolbarColor(context.getColor(R.color.near_black)).build()) - .setUrlBarHidingEnabled(true); - CustomTabsIntent customTabsIntent = builder.build(); - String buyUrl = FragmentBuy.url(context, partner.getCode(), currency); - customTabsIntent.launchUrl(context, Uri.parse(buyUrl)); - } else { - BRAnimator.showBuyFragment((FragmentActivity) context, currency, partner.getCode()); - } - }); - } - - @StringRes - private int getCurrencyResId(int checkedOption) { - int currency; - if (checkedOption == R.id.cad_fiat) { - currency = R.string.cad_currency_code; - } else if (checkedOption == R.id.eur_fiat) { - currency = R.string.eur_currency_code; - } else if (checkedOption == R.id.jpy_fiat) { - currency = R.string.jpy_currency_code; - } else if (checkedOption == R.id.gbp_fiat) { - currency = R.string.gbp_currency_code; - } else if (checkedOption == R.id.hkd_fiat) { - currency = R.string.hkd_currency_code; - } else if (checkedOption == R.id.idr_fiat) { - currency = R.string.idr_currency_code; - } else if (checkedOption == R.id.rub_fiat) { - currency = R.string.rub_currency_code; - } else if (checkedOption == R.id.sgd_fiat) { - currency = R.string.sgd_currency_code; - } else { - currency = R.string.usd_currency_code; - } - return currency; - } - - @Override - public int getItemCount() { - return partners.size(); - } - - static class PartnerViewHolder extends RecyclerView.ViewHolder { - - final ImageView logo; - final TextView title; - final TextView detail; - final RadioGroup fiatOptions; - final View buyPartnerWrapper; - final HorizontalScrollView fiatOptionHScrollView; - - PartnerViewHolder(@NonNull View itemView) { - super(itemView); - - logo = itemView.findViewById(R.id.logo); - title = itemView.findViewById(R.id.titleLbl); - detail = itemView.findViewById(R.id.detailLbl); - fiatOptions = itemView.findViewById(R.id.fiat_option); - fiatOptionHScrollView = itemView.findViewById(R.id.fiat_option_h_scroll); - buyPartnerWrapper = itemView.findViewById(R.id.buyPartnerWrapper); - } - } -} diff --git a/app/src/main/java/com/brainwallet/presenter/fragments/BuyTabFragment.java b/app/src/main/java/com/brainwallet/presenter/fragments/BuyTabFragment.java index 2ff9abdc..feeabfd3 100644 --- a/app/src/main/java/com/brainwallet/presenter/fragments/BuyTabFragment.java +++ b/app/src/main/java/com/brainwallet/presenter/fragments/BuyTabFragment.java @@ -14,15 +14,9 @@ import androidx.recyclerview.widget.RecyclerView; import com.brainwallet.R; -import com.brainwallet.presenter.entities.Partner; -import com.brainwallet.presenter.fragments.BuyPartnersAdapter; -import com.brainwallet.presenter.fragments.FragmentBuy; import com.brainwallet.tools.manager.AnalyticsManager; import com.brainwallet.tools.util.BRConstants; -import java.util.ArrayList; -import java.util.List; - public class BuyTabFragment extends Fragment { private RecyclerView mRecyclerView; @@ -30,7 +24,7 @@ public class BuyTabFragment extends Fragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_buy_tab, container, false); + return null; } @Override @@ -38,20 +32,10 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat super.onViewCreated(view, savedInstanceState); mRecyclerView = view.findViewById(R.id.recycler_view); - mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); - DividerItemDecoration itemDecor = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL); itemDecor.setDrawable(ContextCompat.getDrawable(mRecyclerView.getContext(), R.drawable.divider_white_shape)); mRecyclerView.addItemDecoration(itemDecor); - - mRecyclerView.setAdapter(new com.brainwallet.presenter.fragments.BuyPartnersAdapter(getContext(), getPartners())); AnalyticsManager.logCustomEvent(BRConstants._20191105_DTBT); } - - private List getPartners() { - List partners = new ArrayList<>(); - partners.add(new Partner(R.drawable.ic_moonpay_logo, R.string.BuyCenter_moonpay_Title, R.string.BuyCenter_moonpay_FinancialDetails, FragmentBuy.Partner.MOONPAY)); - return partners; - } } diff --git a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentBuy.java b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentBuy.java deleted file mode 100644 index 739a4073..00000000 --- a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentBuy.java +++ /dev/null @@ -1,273 +0,0 @@ -package com.brainwallet.presenter.fragments; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.ClipData; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.ValueCallback; -import android.webkit.WebChromeClient; -import android.webkit.WebResourceRequest; -import android.webkit.WebSettings; -import android.webkit.WebView; -import android.webkit.WebViewClient; - -import android.widget.LinearLayout; -import android.widget.ProgressBar; - -import androidx.activity.OnBackPressedCallback; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.Toolbar; -import androidx.fragment.app.Fragment; - -import com.brainwallet.BrainwalletApp; -import com.brainwallet.BuildConfig; -import com.brainwallet.R; -import com.brainwallet.tools.animation.BRAnimator; -import com.brainwallet.tools.manager.BRApiManager; -import com.brainwallet.tools.manager.BRSharedPrefs; -import com.brainwallet.tools.util.BRConstants; -import com.brainwallet.tools.util.Utils; - -import org.koin.core.component.KoinComponentKt; -import org.koin.java.KoinJavaComponent; - -import java.util.Date; - -import timber.log.Timber; - -public class FragmentBuy extends Fragment { - private static final int FILE_CHOOSER_REQUEST_CODE = 15423; - public LinearLayout backgroundLayout; - private ProgressBar progress; - private WebView webView; - private String onCloseUrl; - private static final String CURRENCY_KEY = "currency_code_key"; - private static final String PARTNER_KEY = "partner_key"; - private ValueCallback uploadMessage; - private ValueCallback uploadMessageAboveL; - - public static Fragment newInstance(String currency, Partner partner) { - Bundle bundle = new Bundle(); - bundle.putString(CURRENCY_KEY, currency); - bundle.putSerializable(PARTNER_KEY, partner); - Fragment fragment = new FragmentBuy(); - fragment.setArguments(bundle); - return fragment; - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) { - @Override - public void handleOnBackPressed() { - if (webView.canGoBack()) { - webView.goBack(); - } else { - closePayment(); - } - } - }); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_buy, container, false); - Toolbar toolbar = rootView.findViewById(R.id.toolbar); - toolbar.setNavigationOnClickListener(v -> closePayment()); - backgroundLayout = rootView.findViewById(R.id.background_layout); - progress = rootView.findViewById(R.id.progress); - webView = rootView.findViewById(R.id.web_view); - webView.setWebChromeClient(mWebChromeClient); - webView.setWebViewClient(mWebViewClient); - - WebSettings webSettings = webView.getSettings(); - if (BuildConfig.DEBUG) { - WebView.setWebContentsDebuggingEnabled(true); - } - webSettings.setDomStorageEnabled(true); - webSettings.setJavaScriptEnabled(true); -// -// // App (in Java) -// WebMessageListener bitrefillListener = new WebMessageListener() { -// @Override -// public void onPostMessage(WebView view, WebMessageCompat message, Uri sourceOrigin, -// boolean isMainFrame, JavaScriptReplyProxy replyProxy) { -// // do something about view, message, sourceOrigin and isMainFrame. -// replyProxy.postMessage("Got it!"); -// } -// }; -// if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { -// WebViewCompat.addWebMessageListener(webView, "bitrefillPostObj", rules, bitrefillListener); -// } - -// // App (in Java) -// WebMessageListener bitrefillListener = new WebMessageListener() { -// @Override -// public void onPostMessage(WebView view, WebMessageCompat message, Uri sourceOrigin, -// boolean isMainFrame, JavaScriptReplyProxy replyProxy) { -// // do something about view, message, sourceOrigin and isMainFrame. -// replyProxy.postMessage("Got it!"); -// } -// }; -// -// if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) { -// WebViewCompat.addWebMessageListener(webView, "bitrefillPostObj", rules, bitrefillListener); -// } - - String currency = getArguments().getString(CURRENCY_KEY); - Partner partner = (Partner) getArguments().getSerializable(PARTNER_KEY); - - String bitrefillRef = "bAshL935"; - String utmSource = "BrainwalletAndroid"; - String bitrefillUrl = String.format( BRConstants.BITREFILL_AFFILIATE_LINK + "/embed/?paymentMethod=litecoin&ref=%s&utm_source=%s", bitrefillRef,utmSource); - - String buyUrl = partner == Partner.BITREFILL ? bitrefillUrl : url(getContext(), partner, currency); - Timber.d("timber: URL %s", buyUrl); - webView.loadUrl(buyUrl); - - return rootView; - } - - public static String url(Context context, Partner partner, String currency) { - String walletAddress = BRSharedPrefs.getReceiveAddress(context); - Long timestamp = new Date().getTime(); - String uuid = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); - String prefix = partner == Partner.MOONPAY ? "/moonpay/buy" : ""; - String baseUrl = ((BRApiManager) KoinJavaComponent.get(BRApiManager.class)).getBaseUrlProd(); - return String.format(baseUrl + prefix + "?address=%s&code=%s&idate=%s&uid=%s", walletAddress, currency, timestamp, uuid); - } - - private void closePayment() { - requireActivity().getSupportFragmentManager().popBackStack(); - } - - @Override - public void onStop() { - super.onStop(); - BRAnimator.animateBackgroundDim(backgroundLayout, true); - } - - private WebChromeClient mWebChromeClient = new WebChromeClient() { - // For Android API < 11 (3.0 OS) - public void openFileChooser(ValueCallback valueCallback) { - uploadMessage = valueCallback; - openImageChooserActivity(); - } - - // For Android API >= 11 (3.0 OS) - public void openFileChooser(ValueCallback valueCallback, String acceptType, String capture) { - uploadMessage = valueCallback; - openImageChooserActivity(); - } - - // For Android API >= 21 (5.0 OS) - @Override - public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { - uploadMessageAboveL = filePathCallback; - openImageChooserActivity(); - return true; - } - - @Override - public void onProgressChanged(WebView view, int newProgress) { - super.onProgressChanged(view, newProgress); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - progress.setProgress(newProgress, true); - } else progress.setProgress(newProgress); - } - }; - - private WebViewClient mWebViewClient = new WebViewClient() { - @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - String url = request.getUrl().toString(); - Timber.d("timber: shouldOverrideUrlLoading: URL=%s\nMethod=%s", url, request.getMethod()); - if (url.equalsIgnoreCase(onCloseUrl)) { - closePayment(); - onCloseUrl = null; - } else if (url.contains("close")) { - closePayment(); - } else { - view.loadUrl(url); - } - - return true; - } - - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - Timber.d("timber: onPageStarted: %s", url); - super.onPageStarted(view, url, favicon); - progress.setVisibility(View.VISIBLE); - } - - @Override - public void onPageFinished(WebView view, String url) { - super.onPageFinished(view, url); - Timber.d("timber: onPageFinished %s", url); - progress.setVisibility(View.GONE); - } - }; - - private void openImageChooserActivity() { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("image/*"); - startActivityForResult(Intent.createChooser(intent, "Image Chooser"), FILE_CHOOSER_REQUEST_CODE); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == FILE_CHOOSER_REQUEST_CODE) { - if (uploadMessageAboveL != null) { - Uri[] results = getResultAboveL(resultCode, data); - uploadMessageAboveL.onReceiveValue(results); - } else if (uploadMessage != null) { - Uri result = data != null && resultCode == Activity.RESULT_OK ? data.getData() : null; - uploadMessage.onReceiveValue(result); - } - uploadMessageAboveL = null; - uploadMessage = null; - } - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private Uri[] getResultAboveL(int resultCode, Intent intent) { - Uri[] results = null; - if (intent != null && resultCode == Activity.RESULT_OK) { - String dataString = intent.getDataString(); - ClipData clipData = intent.getClipData(); - if (clipData != null) { - results = new Uri[clipData.getItemCount()]; - for (int i = 0; i < clipData.getItemCount(); i++) { - ClipData.Item item = clipData.getItemAt(i); - results[i] = item.getUri(); - } - } else if (dataString != null) { - results = new Uri[]{Uri.parse(dataString)}; - } - } - return results; - } - - @Override - public void onPause() { - super.onPause(); - Utils.hideKeyboard(getActivity()); - } - - public enum Partner { - MOONPAY, BITREFILL - } -} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/presenter/fragments/FragmentMoonpay.kt b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentMoonpay.kt new file mode 100644 index 00000000..ce0a4c20 --- /dev/null +++ b/app/src/main/java/com/brainwallet/presenter/fragments/FragmentMoonpay.kt @@ -0,0 +1,65 @@ +package com.brainwallet.presenter.fragments + +import android.content.res.ColorStateList +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.webkit.WebSettings +import android.webkit.WebView +import android.webkit.WebViewClient +import android.widget.ImageButton +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import com.brainwallet.R +import com.brainwallet.tools.manager.BRClipboardManager +import com.brainwallet.tools.manager.BRSharedPrefs + +class FragmentMoonpay : Fragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_moonpay_temp, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val webView = view.findViewById(R.id.web_view) + val buttonClose = view.findViewById(R.id.close_button) + val copyAddressButton = view.findViewById(R.id.copy_button) + var receiveAddressLabel = view.findViewById(R.id.receive_address) + val addressText = BRSharedPrefs.getReceiveAddress(context) + + // buttonClose + receiveAddressLabel.setText(addressText) + receiveAddressLabel.setTextColor(receiveAddressLabel.getResources().getColor(R.color.midnight, null)); + webView.setInitialScale(80) + webView.settings.apply { + javaScriptEnabled = true + domStorageEnabled = true + cacheMode = WebSettings.LOAD_DEFAULT + setSupportZoom(true) + useWideViewPort = true + loadWithOverviewMode = true + } + + webView.webViewClient = WebViewClient() + webView.loadUrl("https://www.brainwallet.co/mobile-top-up.html") + + buttonClose.setOnClickListener { + parentFragmentManager.popBackStack() + } + + receiveAddressLabel.setOnClickListener { + BRClipboardManager.putClipboard(context, receiveAddressLabel.getText().toString()) + } + + copyAddressButton.setOnClickListener { + BRClipboardManager.putClipboard(context, receiveAddressLabel.getText().toString()) + } + } + } diff --git a/app/src/main/java/com/brainwallet/tools/animation/BRAnimator.java b/app/src/main/java/com/brainwallet/tools/animation/BRAnimator.java index 41c6d64d..78c5364f 100644 --- a/app/src/main/java/com/brainwallet/tools/animation/BRAnimator.java +++ b/app/src/main/java/com/brainwallet/tools/animation/BRAnimator.java @@ -1,5 +1,7 @@ package com.brainwallet.tools.animation; +import static androidx.databinding.DataBindingUtil.setContentView; + import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -20,21 +22,21 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.compose.ui.platform.ComposeView; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.FragmentActivity; import com.brainwallet.navigation.LegacyNavigation; +import com.brainwallet.presenter.fragments.FragmentMoonpay; import com.brainwallet.tools.threads.BRExecutor; import com.brainwallet.tools.util.BRConstants; -import com.brainwallet.tools.util.Utils; import com.brainwallet.R; import com.brainwallet.presenter.activities.BreadActivity; import com.brainwallet.presenter.activities.camera.ScanQRActivity; import com.brainwallet.presenter.customviews.BRDialogView; import com.brainwallet.presenter.entities.TxItem; import com.brainwallet.presenter.fragments.FragmentBalanceSeedReminder; -import com.brainwallet.presenter.fragments.FragmentBuy; import com.brainwallet.presenter.fragments.FragmentMenu; import com.brainwallet.presenter.fragments.FragmentReceive; import com.brainwallet.presenter.fragments.FragmentSend; @@ -52,6 +54,8 @@ public class BRAnimator { public static int SLIDE_ANIMATION_DURATION = 300; public static boolean supportIsShowing; + private static boolean shouldShowSettingsComposable = false; + public static void showBreadSignal(FragmentActivity activity, String title, String iconDescription, int drawableId, BROnSignalCompletion completion) { fragmentSignal = new FragmentSignal(); Bundle bundle = new Bundle(); @@ -217,29 +221,25 @@ public static void showReceiveFragment(Activity app, boolean isReceive) { } - public static void showBuyFragment(FragmentActivity app, String currency, FragmentBuy.Partner partner) { + public static void showMoonpayFragment(FragmentActivity app) { + if (app == null) { - Timber.i("timber: showBuyFragment: app is null"); + Timber.i("timber: showSendFragment: app is null"); return; } - app.getSupportFragmentManager() - .beginTransaction() - .setCustomAnimations(0, 0, 0, R.animator.plain_300) - .add(android.R.id.content, FragmentBuy.newInstance(currency, partner), FragmentBuy.class.getName()) - .addToBackStack(FragmentBuy.class.getName()) - .commit(); - } - - public static void showMenuFragment(Activity app) { - if (app == null) { - Timber.i("timber: showReceiveFragment: app is null"); + androidx.fragment.app.FragmentManager fragmentManager = app.getSupportFragmentManager(); + FragmentMoonpay fragmentMoonpay = (FragmentMoonpay) fragmentManager.findFragmentByTag(FragmentMoonpay.class.getName()); + if (fragmentMoonpay != null && fragmentMoonpay.isAdded()) { return; } - FragmentTransaction transaction = app.getFragmentManager().beginTransaction(); - transaction.setCustomAnimations(0, 0, 0, R.animator.plain_300); - transaction.add(android.R.id.content, new FragmentMenu(), FragmentMenu.class.getName()); - transaction.addToBackStack(FragmentMenu.class.getName()); - transaction.commit(); + try { + fragmentMoonpay = new FragmentMoonpay(); + fragmentManager.beginTransaction() + .setCustomAnimations(0, 0, 0, R.animator.plain_300) + .add(android.R.id.content, fragmentMoonpay, FragmentMoonpay.class.getName()) + .addToBackStack(FragmentMoonpay.class.getName()).commit(); + } finally { + } } public static boolean isClickAllowed() { diff --git a/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java b/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java index aa02b78b..d57f9f71 100644 --- a/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java +++ b/app/src/main/java/com/brainwallet/tools/manager/BRApiManager.java @@ -64,17 +64,18 @@ private Set getCurrencies(Activity context) { CurrencyEntity tmp = new CurrencyEntity(); try { JSONObject tmpObj = (JSONObject) arr.get(i); - tmp.name = tmpObj.getString("code"); + tmp.name = tmpObj.getString("name"); tmp.code = tmpObj.getString("code"); tmp.rate = (float) tmpObj.getDouble("n"); if (tmp.code.equalsIgnoreCase(selectedISO)) { BRSharedPrefs.putIso(context, tmp.code); BRSharedPrefs.putCurrencyListPosition(context, i - 1); } + set.add(tmp); } catch (JSONException e) { Timber.e(e); } - set.add(tmp); + } } else { Timber.d("timber: getCurrencies: failed to get currencies"); diff --git a/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java b/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java index 3b17ec91..40ad36b1 100644 --- a/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java +++ b/app/src/main/java/com/brainwallet/tools/sqlite/CurrencyDataSource.java @@ -14,6 +14,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; @@ -70,40 +71,68 @@ public List getAllCurrencies(Boolean shouldBeFiltered) { List currencies = new ArrayList<>(); + /// Set the most popular fiats + /// Hack: Database needs a symbol column. This is injected here. + HashMap codeSymbolsMap = new HashMap(); + codeSymbolsMap.put("USD","$"); + codeSymbolsMap.put("EUR","€"); + codeSymbolsMap.put("GBP","£"); + codeSymbolsMap.put("SGD","$"); + codeSymbolsMap.put("CAD","$"); + codeSymbolsMap.put("AUD","$"); + codeSymbolsMap.put("RUB","₽"); + codeSymbolsMap.put("KRW","₩"); + codeSymbolsMap.put("MXN","$"); + codeSymbolsMap.put("SAR","﷼"); + codeSymbolsMap.put("UAH","₴"); + codeSymbolsMap.put("NGN","₦"); + codeSymbolsMap.put("JPY","¥"); + codeSymbolsMap.put("CNY","¥"); + codeSymbolsMap.put("IDR","Rp"); + codeSymbolsMap.put("TRY","₺"); + /// Set the most popular fiats List filteredFiatCodes = Arrays.asList("USD","EUR","GBP", "SGD","CAD","AUD","RUB","KRW","MXN","SAR","UAH","NGN","JPY","CNY","IDR","TRY"); - Cursor cursor = null; - try { - database = openDatabase(); - - cursor = database.query(BRSQLiteHelper.CURRENCY_TABLE_NAME, - allColumns, null, null, null, null, "\'" + BRSQLiteHelper.CURRENCY_CODE + "\'"); - - cursor.moveToFirst(); - while (!cursor.isAfterLast()) { - CurrencyEntity curEntity = cursorToCurrency(cursor); - currencies.add(curEntity); - cursor.moveToNext(); + Cursor cursor = null; + try { + database = openDatabase(); + + cursor = database.query(BRSQLiteHelper.CURRENCY_TABLE_NAME, + allColumns, null, null, null, null, "\'" + BRSQLiteHelper.CURRENCY_CODE + "\'"); + + cursor.moveToFirst(); + while (!cursor.isAfterLast()) { + CurrencyEntity curEntity = cursorToCurrency(cursor); + currencies.add(curEntity); + cursor.moveToNext(); + } + } finally { + if (cursor != null) + cursor.close(); + closeDatabase(); } - } finally { - if (cursor != null) - cursor.close(); - closeDatabase(); - } - if (shouldBeFiltered) { - // Filtering Brainwallet fiats - List filteredFiats = currencies.stream() - .filter(currency -> filteredFiatCodes.contains(currency.code)) - .collect(Collectors.toList()); - currencies = filteredFiats; + if (shouldBeFiltered) { + // Filtering Brainwallet fiats + List filteredFiats = currencies.stream() + .filter(currency -> filteredFiatCodes.contains(currency.code)) + .collect(Collectors.toList()); + currencies = filteredFiats; + + // Load the symbols to Brainwallet fiats + List completeCurrencyEntities = new ArrayList<>(); + for(int i=0;i Unit + } } diff --git a/app/src/main/java/com/brainwallet/ui/composable/DarkModeToggleButton.kt b/app/src/main/java/com/brainwallet/ui/composable/DarkModeToggleButton.kt new file mode 100644 index 00000000..05b89e53 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/composable/DarkModeToggleButton.kt @@ -0,0 +1,58 @@ +package com.brainwallet.ui.composable +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Icon +import androidx.compose.material3.IconToggleButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.brainwallet.R +import com.brainwallet.ui.theme.BrainwalletTheme + +@Composable +fun DarkModeToggleButton( + checked: Boolean, + onCheckedChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, +) { + val iconButtonSize = 32 + + IconToggleButton( + checked = checked, + onCheckedChange = onCheckedChange, + modifier = modifier, + ) { + Box( + modifier = Modifier + .fillMaxSize() + .width(iconButtonSize.dp) + .aspectRatio(1f) + .clip(CircleShape) + .border( + 1.dp, + if (checked) BrainwalletTheme.colors.warn else BrainwalletTheme.colors.surface, + CircleShape + ) + .background(if (checked) BrainwalletTheme.colors.surface else BrainwalletTheme.colors.content) + ) { + Icon( + modifier = Modifier + .align(Alignment.Center) + .width(iconButtonSize.dp) + .aspectRatio(1f), + tint = if (checked) BrainwalletTheme.colors.warn else BrainwalletTheme.colors.surface, + painter = painterResource(if (checked) R.drawable.ic_light_mode else R.drawable.ic_dark_mode), + contentDescription = stringResource(R.string.toggle_dark_mode), + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt new file mode 100644 index 00000000..531305b6 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsEvent.kt @@ -0,0 +1,20 @@ +package com.brainwallet.ui.screens.home + +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.Language + +sealed class SettingsEvent { + data class OnLoad(val shareAnalyticsDataEnabled: Boolean = false) : SettingsEvent() + object OnSecurityUpdatePinClick : SettingsEvent() + object OnSecuritySeedPhraseClick : SettingsEvent() + object OnSecurityShareAnalyticsDataClick : SettingsEvent() + object OnToggleDarkMode : SettingsEvent() + object OnToggleLock : SettingsEvent() + object OnLanguageSelectorButtonClick : SettingsEvent() + object OnLanguageSelectorDismiss : SettingsEvent() + data class OnLanguageChange(val language: Language) : SettingsEvent() + object OnFiatButtonClick : SettingsEvent() + object OnFiatSelectorDismiss : SettingsEvent() + data class OnFiatChange(val currency: CurrencyEntity) : SettingsEvent() + object OnBlockchainSyncClick : SettingsEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt new file mode 100644 index 00000000..3efe10a7 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsState.kt @@ -0,0 +1,17 @@ +package com.brainwallet.ui.screens.home +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.data.model.Language + +data class SettingsState( + val darkMode: Boolean = true, + val selectedLanguage: Language = Language.ENGLISH, + val selectedCurrency: CurrencyEntity = CurrencyEntity( + "USD", + "US Dollar", + -1f, + "$" + ), //-1 = need to fetch + val languageSelectorBottomSheetVisible: Boolean = false, + val fiatSelectorBottomSheetVisible: Boolean = false, + val shareAnalyticsDataEnabled: Boolean = false, +) \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt new file mode 100644 index 00000000..7ec71f98 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/SettingsViewModel.kt @@ -0,0 +1,148 @@ +package com.brainwallet.ui.screens.home + +import androidx.appcompat.app.AppCompatDelegate +import androidx.core.os.LocaleListCompat +import androidx.lifecycle.viewModelScope +import com.brainwallet.data.model.AppSetting +import com.brainwallet.data.model.Language +import com.brainwallet.data.repository.SettingRepository +import com.brainwallet.ui.BrainwalletViewModel +import com.brainwallet.util.EventBus +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.updateAndGet +import kotlinx.coroutines.launch + + +class SettingsViewModel( + private val settingRepository: SettingRepository +) : BrainwalletViewModel() { + + private val _state = MutableStateFlow(SettingsState()) + val state: StateFlow = _state.asStateFlow() + + val appSetting = settingRepository.settings + .distinctUntilChanged() + .onEach { setting -> + _state.update { + it.copy( + darkMode = setting.isDarkMode, + selectedLanguage = Language.find(setting.languageCode), + selectedCurrency = setting.currency, + ) + } + } + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + AppSetting() + ) + + override fun onEvent(event: SettingsEvent) { + when (event) { + is SettingsEvent.OnLoad -> viewModelScope.launch { + _state.update { it.copy(shareAnalyticsDataEnabled = event.shareAnalyticsDataEnabled) } + } + + SettingsEvent.OnToggleDarkMode -> viewModelScope.launch { + _state.update { + val toggled = it.darkMode.not() + + settingRepository.save( + appSetting.value.copy( + isDarkMode = toggled + ) + ) + + it.copy(darkMode = toggled) + } + EventBus.emit(EventBus.Event.Message(LEGACY_EFFECT_ON_TOGGLE_DARK_MODE)) + } + + SettingsEvent.OnToggleLock -> viewModelScope.launch { + EventBus.emit(EventBus.Event.Message(LEGACY_EFFECT_ON_LOCK)) + } + + SettingsEvent.OnFiatButtonClick -> _state.update { + it.copy(fiatSelectorBottomSheetVisible = true) + } + + SettingsEvent.OnLanguageSelectorButtonClick -> _state.update { + it.copy(languageSelectorBottomSheetVisible = true) + } + + SettingsEvent.OnFiatSelectorDismiss -> _state.update { + it.copy( + fiatSelectorBottomSheetVisible = false + ) + } + + SettingsEvent.OnLanguageSelectorDismiss -> _state.update { + it.copy( + languageSelectorBottomSheetVisible = false + ) + } + + is SettingsEvent.OnLanguageChange -> _state.updateAndGet { + it.copy( + selectedLanguage = event.language, + languageSelectorBottomSheetVisible = false + ) + }.let { + viewModelScope.launch { + settingRepository.save(appSetting.value.copy(languageCode = event.language.code)) + AppCompatDelegate.setApplicationLocales( + LocaleListCompat.forLanguageTags( + event.language.code + ) + ) + } + } + + is SettingsEvent.OnFiatChange -> _state.updateAndGet { + it.copy(selectedCurrency = event.currency) + }.let { + viewModelScope.launch { + settingRepository.save( + appSetting.value.copy( + currency = event.currency + ) + ) + } + } + + is SettingsEvent.OnBlockchainSyncClick -> viewModelScope.launch { + EventBus.emit(EventBus.Event.Message(LEGACY_EFFECT_ON_SYNC)) + } + + SettingsEvent.OnSecuritySeedPhraseClick -> viewModelScope.launch { + EventBus.emit(EventBus.Event.Message(LEGACY_EFFECT_ON_SEED_PHRASE)) + } + + SettingsEvent.OnSecurityUpdatePinClick -> viewModelScope.launch { + EventBus.emit(EventBus.Event.Message(LEGACY_EFFECT_ON_SEC_UPDATE_PIN)) + } + + SettingsEvent.OnSecurityShareAnalyticsDataClick -> viewModelScope.launch { + _state.update { it.copy(shareAnalyticsDataEnabled = it.shareAnalyticsDataEnabled.not()) } + + EventBus.emit(EventBus.Event.Message(LEGACY_EFFECT_ON_SHARE_ANALYTICS_DATA_TOGGLE)) + } + } + } + + companion object { + const val LEGACY_EFFECT_ON_LOCK = "onLockInvoked" + const val LEGACY_EFFECT_ON_TOGGLE_DARK_MODE = "onToggleDarkMode" + const val LEGACY_EFFECT_ON_SYNC = "onSyncInvoked" + const val LEGACY_EFFECT_ON_SEC_UPDATE_PIN = "onSecUpdatePin" + const val LEGACY_EFFECT_ON_SEED_PHRASE = "onSeedPhrase" + const val LEGACY_EFFECT_ON_SHARE_ANALYTICS_DATA_TOGGLE = "onShareAnalyticsDataToggle" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt new file mode 100644 index 00000000..497770f8 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/HomeSettingDrawerSheet.kt @@ -0,0 +1,216 @@ +package com.brainwallet.ui.screens.home.composable + +import android.content.Context +import android.net.Uri +import android.util.AttributeSet +import androidx.browser.customtabs.CustomTabsIntent +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ModalDrawerSheet +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.AbstractComposeView +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.lifecycle.coroutineScope +import androidx.lifecycle.findViewTreeLifecycleOwner +import com.brainwallet.R +import com.brainwallet.data.model.AppSetting +import com.brainwallet.tools.manager.BRSharedPrefs +import com.brainwallet.tools.util.BRConstants +import com.brainwallet.ui.screens.home.SettingsEvent +import com.brainwallet.ui.screens.home.SettingsViewModel +import com.brainwallet.ui.screens.home.composable.settingsrows.CurrencyDetail +import com.brainwallet.ui.screens.home.composable.settingsrows.GamesDetail +import com.brainwallet.ui.screens.home.composable.settingsrows.LanguageDetail +import com.brainwallet.ui.screens.home.composable.settingsrows.LitecoinBlockchainDetail +import com.brainwallet.ui.screens.home.composable.settingsrows.LockSettingRowItem +import com.brainwallet.ui.screens.home.composable.settingsrows.SecurityDetail +import com.brainwallet.ui.screens.home.composable.settingsrows.SettingRowItem +import com.brainwallet.ui.screens.home.composable.settingsrows.ThemeSettingRowItem +import com.brainwallet.ui.theme.BrainwalletAppTheme +import com.brainwallet.ui.theme.BrainwalletTheme +import com.brainwallet.util.EventBus +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import org.koin.compose.koinInject +import org.koin.java.KoinJavaComponent.inject + +@Composable +fun HomeSettingDrawerSheet( + modifier: Modifier = Modifier, + viewModel: SettingsViewModel = koinInject() +) { + val state by viewModel.state.collectAsState() + val context = LocalContext.current + + LaunchedEffect(Unit) { + viewModel.onEvent(SettingsEvent.OnLoad(BRSharedPrefs.getShareData(context))) //currently just load analytics share data here + } + + /// Layout values + val headerPadding = 56 + + ModalDrawerSheet( + modifier = modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()), + drawerContainerColor = BrainwalletTheme.colors.surface, + drawerContentColor = BrainwalletTheme.colors.content + ) { + LazyColumn( + modifier = Modifier + .weight(1f) + .padding(top = headerPadding.dp) + .wrapContentHeight(align = Alignment.Top) + ) { + item { + SecurityDetail( + modifier = Modifier + .fillMaxSize() + .wrapContentHeight(), + shareAnalyticsDataEnabled = state.shareAnalyticsDataEnabled, + onEvent = { + viewModel.onEvent(it) + } + ) + } + item { + LanguageDetail( + modifier = Modifier + .fillMaxSize() + .wrapContentHeight(), + selectedLanguage = state.selectedLanguage, + onLanguageSelect = { language -> + viewModel.onEvent( + SettingsEvent.OnLanguageChange( + language + ) + ) + } + ) + + } + item { + CurrencyDetail( + modifier = Modifier + .fillMaxSize() + .wrapContentHeight(), + selectedCurrency = state.selectedCurrency, + onFiatSelect = { currency -> + viewModel.onEvent( + SettingsEvent.OnFiatChange( + currency + ) + ) + } + ) + } + item { + GamesDetail( + modifier = Modifier + .fillMaxSize() + .wrapContentHeight() + ) + } + item { + LitecoinBlockchainDetail( + modifier = Modifier + .fillMaxSize() + .wrapContentHeight(), + onEvent = { + viewModel.onEvent(it) + } + ) + } + item { + SettingRowItem( + title = stringResource(R.string.settings_title_support), + description = "brainwallet.co", + onClick = { + val builder = CustomTabsIntent.Builder() + val customTabsIntent = builder.build() + customTabsIntent.launchUrl(context, Uri.parse(BRConstants.WEB_LINK)) + } + ) + } + item { + SettingRowItem( + title = stringResource(R.string.settings_title_social_media), + description = "linktr.ee/brainwallet", + onClick = { + val builder = CustomTabsIntent.Builder() + val customTabsIntent = builder.build() + customTabsIntent.launchUrl(context, Uri.parse(BRConstants.LINKTREE_URL)) + } + ) + } + item { + // Lock / Unlock + LockSettingRowItem { + viewModel.onEvent(SettingsEvent.OnToggleLock) + } + } + item { + // Theme + ThemeSettingRowItem( + darkMode = state.darkMode, + onToggledDarkMode = { + viewModel.onEvent(SettingsEvent.OnToggleDarkMode) + } + ) + } + + item { + SettingRowItem( + title = stringResource(R.string.settings_title_app_version), + description = BRConstants.APP_VERSION_NAME_CODE + ) + } + } + } +} + +/** + * for backward compat with XML, for now we are using XML + * will used by [activity_bread.xml] + */ + +class HomeSettingDrawerComposeView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null +) : AbstractComposeView(context, attrs) { + + private val settingsViewModel: SettingsViewModel by inject(SettingsViewModel::class.java) + + @Composable + override fun Content() { + val appSetting by settingsViewModel.appSetting.collectAsState( + AppSetting() + ) + BrainwalletAppTheme(appSetting = appSetting) { + HomeSettingDrawerSheet(viewModel = settingsViewModel) + } + } + + fun observeBus( + onEach: (EventBus.Event.Message) -> Unit + ) { + EventBus.events + .filter { it is EventBus.Event.Message } + .map { it as EventBus.Event.Message } + .onEach { onEach.invoke(it) } + .launchIn(findViewTreeLifecycleOwner()!!.lifecycle.coroutineScope) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/CurrencyDetail.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/CurrencyDetail.kt new file mode 100644 index 00000000..83821a2f --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/CurrencyDetail.kt @@ -0,0 +1,101 @@ +package com.brainwallet.ui.screens.home.composable.settingsrows + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CheckCircle +import androidx.compose.material3.Icon +import androidx.compose.material3.ListItem +import androidx.compose.material3.ListItemDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.brainwallet.R +import com.brainwallet.data.model.CurrencyEntity +import com.brainwallet.tools.sqlite.CurrencyDataSource +import com.brainwallet.ui.theme.BrainwalletTheme + +@Composable +fun CurrencyDetail( + modifier: Modifier = Modifier, + selectedCurrency: CurrencyEntity, + onFiatSelect: (CurrencyEntity) -> Unit +) { + val context = LocalContext.current + + /// Layout values + val closedHeight = 60 + val expandedHeight = 100 + val dividerThickness = 1 + val unselectedCircleSize = 20 + val tinyPad = 2 + + SettingRowItemExpandable( + modifier = modifier, + title = stringResource(R.string.settings_title_currency) + ) { + LazyColumn( + modifier = Modifier.height(expandedHeight.dp) + ) { + items( + items = CurrencyDataSource.getInstance(context).getAllCurrencies(true) + ) { currency -> + ListItem(colors = ListItemDefaults.colors( + containerColor = BrainwalletTheme.colors.background, + headlineColor = BrainwalletTheme.colors.content, + ), modifier = Modifier.clickable { + onFiatSelect.invoke(currency) + }, headlineContent = { + Row { + Text( + modifier = Modifier.padding(tinyPad.dp), + text = currency.name, + style = MaterialTheme.typography.labelMedium + .copy(textAlign = TextAlign.Left) + ) + Spacer(modifier = Modifier.weight(1f)) + Text( + modifier = Modifier.padding(tinyPad.dp), + text = "${currency.code} (${currency.symbol})", + style = MaterialTheme.typography.labelMedium + .copy(textAlign = TextAlign.Left) + ) + } + + }, trailingContent = { + if (selectedCurrency.code == currency.code) { + Icon( + Icons.Default.CheckCircle, + contentDescription = null, + tint = BrainwalletTheme.colors.affirm + ) + } else { + Box( + modifier = Modifier + .size(unselectedCircleSize.dp) + .alpha(0.1f) + .clip(CircleShape) + .background(BrainwalletTheme.colors.content) + ) + } + }) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/GamesDetail.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/GamesDetail.kt new file mode 100644 index 00000000..02bb1132 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/GamesDetail.kt @@ -0,0 +1,88 @@ +package com.brainwallet.ui.screens.home.composable.settingsrows + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.brainwallet.R + +@Composable +fun GamesDetail( + modifier: Modifier = Modifier +) { + /// Layout values + val contentHeight = 60 + val horizontalPadding = 14 + + SettingRowItemExpandable( + modifier = modifier, + title = stringResource(R.string.settings_title_games) + ) { + Column( + modifier = Modifier.padding(horizontal = horizontalPadding.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + + Row( + modifier = Modifier + .height(contentHeight.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(stringResource(R.string.game_title, 1)) + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { + }) { + Text(stringResource(R.string.game_buy_price_1, "TBD")) + } + } + + Row( + modifier = Modifier + .height(contentHeight.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(stringResource(R.string.game_title, 2)) + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { + }) { + Text(stringResource(R.string.game_buy_price_2, "TBD")) + } + } + + Row( + modifier = Modifier + .height(contentHeight.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(stringResource(R.string.game_title, 3)) + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { + }) { + Text(stringResource(R.string.game_buy_price_3, "TBD")) + } + } + Row( + modifier = Modifier + .height(contentHeight.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(stringResource(R.string.game_title, 4)) + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { + }) { + Text(stringResource(R.string.game_buy_price_4, "TBD")) + } + } + + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LanguageDetail.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LanguageDetail.kt new file mode 100644 index 00000000..24046969 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LanguageDetail.kt @@ -0,0 +1,90 @@ +package com.brainwallet.ui.screens.home.composable.settingsrows + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CheckCircle +import androidx.compose.material3.Icon +import androidx.compose.material3.ListItem +import androidx.compose.material3.ListItemDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.brainwallet.R +import com.brainwallet.data.model.Language +import com.brainwallet.ui.theme.BrainwalletTheme + +//TODO +@Composable +fun LanguageDetail( + modifier: Modifier = Modifier, + selectedLanguage: Language, + onLanguageSelect: (Language) -> Unit +) { + val languages = Language.entries.toTypedArray() + + /// Layout values + val expandedHeight = 150 + val unselectedCircleSize = 20 + + + SettingRowItemExpandable( + modifier = modifier, + title = stringResource(R.string.settings_title_language) + ) { + LazyColumn(modifier = Modifier.height(expandedHeight.dp)) { + items( + items = languages + ) { language -> + ListItem( + colors = ListItemDefaults.colors( + containerColor = BrainwalletTheme.colors.background, + headlineColor = BrainwalletTheme.colors.content, + ), + modifier = Modifier.clickable { + if (language.code.isNotBlank()) { + onLanguageSelect.invoke(language) + } + }, + headlineContent = { + Text( + modifier = Modifier, + text = language.title, + style = MaterialTheme.typography.bodyMedium + .copy(textAlign = TextAlign.Left) + ) + }, + trailingContent = { + if (selectedLanguage.code == language.code) { + Icon( + Icons.Default.CheckCircle, + contentDescription = null, + tint = BrainwalletTheme.colors.affirm + ) + } else { + Box( + modifier = Modifier + .size(unselectedCircleSize.dp) + .alpha(0.1f) + .clip(CircleShape) + .background(BrainwalletTheme.colors.content) + ) + } + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt new file mode 100644 index 00000000..339584cd --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LitecoinBlockchainDetail.kt @@ -0,0 +1,53 @@ +package com.brainwallet.ui.screens.home.composable.settingsrows + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.brainwallet.R +import com.brainwallet.ui.screens.home.SettingsEvent + +//TODO +@Composable +fun LitecoinBlockchainDetail( + modifier: Modifier = Modifier, + onEvent: (SettingsEvent) -> Unit, +) { + /// Layout values + val contentHeight = 60 + val horizontalPadding = 14 + + SettingRowItemExpandable( + modifier = modifier, + title = stringResource(R.string.blockchain_litecoin) + ) { + Column( + modifier = Modifier.padding(horizontal = horizontalPadding.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + + Row( + modifier = Modifier + .height(contentHeight.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(stringResource(R.string.settings_blockchain_litecoin_description)) + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { + onEvent.invoke(SettingsEvent.OnBlockchainSyncClick) + }) { + Text(stringResource(R.string.settings_blockchain_litecoin_button)) + } + } + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LockSettingRowItem.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LockSettingRowItem.kt new file mode 100644 index 00000000..8f0ab2eb --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/LockSettingRowItem.kt @@ -0,0 +1,20 @@ +package com.brainwallet.ui.screens.home.composable.settingsrows + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Lock +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.brainwallet.R + +@Composable +fun LockSettingRowItem( + onClick: () -> Unit, +) { + SettingRowItem( + title = stringResource(R.string.settings_title_lock), + onClick = onClick + ) { + Icon(Icons.Default.Lock, contentDescription = stringResource(R.string.settings_title_lock)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/SecurityDetail.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/SecurityDetail.kt new file mode 100644 index 00000000..84e86234 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/SecurityDetail.kt @@ -0,0 +1,94 @@ +package com.brainwallet.ui.screens.home.composable.settingsrows + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.brainwallet.R +import com.brainwallet.ui.screens.home.SettingsEvent + +//TODO +@Composable +fun SecurityDetail( + modifier: Modifier = Modifier, + shareAnalyticsDataEnabled: Boolean = false, + onEvent: (SettingsEvent) -> Unit +) { + + /// Layout values + val contentHeight = 60 + val horizontalPadding = 14 + + SettingRowItemExpandable( + modifier = modifier, + title = stringResource(R.string.settings_title_security), + ) { + Column( + modifier = Modifier.padding(horizontal = horizontalPadding.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Row( + modifier = Modifier + .height(contentHeight.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(stringResource(R.string.security_PIN_title)) + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { + onEvent.invoke(SettingsEvent.OnSecurityUpdatePinClick) + }) { + Text(stringResource(R.string.security_PIN_button)) + } + } + + Row( + modifier = Modifier + .height(contentHeight.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(stringResource(R.string.security_seed_phrase_title)) + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { + onEvent.invoke(SettingsEvent.OnSecuritySeedPhraseClick) + }) { + Text(stringResource(R.string.security_phrase_button)) + } + } + +// Row( +// modifier = Modifier +// .height(contentHeight.dp), +// verticalAlignment = Alignment.CenterVertically +// ) { +// Text(stringResource(R.string.security_brainwallet_phrase_title)) +// Spacer(modifier = Modifier.weight(1f)) +// Button(onClick = { +// }) { +// Text(stringResource(R.string.security_phrase_button)) +// } +// } + Row( + modifier = Modifier + .height(contentHeight.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(stringResource(R.string.security_share_data_title)) + Spacer(modifier = Modifier.weight(1f)) + Button(onClick = { + onEvent.invoke(SettingsEvent.OnSecurityShareAnalyticsDataClick) + }) { + Text(stringResource(if (shareAnalyticsDataEnabled) R.string.Button_yes else R.string.Button_no)) + } + } + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/SettingRowItem.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/SettingRowItem.kt new file mode 100644 index 00000000..845e31c2 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/SettingRowItem.kt @@ -0,0 +1,121 @@ +package com.brainwallet.ui.screens.home.composable.settingsrows + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.KeyboardArrowDown +import androidx.compose.material.icons.filled.KeyboardArrowUp +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.ListItem +import androidx.compose.material3.ListItemColors +import androidx.compose.material3.ListItemDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.brainwallet.ui.theme.BrainwalletColors +import com.brainwallet.ui.theme.BrainwalletTheme + +/** + * main composable for [SettingRowItem] and [SettingRowItemExpandable] + */ + +@Composable +fun SettingRowItem( + modifier: Modifier = Modifier, + title: String, + description: String? = null, + onClick: (() -> Unit)? = null, + trailingIcon: @Composable (() -> Unit)? = null, +) { + SettingRowItemExpandable( + modifier = modifier, + title = title, + description = description, + trailingIcon = trailingIcon, + hasExpandedContent = false, + onClick = onClick + ) { } +} + +@Composable +fun SettingRowItemExpandable( + modifier: Modifier = Modifier, + title: String, + description: String? = null, + hasExpandedContent: Boolean = true, + trailingIcon: @Composable (() -> Unit)? = null, + onClick: (() -> Unit)? = null, + colors: ListItemColors = ListItemDefaults.colors( + containerColor = BrainwalletTheme.colors.surface, + headlineColor = BrainwalletTheme.colors.content, + supportingColor = BrainwalletTheme.colors.content.copy(0.6f), + trailingIconColor = BrainwalletTheme.colors.content, + ), + content: @Composable () -> Unit, +) { + var expanded by remember { mutableStateOf(false) } + + /// Layout values + val closedHeight = 60 + val expandedHeight = 100 + val dividerThickness = 1 + val horizontalPadding = 14 + + + Column( + modifier = modifier.background(BrainwalletTheme.colors.settingRowItemBackground(expanded)) + ) { + HorizontalDivider(thickness = dividerThickness.dp, color = BrainwalletTheme.colors.content) + ListItem( + colors = colors, + modifier = Modifier.clickable { + if (hasExpandedContent) { + expanded = expanded.not() + } else { + onClick?.invoke() + } + }, + headlineContent = { + Text( + text = title, + style = BrainwalletTheme.typography.labelLarge + .copy(textAlign = TextAlign.Left) + ) + }, + supportingContent = { + description?.let { Text(text = it) } + }, + trailingContent = { + if (hasExpandedContent) { + Icon( + if (expanded) Icons.Default.KeyboardArrowUp else Icons.Default.KeyboardArrowDown, + contentDescription = null + ) + } else { + trailingIcon?.invoke() + } + } + ) + + AnimatedVisibility( + visible = expanded, + modifier = Modifier.padding(vertical = 8.dp) + ) { + content.invoke() + } + } +} + +fun BrainwalletColors.settingRowItemBackground( + expanded: Boolean = false +) = if (expanded) background else surface \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/ThemeSettingRowItem.kt b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/ThemeSettingRowItem.kt new file mode 100644 index 00000000..98a8b1e5 --- /dev/null +++ b/app/src/main/java/com/brainwallet/ui/screens/home/composable/settingsrows/ThemeSettingRowItem.kt @@ -0,0 +1,32 @@ +package com.brainwallet.ui.screens.home.composable.settingsrows + +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.brainwallet.R +import com.brainwallet.ui.composable.DarkModeToggleButton + +@Composable +fun ThemeSettingRowItem( + darkMode: Boolean = true, + onToggledDarkMode: () -> Unit +) { + val toggleButtonSize = 24 + SettingRowItem( + title = stringResource(R.string.settings_title_theme), + onClick = onToggledDarkMode + ) { + DarkModeToggleButton( + modifier = Modifier + .width(toggleButtonSize.dp) + .aspectRatio(1f), + checked = darkMode, + onCheckedChange = { + onToggledDarkMode.invoke() + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/setpasscode/SetPasscodeState.kt b/app/src/main/java/com/brainwallet/ui/screens/setpasscode/SetPasscodeState.kt index 6ee3206c..c8286b67 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/setpasscode/SetPasscodeState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/setpasscode/SetPasscodeState.kt @@ -4,6 +4,7 @@ data class SetPasscodeState( val isConfirm: Boolean = false, val passcode: List = List(4) { -1 }, //create 4 digit val passcodeConfirm: List = List(4) { -1 }, //create 4 digit + val isUpdatePin: Boolean = false, ) fun SetPasscodeState.isMatchPasscode(): Boolean = diff --git a/app/src/main/java/com/brainwallet/ui/screens/settings/SettingsScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/settings/SettingsScreen.kt deleted file mode 100644 index b3d1f4c0..00000000 --- a/app/src/main/java/com/brainwallet/ui/screens/settings/SettingsScreen.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.brainwallet.ui.screens.settings - -import androidx.compose.runtime.Composable - -@Composable -fun SettingsScreen() { - //todo -} \ No newline at end of file diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockEvent.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockEvent.kt index 1fd49dbc..c83406f9 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockEvent.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockEvent.kt @@ -3,8 +3,14 @@ package com.brainwallet.ui.screens.unlock import android.content.Context sealed class UnLockEvent { - data class OnLoad(val context: Context) : UnLockEvent() - data class OnPinDigitChange(val digit: Int) : UnLockEvent() + data class OnLoad( + val context: Context, + val isUpdatePin: Boolean = false, + ) : UnLockEvent() + data class OnPinDigitChange( + val digit: Int, + val isValidPin: (String) -> Boolean + ) : UnLockEvent() object OnDeletePinDigit : UnLockEvent() } diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockScreen.kt index acd4819d..0ea4da7e 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockScreen.kt @@ -3,6 +3,7 @@ package com.brainwallet.ui.screens.unlock +import android.widget.Toast import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -30,6 +31,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.brainwallet.R import com.brainwallet.navigation.OnNavigate +import com.brainwallet.navigation.UiEffect +import com.brainwallet.tools.manager.AnalyticsManager +import com.brainwallet.tools.security.AuthManager import com.brainwallet.tools.util.BRConstants import com.brainwallet.ui.composable.BrainwalletScaffold import com.brainwallet.ui.composable.BrainwalletTopAppBar @@ -39,17 +43,23 @@ import com.brainwallet.ui.composable.PasscodeKeypadEvent import com.brainwallet.ui.theme.BrainwalletTheme import org.koin.compose.koinInject -//TODO: WIP here @Composable fun UnLockScreen( onNavigate: OnNavigate, + isUpdatePin: Boolean = false, viewModel: UnLockViewModel = koinInject() ) { val state by viewModel.state.collectAsState() val context = LocalContext.current LaunchedEffect(Unit) { - viewModel.onEvent(UnLockEvent.OnLoad(context)) + viewModel.onEvent(UnLockEvent.OnLoad(context, isUpdatePin)) + viewModel.uiEffect.collect { effect -> + when (effect) { + is UiEffect.Navigate -> onNavigate.invoke(effect) + else -> Unit + } + } } LaunchedEffect(state.passcode.all { it > -1 }) { @@ -90,8 +100,12 @@ fun UnLockScreen( ) Spacer(modifier = Modifier.weight(1f)) - Text(stringResource(R.string.Login_ltcPrice, state.formattedCurrency)) - Text(stringResource(R.string.Login_currentLtcPrice, state.iso)) + if (state.isUpdatePin) { + Text(stringResource(R.string.UpdatePin_enterCurrent)) + } else { + Text(stringResource(R.string.Login_ltcPrice, state.formattedCurrency)) + Text(stringResource(R.string.Login_currentLtcPrice, state.iso)) + } // TODO // https://developer.android.com/develop/ui/compose/animation/customize @@ -116,7 +130,28 @@ fun UnLockScreen( PasscodeKeypadEvent.OnDelete -> viewModel.onEvent(UnLockEvent.OnDeletePinDigit) is PasscodeKeypadEvent.OnPressed -> viewModel.onEvent( UnLockEvent.OnPinDigitChange( - digit = passcodeKeypadEvent.digit + digit = passcodeKeypadEvent.digit, + isValidPin = { pin -> + + //provide old logic here, its like on the BrainwalletActivity.onUnlock + return@OnPinDigitChange AuthManager.getInstance() + .checkAuth(pin, context).also { isValid -> + if (isValid) { + AuthManager.getInstance().authSuccess(context) + AnalyticsManager.logCustomEvent(BRConstants._20200217_DUWB) + AnalyticsManager.logCustomEvent(BRConstants._20200217_DUWB) + + } else { + AuthManager.getInstance().authFail(context) + //for now just toast + Toast.makeText( + context, + R.string.incorrect_passcode, + Toast.LENGTH_SHORT + ).show() + } + } + } ) ) } diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockState.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockState.kt index 713b1c95..ff12dab1 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockState.kt @@ -4,7 +4,8 @@ data class UnLockState( val passcode: List = List(4) { -1 }, //4 digit passcode/pin val biometricEnabled: Boolean = false, val iso: String = "USD", - val formattedCurrency: String = "" + val formattedCurrency: String = "", + val isUpdatePin: Boolean = false, ) fun UnLockState.isPasscodeFilled(): Boolean = passcode.all { it > -1 } diff --git a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt index 05277d25..686b562c 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/unlock/UnLockViewModel.kt @@ -1,10 +1,9 @@ package com.brainwallet.ui.screens.unlock import androidx.lifecycle.viewModelScope -import com.brainwallet.navigation.LegacyNavigation -import com.brainwallet.tools.manager.AnalyticsManager +import com.brainwallet.navigation.Route +import com.brainwallet.navigation.UiEffect import com.brainwallet.tools.manager.BRSharedPrefs -import com.brainwallet.tools.security.AuthManager import com.brainwallet.tools.sqlite.CurrencyDataSource import com.brainwallet.tools.util.BRConstants import com.brainwallet.tools.util.BRCurrency @@ -41,10 +40,23 @@ class UnLockViewModel : BrainwalletViewModel() { it.copy(passcode = pinDigits) }.also { + if (it.isPasscodeFilled() && it.isUpdatePin) { + //if update pin from drawer + if (event.isValidPin.invoke(it.passcode.joinToString(""))) { + sendUiEffect( + UiEffect.Navigate( + destinationRoute = Route.SetPasscode() + ) + ) + } + return + } + if (it.isPasscodeFilled()) { viewModelScope.launch { EventBus.emit(EventBus.Event.LegacyUnLock(it.passcode)) } + return } } @@ -80,7 +92,12 @@ class UnLockViewModel : BrainwalletViewModel() { if (formattedCurrency != null) { _state.update { - it.copy(iso = iso, formattedCurrency = formattedCurrency) + it.copy( + iso = iso, + formattedCurrency = formattedCurrency, + isUpdatePin = event.isUpdatePin + ) + } } } diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt index 77104115..da80ef85 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeScreen.kt @@ -49,6 +49,7 @@ import com.brainwallet.navigation.Route import com.brainwallet.navigation.UiEffect import com.brainwallet.ui.composable.BorderedLargeButton import com.brainwallet.ui.composable.BrainwalletButton +import com.brainwallet.ui.composable.DarkModeToggleButton import com.brainwallet.ui.composable.bottomsheet.FiatSelectorBottomSheet import com.brainwallet.ui.composable.bottomsheet.LanguageSelectorBottomSheet import com.brainwallet.ui.theme.BrainwalletTheme @@ -157,32 +158,7 @@ fun WelcomeScreen( onCheckedChange = { viewModel.onEvent(WelcomeEvent.OnToggleDarkMode) } - ) { - - Box( - modifier = Modifier - .fillMaxSize() - .width(iconButtonSize.dp) - .aspectRatio(1f) - .clip(CircleShape) - .border( - 1.dp, - if (state.darkMode) BrainwalletTheme.colors.warn else BrainwalletTheme.colors.surface, - CircleShape - ) - .background(if (state.darkMode) BrainwalletTheme.colors.surface else BrainwalletTheme.colors.content) - ) { - Icon( - modifier = Modifier - .align(Alignment.Center) - .width(iconButtonSize.dp) - .aspectRatio(1f), - tint = if (state.darkMode) BrainwalletTheme.colors.warn else BrainwalletTheme.colors.surface, - painter = painterResource(if (state.darkMode) R.drawable.ic_light_mode else R.drawable.ic_dark_mode), - contentDescription = stringResource(R.string.toggle_dark_mode), - ) - } - } + ) Spacer(modifier = Modifier.weight(0.2f)) @@ -272,20 +248,6 @@ fun WelcomeScreen( } } -@Composable -fun DarkModeToggleButton( - checked: Boolean, - onCheckedChange: (Boolean) -> Unit, - modifier: Modifier = Modifier, - content: @Composable () -> Unit -) { - IconToggleButton( - checked = checked, - onCheckedChange = onCheckedChange, - modifier = modifier, - content = content - ) -} @Preview @Composable diff --git a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeState.kt b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeState.kt index 12ac4d0f..415f1333 100644 --- a/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeState.kt +++ b/app/src/main/java/com/brainwallet/ui/screens/welcome/WelcomeState.kt @@ -8,8 +8,9 @@ data class WelcomeState( val selectedLanguage: Language = Language.ENGLISH, val selectedCurrency: CurrencyEntity = CurrencyEntity( "USD", - "USD", - -1f + "US Dollar", + -1f, + "$" ), //-1 = need to fetch val languageSelectorBottomSheetVisible: Boolean = false, val fiatSelectorBottomSheetVisible: Boolean = false, diff --git a/app/src/main/java/com/brainwallet/ui/theme/Theme.kt b/app/src/main/java/com/brainwallet/ui/theme/Theme.kt index 315ab497..819eb43e 100644 --- a/app/src/main/java/com/brainwallet/ui/theme/Theme.kt +++ b/app/src/main/java/com/brainwallet/ui/theme/Theme.kt @@ -1,9 +1,11 @@ package com.brainwallet.ui.theme import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Typography import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.Immutable +import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.ComposeView @@ -79,6 +81,9 @@ object BrainwalletTheme { @Composable get() = LocalBrainwalletColors.current + val typography: Typography + @Composable @ReadOnlyComposable get() = MaterialTheme.typography + //todo: add typography, shape? for the design system } diff --git a/app/src/main/java/com/brainwallet/util/EventBus.kt b/app/src/main/java/com/brainwallet/util/EventBus.kt index 8c6ed440..313358db 100644 --- a/app/src/main/java/com/brainwallet/util/EventBus.kt +++ b/app/src/main/java/com/brainwallet/util/EventBus.kt @@ -28,7 +28,7 @@ object EventBus { //provide this for old flow data class LegacyPasscodeVerified( - val passcode: List + val passcode: List, ) : Event() data class LegacyUnLock( diff --git a/app/src/main/res/drawable-hdpi/ic_nav_spend.png b/app/src/main/res/drawable-hdpi/ic_nav_spend.png deleted file mode 100644 index 8d0979c0..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_nav_spend.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/import_symbol.png b/app/src/main/res/drawable-hdpi/import_symbol.png deleted file mode 100644 index a3df0f90..00000000 Binary files a/app/src/main/res/drawable-hdpi/import_symbol.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/restore_image.png b/app/src/main/res/drawable-hdpi/restore_image.png deleted file mode 100644 index d2335bd7..00000000 Binary files a/app/src/main/res/drawable-hdpi/restore_image.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_nav_spend.png b/app/src/main/res/drawable-mdpi/ic_nav_spend.png deleted file mode 100644 index e84e69ba..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_nav_spend.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/import_symbol.png b/app/src/main/res/drawable-mdpi/import_symbol.png deleted file mode 100644 index 2f60e656..00000000 Binary files a/app/src/main/res/drawable-mdpi/import_symbol.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/restore_image.png b/app/src/main/res/drawable-mdpi/restore_image.png deleted file mode 100644 index a0e12fb9..00000000 Binary files a/app/src/main/res/drawable-mdpi/restore_image.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_nav_spend.png b/app/src/main/res/drawable-xhdpi/ic_nav_spend.png deleted file mode 100644 index 5a805981..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_nav_spend.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/import_symbol.png b/app/src/main/res/drawable-xhdpi/import_symbol.png deleted file mode 100644 index dd0a4935..00000000 Binary files a/app/src/main/res/drawable-xhdpi/import_symbol.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/restore_image.png b/app/src/main/res/drawable-xhdpi/restore_image.png deleted file mode 100644 index 3dfc1843..00000000 Binary files a/app/src/main/res/drawable-xhdpi/restore_image.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_nav_spend.png b/app/src/main/res/drawable-xxhdpi/ic_nav_spend.png deleted file mode 100644 index 4dfcdb19..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_nav_spend.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/import_symbol.png b/app/src/main/res/drawable-xxhdpi/import_symbol.png deleted file mode 100644 index f3bb9063..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/import_symbol.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/restore_image.png b/app/src/main/res/drawable-xxhdpi/restore_image.png deleted file mode 100644 index d3479ac3..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/restore_image.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_nav_spend.png b/app/src/main/res/drawable-xxxhdpi/ic_nav_spend.png deleted file mode 100644 index 0e4951a0..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_nav_spend.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/import_symbol.png b/app/src/main/res/drawable-xxxhdpi/import_symbol.png deleted file mode 100644 index d95e2e36..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/import_symbol.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/restore_image.png b/app/src/main/res/drawable-xxxhdpi/restore_image.png deleted file mode 100644 index 16a2ee4b..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/restore_image.png and /dev/null differ diff --git a/app/src/main/res/drawable/copy_icon.png b/app/src/main/res/drawable/copy_icon.png new file mode 100644 index 00000000..243729b1 Binary files /dev/null and b/app/src/main/res/drawable/copy_icon.png differ diff --git a/app/src/main/res/drawable/ic_bread_logo_white.xml b/app/src/main/res/drawable/ic_bread_logo_white.xml deleted file mode 100644 index 7ba8d331..00000000 --- a/app/src/main/res/drawable/ic_bread_logo_white.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_bread.xml b/app/src/main/res/layout/activity_bread.xml index 5fb9763b..7ad85ca9 100644 --- a/app/src/main/res/layout/activity_bread.xml +++ b/app/src/main/res/layout/activity_bread.xml @@ -1,139 +1,168 @@ - - - + + - - + + + + android:clipToPadding="false" + android:descendantFocusability="beforeDescendants" + android:filterTouchesWhenObscured="true" + android:fitsSystemWindows="true" + android:focusableInTouchMode="true" + tools:context="com.brainwallet.presenter.activities.BreadActivity"> - + android:elevation="8dp" + android:orientation="vertical"> - - - - -