diff --git a/app/build.gradle b/app/build.gradle index 3a34905..4746b27 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,13 +6,12 @@ static def buildTime() { android { compileSdkVersion compile_version - buildToolsVersion build_tools_version defaultConfig { applicationId "io.xdag.xdagwallet" minSdkVersion min_version targetSdkVersion target_version - versionCode 24 - versionName "0.2.4" + versionCode 25 + versionName "0.2.5" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { @@ -74,8 +73,6 @@ dependencies { implementation 'com.tapadoo.android:alerter:2.0.5' // https://github.com/yanzhenjie/AndPermission implementation 'com.yanzhenjie:permission:2.0.0-rc6' - // https://github.com/aurelhubert/ahbottomnavigation - implementation 'com.aurelhubert:ahbottomnavigation:2.1.0' // https://github.com/PureWriter/about-page implementation 'me.drakeet.support:about:2.1.1' implementation 'me.drakeet.multitype:multitype:3.4.4' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9ca5744..30abb00 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -14,7 +15,8 @@ android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme" + tools:ignore="GoogleAppIndexingWarning"> diff --git a/app/src/main/java/io/xdag/xdagwallet/MainActivity.java b/app/src/main/java/io/xdag/xdagwallet/MainActivity.java index 0ac4b3c..2d04d93 100644 --- a/app/src/main/java/io/xdag/xdagwallet/MainActivity.java +++ b/app/src/main/java/io/xdag/xdagwallet/MainActivity.java @@ -7,11 +7,8 @@ import android.support.v4.app.FragmentManager; import android.view.View; import butterknife.BindView; -import com.aurelhubert.ahbottomnavigation.AHBottomNavigation; -import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem; import com.yanzhenjie.permission.AndPermission; import com.yanzhenjie.permission.Permission; -import io.xdag.common.Common; import io.xdag.common.base.ToolbarActivity; import io.xdag.common.tool.ActivityStack; import io.xdag.common.tool.ToolbarMode; @@ -23,6 +20,8 @@ import io.xdag.xdagwallet.fragment.SendFragment; import io.xdag.xdagwallet.util.AlertUtil; import io.xdag.xdagwallet.util.ToolbarUtil; +import io.xdag.xdagwallet.widget.BottomBar; +import io.xdag.xdagwallet.widget.BottomBarItem; import io.xdag.xdagwallet.wrapper.XdagEvent; import io.xdag.xdagwallet.wrapper.XdagEventManager; import io.xdag.xdagwallet.wrapper.XdagHandlerWrapper; @@ -39,9 +38,8 @@ public class MainActivity extends ToolbarActivity { private static final String EXTRA_RESTORE = "extra_restore"; private static final String EXTRA_SWITCH_POOL = "extra_switch_pool"; - public static boolean isStart = false; @BindView(R.id.bottom_navigation) - AHBottomNavigation mNavigationView; + BottomBar mBottomBar; private FragmentManager mFragmentManager; private HomeFragment mHomeFragment; @@ -56,7 +54,6 @@ public class MainActivity extends ToolbarActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - isStart = true; ActivityStack.getInstance().finishNotTopActivities(); } @@ -72,6 +69,7 @@ protected boolean enableEventBus() { return true; } + @Override protected void initView(View rootView, Bundle savedInstanceState) { mFragmentManager = getSupportFragmentManager(); @@ -80,7 +78,7 @@ protected void initView(View rootView, Bundle savedInstanceState) { } else { recoverFragment(); } - initNavigationView(); + initBottomBar(); } @@ -131,7 +129,7 @@ protected void onNewIntent(Intent intent) { XdagHandlerWrapper.getInstance(this).disconnectPool(); mHomeFragment.showNotReady(); showFragment(mHomeFragment); - mNavigationView.setCurrentItem(mHomeFragment.getPosition()); + mBottomBar.setCurrentItem(mHomeFragment.getPosition()); } } @@ -151,34 +149,23 @@ public void ProcessXdagEvent(XdagEvent event) { } - private void initNavigationView() { - // create items - AHBottomNavigationItem home = - new AHBottomNavigationItem(getString(R.string.home), R.drawable.ic_home); - AHBottomNavigationItem receive = - new AHBottomNavigationItem(getString(R.string.receive), R.drawable.ic_receive); - AHBottomNavigationItem send = - new AHBottomNavigationItem(getString(R.string.send), R.drawable.ic_send); - AHBottomNavigationItem setting = - new AHBottomNavigationItem(getString(R.string.more), R.drawable.ic_more); - // add items - mNavigationView.addItem(home); - mNavigationView.addItem(receive); - mNavigationView.addItem(send); - mNavigationView.addItem(setting); - // the selectedImage item color - mNavigationView.setAccentColor(Common.getColor(R.color.colorPrimary)); - // the unselected item color - mNavigationView.setInactiveColor(Common.getColor(R.color.GERY)); - // set titles - mNavigationView.setTitleState(AHBottomNavigation.TitleState.ALWAYS_SHOW); - // set current item selectedImage - mNavigationView.setCurrentItem(0); - ToolbarUtil.setToolbar(0, getToolbar()); - // set listeners - mNavigationView.setOnTabSelectedListener(new AHBottomNavigation.OnTabSelectedListener() { - @Override - public boolean onTabSelected(int position, boolean wasSelected) { + private void initBottomBar() { + + mBottomBar.addItem( + new BottomBarItem(mContext, R.mipmap.ic_home, R.mipmap.ic_home_unselected, + getString(R.string.home))); + mBottomBar.addItem( + new BottomBarItem(mContext, R.mipmap.ic_receive, R.mipmap.ic_receive_unselected, + getString(R.string.receive))); + mBottomBar.addItem( + new BottomBarItem(mContext, R.mipmap.ic_send, R.mipmap.ic_send_unselected, + getString(R.string.send))); + mBottomBar.addItem( + new BottomBarItem(mContext, R.mipmap.ic_more, R.mipmap.ic_more_unselected, + getString(R.string.setting))); + + mBottomBar.setOnTabSelectedListener(new BottomBar.OnTabSelectedListener() { + @Override public void onTabSelected(int position, int prePosition) { switch (position) { case 0: showFragment(mHomeFragment); @@ -193,8 +180,13 @@ public boolean onTabSelected(int position, boolean wasSelected) { showFragment(mSettingFragment); break; } - return true; } + + + @Override public void onTabUnselected(int position) { } + + + @Override public void onTabReselected(int position) { } }); } diff --git a/app/src/main/java/io/xdag/xdagwallet/activity/TranDetailActivity.java b/app/src/main/java/io/xdag/xdagwallet/activity/TranDetailActivity.java index ea3196c..c87c972 100644 --- a/app/src/main/java/io/xdag/xdagwallet/activity/TranDetailActivity.java +++ b/app/src/main/java/io/xdag/xdagwallet/activity/TranDetailActivity.java @@ -56,7 +56,7 @@ public void onRefresh() { private void requestTranDetail(final boolean alert) { mDisposable.add( - HttpRequest.get().getBlockDetail(mContext, mAddress, + HttpRequest.get().getTransactionDetail(mContext, mAddress, blockAsAddresses -> showTransaction(blockAsAddresses, alert)) ); } diff --git a/app/src/main/java/io/xdag/xdagwallet/activity/UsageActivity.java b/app/src/main/java/io/xdag/xdagwallet/activity/UsageActivity.java index 03a3e4d..4258b78 100644 --- a/app/src/main/java/io/xdag/xdagwallet/activity/UsageActivity.java +++ b/app/src/main/java/io/xdag/xdagwallet/activity/UsageActivity.java @@ -87,7 +87,7 @@ protected void initView(View rootView, Bundle savedInstanceState) { if (mCbRootRemind.isChecked()) { Config.setNotRemindRoot(true); } - if (isNotShow()) { + if (isNotDisplay()) { WalletActivity.start(mContext); finish(); } @@ -99,7 +99,7 @@ protected void initView(View rootView, Bundle savedInstanceState) { mContext.finish(); }); builder.show(); - } else if (isNotShow()) { + } else if (isNotDisplay()) { WalletActivity.start(mContext); finish(); } else { @@ -116,7 +116,7 @@ void explain_btn_start() { return; } WalletActivity.start(mContext); - if (isNotShow()) { + if (isNotDisplay()) { finish(); } } @@ -128,7 +128,7 @@ void explain_btn_pool() { } - public static boolean isNotShow() { + public static boolean isNotDisplay() { return Config.isUserBackup() && Config.isNotDisplayUsage(); } @@ -163,8 +163,5 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { @Override protected void onDestroy() { RxUtil.dispose(mDisposable); super.onDestroy(); - if (!MainActivity.isStart) { - ActivityStack.getInstance().exit(); - } } } diff --git a/app/src/main/java/io/xdag/xdagwallet/activity/WalletActivity.java b/app/src/main/java/io/xdag/xdagwallet/activity/WalletActivity.java index eeaeda4..0153a76 100644 --- a/app/src/main/java/io/xdag/xdagwallet/activity/WalletActivity.java +++ b/app/src/main/java/io/xdag/xdagwallet/activity/WalletActivity.java @@ -27,14 +27,6 @@ public class WalletActivity extends ToolbarActivity { @BindView(R.id.wallet_tv_function_text) TextView mTvFunction; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - setTheme(R.style.AppTheme); - super.onCreate(savedInstanceState); - } - - @Override protected int getLayoutResId() { return R.layout.activity_wallet; @@ -87,7 +79,6 @@ void wallet_btn_restore() { .onGranted(data -> { if (XdagHandlerWrapper.createSDCardFile(mContext) != null) { RestoreActivity.start(mContext); - finish(); } }) .start(); @@ -108,7 +99,7 @@ protected int getToolbarTitle() { @Override protected int getToolbarMode() { - if (UsageActivity.isNotShow()) { + if (UsageActivity.isNotDisplay()) { return ToolbarMode.MODE_NONE; } return ToolbarMode.MODE_BACK; diff --git a/app/src/main/java/io/xdag/xdagwallet/dialog/InputBuilder.java b/app/src/main/java/io/xdag/xdagwallet/dialog/InputBuilder.java index f662e8d..ccaf025 100644 --- a/app/src/main/java/io/xdag/xdagwallet/dialog/InputBuilder.java +++ b/app/src/main/java/io/xdag/xdagwallet/dialog/InputBuilder.java @@ -30,7 +30,6 @@ protected void init() { View view = View.inflate(getContext(), R.layout.layout_dialog_input, null); setView(view); mEtInput = view.findViewById(R.id.dialog_input_et); - setCancelable(false); setPositiveButton(R.string.ensure, (dialog, which) -> { if (mOnPositiveClickListener != null) { mOnPositiveClickListener.onClick(dialog, mEtInput.getText().toString()); diff --git a/app/src/main/java/io/xdag/xdagwallet/dialog/LoadingBuilder.java b/app/src/main/java/io/xdag/xdagwallet/dialog/LoadingBuilder.java index b0e335c..7229214 100644 --- a/app/src/main/java/io/xdag/xdagwallet/dialog/LoadingBuilder.java +++ b/app/src/main/java/io/xdag/xdagwallet/dialog/LoadingBuilder.java @@ -24,7 +24,6 @@ protected void init() { super.init(); View view = View.inflate(getContext(), R.layout.layout_dialog_loading, null); setView(view); - setCancelable(false); mTvMessage = view.findViewById(R.id.dialog_loading_tv); } diff --git a/app/src/main/java/io/xdag/xdagwallet/dialog/TipBuilder.java b/app/src/main/java/io/xdag/xdagwallet/dialog/TipBuilder.java index c69901e..712b100 100644 --- a/app/src/main/java/io/xdag/xdagwallet/dialog/TipBuilder.java +++ b/app/src/main/java/io/xdag/xdagwallet/dialog/TipBuilder.java @@ -4,7 +4,6 @@ import android.content.DialogInterface; import android.support.annotation.NonNull; import android.support.v7.app.AlertDialog; - import io.xdag.common.base.AlertBuilder; import io.xdag.xdagwallet.R; @@ -13,16 +12,10 @@ */ public class TipBuilder extends AlertBuilder { - public TipBuilder(@NonNull Context context) { super(context); } - @Override - protected void init() { - super.init(); - setCancelable(false); - } public AlertDialog.Builder setPositiveListener(DialogInterface.OnClickListener listener) { setPositiveButton(R.string.ensure, listener); diff --git a/app/src/main/java/io/xdag/xdagwallet/fragment/HomeFragment.java b/app/src/main/java/io/xdag/xdagwallet/fragment/HomeFragment.java index caac02d..375f4cb 100644 --- a/app/src/main/java/io/xdag/xdagwallet/fragment/HomeFragment.java +++ b/app/src/main/java/io/xdag/xdagwallet/fragment/HomeFragment.java @@ -130,7 +130,7 @@ private void requestUpdate() { private void requestTransaction() { mDisposable.add(HttpRequest.get() - .getBlockList(mContext, mTvAddress.getText().toString(), this::showTransaction)); + .getTransactions(mContext, mTvAddress.getText().toString(), this::showTransaction)); } diff --git a/app/src/main/java/io/xdag/xdagwallet/net/ApiServer.java b/app/src/main/java/io/xdag/xdagwallet/net/ApiServer.java index ebf8088..d5575ef 100644 --- a/app/src/main/java/io/xdag/xdagwallet/net/ApiServer.java +++ b/app/src/main/java/io/xdag/xdagwallet/net/ApiServer.java @@ -1,6 +1,7 @@ package io.xdag.xdagwallet.net; import io.xdag.common.http.ApiFactory; +import io.xdag.xdagwallet.config.Config; import io.xdag.xdagwallet.net.api.ConfigApi; import io.xdag.xdagwallet.net.api.TransactionApi; @@ -12,18 +13,18 @@ public class ApiServer { public static final String BASE_URL_TRANSACTION = "https://explorer.xdag.io/api/block/"; - public static final String BASE_URL_TRANSACTION2 = "http://139.99.124.100/api/block/"; private static final String BASE_URL_GITHUB = "https://raw.githubusercontent.com/"; private ApiServer() { throw new UnsupportedOperationException("ApiServer cannot be instantiated !"); } - static TransactionApi getTransactionApi(String baseUrl) { + static TransactionApi createTransactionApi() { + String baseUrl = Config.getTransactionHost(); return ApiFactory.getInstance().createApi(baseUrl, TransactionApi.class); } - static ConfigApi getConfigApi() { + static ConfigApi createConfigApi() { return ApiFactory.getInstance().createApi(BASE_URL_GITHUB, ConfigApi.class); } } diff --git a/app/src/main/java/io/xdag/xdagwallet/net/HttpRequest.java b/app/src/main/java/io/xdag/xdagwallet/net/HttpRequest.java index c7830d2..e2b39ae 100644 --- a/app/src/main/java/io/xdag/xdagwallet/net/HttpRequest.java +++ b/app/src/main/java/io/xdag/xdagwallet/net/HttpRequest.java @@ -9,10 +9,8 @@ import io.xdag.xdagwallet.model.ConfigModel; import io.xdag.xdagwallet.model.VersionModel; import io.xdag.xdagwallet.net.error.ErrorConsumer; -import io.xdag.xdagwallet.net.error.NoTransactionException; import io.xdag.xdagwallet.net.rx.Detail2AddressListFunction; import io.xdag.xdagwallet.net.rx.Detail2TranListFunction; -import io.xdag.xdagwallet.util.AlertUtil; import java.util.List; /** @@ -22,70 +20,43 @@ public class HttpRequest { private static final HttpRequest sInstance = new HttpRequest(); + public static HttpRequest get() { return sInstance; } + private HttpRequest() { } public Disposable getConfigInfo(Consumer consumer) { - return ApiServer.getConfigApi().getConfigInfo() + return ApiServer.createConfigApi().getConfigInfo() .observeOn(AndroidSchedulers.mainThread()) .subscribe(consumer, new ErrorConsumer()); } public Disposable getVersionInfo(Consumer consumer) { - return ApiServer.getConfigApi().getVersionInfo() + return ApiServer.createConfigApi().getVersionInfo() .observeOn(AndroidSchedulers.mainThread()) .subscribe(consumer, new ErrorConsumer()); } - public Disposable getBlockList(Activity activity, String address, Consumer> consumer) { - String baseUrl = Config.getTransactionHost(); - return ApiServer.getTransactionApi(baseUrl).getBlockDetail(address) + public Disposable getTransactions(Activity activity, String address, Consumer> consumer) { + return ApiServer.createTransactionApi().getBlockDetail(address) .observeOn(AndroidSchedulers.mainThread()) .map(new Detail2AddressListFunction()) - .subscribe(consumer, throwable -> { - - // no transaction - if (throwable instanceof NoTransactionException) { - AlertUtil.show(activity, throwable.getMessage()); - return; - } - - // if failed request api2 again - ApiServer.getTransactionApi(ApiServer.BASE_URL_TRANSACTION2) - .getBlockDetail(address) - .observeOn(AndroidSchedulers.mainThread()) - .map(new Detail2AddressListFunction()) - .subscribe(consumer, new ErrorConsumer(activity)); - }); + .subscribe(consumer, new ErrorConsumer(activity)); } - public Disposable getBlockDetail(Activity activity, String address, Consumer> consumer) { - String baseUrl = Config.getTransactionHost(); - return ApiServer.getTransactionApi(baseUrl).getBlockDetail(address) + + public Disposable getTransactionDetail(Activity activity, String address, Consumer> consumer) { + return ApiServer.createTransactionApi().getBlockDetail(address) .observeOn(AndroidSchedulers.mainThread()) .map(new Detail2TranListFunction()) - .subscribe(consumer, throwable -> { - - // no transaction - if (throwable instanceof NoTransactionException) { - AlertUtil.show(activity, throwable.getMessage()); - return; - } - - // if failed request api2 again - ApiServer.getTransactionApi(ApiServer.BASE_URL_TRANSACTION2) - .getBlockDetail(address) - .observeOn(AndroidSchedulers.mainThread()) - .map(new Detail2TranListFunction()) - .subscribe(consumer, new ErrorConsumer(activity)); - }); + .subscribe(consumer, new ErrorConsumer(activity)); } } diff --git a/app/src/main/java/io/xdag/xdagwallet/net/error/ErrorConsumer.java b/app/src/main/java/io/xdag/xdagwallet/net/error/ErrorConsumer.java index 1e74c65..4f1b50d 100644 --- a/app/src/main/java/io/xdag/xdagwallet/net/error/ErrorConsumer.java +++ b/app/src/main/java/io/xdag/xdagwallet/net/error/ErrorConsumer.java @@ -1,9 +1,14 @@ package io.xdag.xdagwallet.net.error; import android.app.Activity; +import android.text.TextUtils; +import com.google.gson.Gson; import io.reactivex.functions.Consumer; import io.xdag.common.tool.MLog; import io.xdag.xdagwallet.util.AlertUtil; +import java.io.IOException; +import okhttp3.ResponseBody; +import retrofit2.HttpException; /** * created by lxm on 2018/7/19. @@ -13,10 +18,13 @@ public class ErrorConsumer implements Consumer { private Activity activity; + private static final Gson gson = new Gson(); + public ErrorConsumer() { } + public ErrorConsumer(Activity activity) { this.activity = activity; } @@ -24,8 +32,24 @@ public ErrorConsumer(Activity activity) { @Override public void accept(Throwable throwable) { MLog.i(throwable.getMessage()); - if(activity != null) { - AlertUtil.show(activity, throwable.getMessage()); + String errorMessage = throwable.getMessage(); + if (throwable instanceof HttpException) { + // parse error message + HttpException httpException = (HttpException) throwable; + try { + ResponseBody errorBody = httpException.response().errorBody(); + if (errorBody != null) { + ErrorResponse errorResponse = gson.fromJson(errorBody.string(), + ErrorResponse.class); + if (errorResponse != null && !TextUtils.isEmpty(errorResponse.message)) { + errorMessage = errorResponse.message; + } + + } + } catch (IOException ignored) { + } + } + AlertUtil.show(activity, errorMessage); } } diff --git a/app/src/main/java/io/xdag/xdagwallet/util/AlertUtil.java b/app/src/main/java/io/xdag/xdagwallet/util/AlertUtil.java index e801b44..165c6f1 100644 --- a/app/src/main/java/io/xdag/xdagwallet/util/AlertUtil.java +++ b/app/src/main/java/io/xdag/xdagwallet/util/AlertUtil.java @@ -4,6 +4,7 @@ import com.tapadoo.alerter.Alerter; +import io.xdag.common.util.ToastUtil; import io.xdag.xdagwallet.R; /** @@ -22,12 +23,17 @@ public static void show(Activity activity, int res) { public static void show(Activity activity, String message) { - Alerter.create(activity) + if (activity != null) { + Alerter.create(activity) .setDuration(ALERT_DURATION) .hideIcon() .setTextAppearance(R.style.AlertTextStyle) .setBackgroundColorRes(R.color.colorAccent) .setText(message) .show(); + } else { + ToastUtil.showCenter(message); + } + } } diff --git a/app/src/main/java/io/xdag/xdagwallet/util/ToolbarUtil.java b/app/src/main/java/io/xdag/xdagwallet/util/ToolbarUtil.java index 049224b..61ab611 100644 --- a/app/src/main/java/io/xdag/xdagwallet/util/ToolbarUtil.java +++ b/app/src/main/java/io/xdag/xdagwallet/util/ToolbarUtil.java @@ -2,9 +2,6 @@ import android.support.v7.widget.Toolbar; import android.view.View; -import android.widget.LinearLayout; - -import io.xdag.xdagwallet.BuildConfig; import io.xdag.xdagwallet.R; /** diff --git a/app/src/main/java/io/xdag/xdagwallet/util/UpdateUtil.java b/app/src/main/java/io/xdag/xdagwallet/util/UpdateUtil.java index 3f16f43..c6db4ee 100644 --- a/app/src/main/java/io/xdag/xdagwallet/util/UpdateUtil.java +++ b/app/src/main/java/io/xdag/xdagwallet/util/UpdateUtil.java @@ -22,19 +22,9 @@ public static void update(final VersionModel versionModel, final LinearLayout ve versionLayout.setVisibility(View.VISIBLE); tvDesc.setText(context.getString(R.string.new_version_available, versionModel.versionName)); - tvUpdate.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - IntentUtil.openBrowser(context, versionModel.url); - } - }); - - tvClose.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - versionLayout.setVisibility(View.GONE); - } - }); + tvUpdate.setOnClickListener(v -> IntentUtil.openBrowser(context, versionModel.url)); + + tvClose.setOnClickListener(v -> versionLayout.setVisibility(View.GONE)); } else { versionLayout.setVisibility(View.GONE); diff --git a/app/src/main/java/io/xdag/xdagwallet/widget/BottomBar.java b/app/src/main/java/io/xdag/xdagwallet/widget/BottomBar.java new file mode 100755 index 0000000..c90b711 --- /dev/null +++ b/app/src/main/java/io/xdag/xdagwallet/widget/BottomBar.java @@ -0,0 +1,211 @@ +package io.xdag.xdagwallet.widget; + +import android.content.Context; +import android.graphics.Color; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Interpolator; +import android.widget.LinearLayout; +import java.util.ArrayList; +import java.util.List; + +public class BottomBar extends LinearLayout { + private static final int TRANSLATE_DURATION_MILLIS = 200; + + private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator(); + private boolean mVisible = true; + + private List mTabs = new ArrayList<>(); + + private LinearLayout mTabLayout; + + private LayoutParams mTabParams; + private int mCurrentPosition = 0; + private OnTabSelectedListener mListener; + + public BottomBar(Context context) { + this(context, null); + } + + public BottomBar(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BottomBar(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + setOrientation(VERTICAL); + + mTabLayout = new LinearLayout(context); + mTabLayout.setBackgroundColor(Color.WHITE); + mTabLayout.setOrientation(LinearLayout.HORIZONTAL); + addView(mTabLayout, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + + mTabParams = new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT); + mTabParams.weight = 1; + } + + public BottomBar addItem(final BottomBarItem tab) { + tab.setOnClickListener(v -> { + if (mListener == null) return; + + int pos = tab.getTabPosition(); + if (mCurrentPosition == pos) { + mListener.onTabReselected(pos); + } else { + mListener.onTabSelected(pos, mCurrentPosition); + tab.setSelected(true); + mListener.onTabUnselected(mCurrentPosition); + mTabs.get(mCurrentPosition).setSelected(false); + mCurrentPosition = pos; + } + }); + tab.setTabPosition(mTabLayout.getChildCount()); + tab.setLayoutParams(mTabParams); + mTabLayout.addView(tab); + mTabs.add(tab); + return this; + } + + public void setOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) { + mListener = onTabSelectedListener; + } + + public void setCurrentItem(final int position) { + mTabLayout.post(new Runnable() { + @Override + public void run() { + mTabLayout.getChildAt(position).performClick(); + } + }); + } + + public int getCurrentItemPosition() { + return mCurrentPosition; + } + + /** + * 获取 Tab + */ + public BottomBarItem getItem(int index) { + if (mTabs.size() < index) return null; + return mTabs.get(index); + } + + public interface OnTabSelectedListener { + void onTabSelected(int position, int prePosition); + + void onTabUnselected(int position); + + void onTabReselected(int position); + } + + @Override + protected Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + return new SavedState(superState, mCurrentPosition); + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + + if (mCurrentPosition != ss.position) { + mTabLayout.getChildAt(mCurrentPosition).setSelected(false); + mTabLayout.getChildAt(ss.position).setSelected(true); + } + mCurrentPosition = ss.position; + } + + static class SavedState extends BaseSavedState { + private int position; + + public SavedState(Parcel source) { + super(source); + position = source.readInt(); + } + + public SavedState(Parcelable superState, int position) { + super(superState); + this.position = position; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(position); + } + + public static final Creator CREATOR = new Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + + public void hide() { + hide(true); + } + + public void show() { + show(true); + } + + public void hide(boolean anim) { + toggle(false, anim, false); + } + + public void show(boolean anim) { + toggle(true, anim, false); + } + + public boolean isVisible() { + return mVisible; + } + + private void toggle(final boolean visible, final boolean animate, boolean force) { + if (mVisible != visible || force) { + mVisible = visible; + int height = getHeight(); + if (height == 0 && !force) { + ViewTreeObserver vto = getViewTreeObserver(); + if (vto.isAlive()) { + // view 树完成测量并且分配空间而绘制过程还没有开始的时候播放动画。 + vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + ViewTreeObserver currentVto = getViewTreeObserver(); + if (currentVto.isAlive()) { + currentVto.removeOnPreDrawListener(this); + } + toggle(visible, animate, true); + return true; + } + }); + return; + } + } + int translationY = visible ? 0 : height; + if (animate) { + animate().setInterpolator(mInterpolator) + .setDuration(TRANSLATE_DURATION_MILLIS) + .translationY(translationY); + } else { + setTranslationY(translationY); + } + } + } +} diff --git a/app/src/main/java/io/xdag/xdagwallet/widget/BottomBarItem.java b/app/src/main/java/io/xdag/xdagwallet/widget/BottomBarItem.java new file mode 100755 index 0000000..2c1d8f6 --- /dev/null +++ b/app/src/main/java/io/xdag/xdagwallet/widget/BottomBarItem.java @@ -0,0 +1,175 @@ +package io.xdag.xdagwallet.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.support.annotation.DrawableRes; +import android.support.v4.content.ContextCompat; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import io.xdag.xdagwallet.R; + +@SuppressLint("ViewConstructor") +public class BottomBarItem extends FrameLayout { + private static final int DEFAULT_ICON_UNSELECTED = -1; + private ImageView mIconImageView; + private int mIconUnSelected; + private int mIcon; + private TextView mTvTitle; + private Context mContext; + private int mTabPosition = -1; + + private TextView mTvUnreadCount; + + public BottomBarItem(Context context, @DrawableRes int icon, CharSequence title) { + this(context, icon, DEFAULT_ICON_UNSELECTED, title); + } + + public BottomBarItem(Context context, @DrawableRes int icon, @DrawableRes + int iconUnselected, CharSequence title) { + super(context, null, 0); + init(context, icon, iconUnselected, title); + } + + + private void init(Context context, int icon, int iconUnselected, CharSequence title) { + mContext = context; + TypedArray typedArray = context.obtainStyledAttributes(new int[]{R.attr.selectableItemBackgroundBorderless}); + Drawable drawable = typedArray.getDrawable(0); + setBackground(drawable); + typedArray.recycle(); + + LinearLayout lLContainer = new LinearLayout(context); + lLContainer.setOrientation(LinearLayout.VERTICAL); + lLContainer.setGravity(Gravity.CENTER); + LayoutParams paramsContainer = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + paramsContainer.gravity = Gravity.CENTER; + lLContainer.setLayoutParams(paramsContainer); + + mIcon = icon; + mIconUnSelected = iconUnselected; + mIconImageView = new ImageView(context); + int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics()); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(size, size); + if (isColorFilterMode()) { + mIconImageView.setImageResource(icon); + mIconImageView.setColorFilter(ContextCompat.getColor(context, R.color.bottom_bar_un_selected)); + } else { + mIconImageView.setImageResource(mIconUnSelected); + } + mIconImageView.setLayoutParams(params); + lLContainer.addView(mIconImageView); + mTvTitle = new TextView(context); + mTvTitle.setText(title); + LinearLayout.LayoutParams paramsTv = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + paramsTv.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics()); + mTvTitle.setTextSize(12); + mTvTitle.setTextColor(ContextCompat.getColor(context, R.color.bottom_bar_un_selected)); + mTvTitle.setLayoutParams(paramsTv); + lLContainer.addView(mTvTitle); + + addView(lLContainer); + + int min = dip2px(context, 20); + int padding = dip2px(context, 5); + mTvUnreadCount = new TextView(context); + mTvUnreadCount.setBackgroundResource(R.drawable.bg_msg_bubble); + mTvUnreadCount.setMinWidth(min); + mTvUnreadCount.setTextColor(Color.WHITE); + mTvUnreadCount.setPadding(padding, 0, padding, 0); + mTvUnreadCount.setGravity(Gravity.CENTER); + FrameLayout.LayoutParams tvUnReadParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, min); + tvUnReadParams.gravity = Gravity.CENTER; + tvUnReadParams.leftMargin = dip2px(context, 17); + tvUnReadParams.bottomMargin = dip2px(context, 14); + mTvUnreadCount.setLayoutParams(tvUnReadParams); + mTvUnreadCount.setVisibility(GONE); + + addView(mTvUnreadCount); + } + + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + if (isColorFilterMode()) { + if (selected) { + mIconImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary)); + mTvTitle.setTextColor(ContextCompat.getColor(mContext, R.color.colorPrimary)); + } else { + mIconImageView.setColorFilter(ContextCompat.getColor(mContext, R.color.bottom_bar_un_selected)); + mTvTitle.setTextColor(ContextCompat.getColor(mContext, R.color.bottom_bar_un_selected)); + } + } else { + mIconImageView.clearColorFilter(); + if (selected) { + mIconImageView.setImageResource(mIcon); + mTvTitle.setTextColor(ContextCompat.getColor(mContext, R.color.bottom_bar_selected)); + } else { + mIconImageView.setImageResource(mIconUnSelected); + mTvTitle.setTextColor(ContextCompat.getColor(mContext, R.color.bottom_bar_un_selected)); + } + } + } + + public void setTabPosition(int position) { + mTabPosition = position; + if (position == 0) { + setSelected(true); + } + } + + public int getTabPosition() { + return mTabPosition; + } + + /** + * 设置未读数量 + */ + public void setUnreadCount(int num) { + if (num <= 0) { + mTvUnreadCount.setText(String.valueOf(0)); + mTvUnreadCount.setVisibility(GONE); + } else { + mTvUnreadCount.setVisibility(VISIBLE); + if (num > 99) { + mTvUnreadCount.setText("99+"); + } else { + mTvUnreadCount.setText(String.valueOf(num)); + } + } + } + + /** + * 获取当前未读数量 + */ + public int getUnreadCount() { + int count = 0; + if (TextUtils.isEmpty(mTvUnreadCount.getText())) { + return count; + } + if (mTvUnreadCount.getText().toString().equals("99+")) { + return 99; + } + try { + count = Integer.valueOf(mTvUnreadCount.getText().toString()); + } catch (Exception ignored) { + } + return count; + } + + private boolean isColorFilterMode() { + return mIconUnSelected == DEFAULT_ICON_UNSELECTED; + } + + private int dip2px(Context context, float dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); + } +} diff --git a/app/src/main/res/drawable-v24/.DS_Store b/app/src/main/res/drawable-v24/.DS_Store deleted file mode 100644 index 5008ddf..0000000 Binary files a/app/src/main/res/drawable-v24/.DS_Store and /dev/null differ diff --git a/app/src/main/res/drawable/bg_msg_bubble.xml b/app/src/main/res/drawable/bg_msg_bubble.xml new file mode 100755 index 0000000..6e81f7b --- /dev/null +++ b/app/src/main/res/drawable/bg_msg_bubble.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_btn_update.xml b/app/src/main/res/drawable/bg_shape_btn.xml similarity index 84% rename from app/src/main/res/drawable/shape_btn_update.xml rename to app/src/main/res/drawable/bg_shape_btn.xml index 832dab6..5ce9bea 100644 --- a/app/src/main/res/drawable/shape_btn_update.xml +++ b/app/src/main/res/drawable/bg_shape_btn.xml @@ -2,7 +2,7 @@ - + diff --git a/app/src/main/res/drawable/ic_home.xml b/app/src/main/res/drawable/ic_home.xml deleted file mode 100644 index 95b3870..0000000 --- a/app/src/main/res/drawable/ic_home.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_more.xml b/app/src/main/res/drawable/ic_more.xml deleted file mode 100644 index 4c37209..0000000 --- a/app/src/main/res/drawable/ic_more.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_receive.xml b/app/src/main/res/drawable/ic_receive.xml deleted file mode 100644 index 89fc1be..0000000 --- a/app/src/main/res/drawable/ic_receive.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_scan.xml b/app/src/main/res/drawable/ic_scan.xml deleted file mode 100644 index 3dfddd8..0000000 --- a/app/src/main/res/drawable/ic_scan.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_send.xml b/app/src/main/res/drawable/ic_send.xml deleted file mode 100644 index f82332d..0000000 --- a/app/src/main/res/drawable/ic_send.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 58887da..035f8e5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,22 +1,23 @@ - - + - - - - + + + + + android:layout_height="58dp"/> diff --git a/app/src/main/res/layout/activity_poollist.xml b/app/src/main/res/layout/activity_poollist.xml index 028d800..f8e3d5e 100644 --- a/app/src/main/res/layout/activity_poollist.xml +++ b/app/src/main/res/layout/activity_poollist.xml @@ -19,7 +19,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_add" - android:layout_margin="@dimen/space_32" + android:layout_marginRight="@dimen/space_16" + android:layout_marginBottom="@dimen/space_32" android:layout_gravity="bottom|end"/> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_restore.xml b/app/src/main/res/layout/activity_restore.xml index cdf940e..b546500 100644 --- a/app/src/main/res/layout/activity_restore.xml +++ b/app/src/main/res/layout/activity_restore.xml @@ -12,13 +12,13 @@