- * Note: Will be immediately called for the currently selected tab - * once when set. - * - * @param listener a listener for monitoring changes in tab selection. - */ - public void setOnTabSelectListener(@NonNull OnTabSelectListener listener) { - setOnTabSelectListener(listener, true); - } - - /** - * Set a listener that gets fired when the selected {@link BottomBarTab} changes. - *
- * If {@code shouldFireInitially} is set to false, this listener isn't fired straight away
- * it's set, but you'll get all events normally for consecutive tab selection changes.
- *
- * @param listener a listener for monitoring changes in tab selection.
- * @param shouldFireInitially whether the listener should be fired the first time it's set.
- */
- public void setOnTabSelectListener(@NonNull OnTabSelectListener listener, boolean shouldFireInitially) {
- onTabSelectListener = listener;
-
- if (shouldFireInitially && getTabCount() > 0) {
- listener.onTabSelected(getCurrentTabId());
- }
- }
-
- /**
- * Removes the current {@link OnTabSelectListener} listener
- */
- public void removeOnTabSelectListener() {
- onTabSelectListener = null;
- }
-
- /**
- * Set a listener that gets fired when a currently selected {@link BottomBarTab} is clicked.
- *
- * @param listener a listener for handling tab reselections.
- */
- public void setOnTabReselectListener(@NonNull OnTabReselectListener listener) {
- onTabReselectListener = listener;
- }
-
- /**
- * Removes the current {@link OnTabReselectListener} listener
- */
- public void removeOnTabReselectListener() {
- onTabReselectListener = null;
- }
-
- /**
- * Set the default selected to be the tab with the corresponding tab id.
- * By default, the first tab in the container is the default tab.
- */
- public void setDefaultTab(@IdRes int defaultTabId) {
- int defaultTabPosition = findPositionForTabWithId(defaultTabId);
- setDefaultTabPosition(defaultTabPosition);
- }
-
- /**
- * Sets the default tab for this BottomBar that is shown until the user changes
- * the selection.
- *
- * @param defaultTabPosition the default tab position.
- */
- public void setDefaultTabPosition(int defaultTabPosition) {
- if (isComingFromRestoredState) return;
-
- selectTabAtPosition(defaultTabPosition);
- }
-
- /**
- * Select the tab with the corresponding id.
- */
- public void selectTabWithId(@IdRes int tabResId) {
- int tabPosition = findPositionForTabWithId(tabResId);
- selectTabAtPosition(tabPosition);
- }
-
- /**
- * Select a tab at the specified position.
- *
- * @param position the position to select.
- */
- public void selectTabAtPosition(int position) {
- selectTabAtPosition(position, false);
- }
-
- /**
- * Select a tab at the specified position.
- *
- * @param position the position to select.
- * @param animate should the tab change be animated or not.
- */
- public void selectTabAtPosition(int position, boolean animate) {
- if (position > getTabCount() - 1 || position < 0) {
- throw new IndexOutOfBoundsException("Can't select tab at position " +
- position + ". This BottomBar has no items at that position.");
- }
-
- BottomBarTab oldTab = getCurrentTab();
- BottomBarTab newTab = getTabAtPosition(position);
-
- oldTab.deselect(animate);
- newTab.select(animate);
-
- updateSelectedTab(position);
- shiftingMagic(oldTab, newTab, animate);
- handleBackgroundColorChange(newTab, animate);
- }
-
- public int getTabCount() {
- return tabContainer.getChildCount();
- }
-
- /**
- * Get the currently selected tab.
- */
- public BottomBarTab getCurrentTab() {
- return getTabAtPosition(getCurrentTabPosition());
- }
-
- /**
- * Get the tab at the specified position.
- */
- public BottomBarTab getTabAtPosition(int position) {
- View child = tabContainer.getChildAt(position);
-
- if (child instanceof BadgeContainer) {
- return findTabInLayout((BadgeContainer) child);
- }
-
- return (BottomBarTab) child;
- }
-
- /**
- * Get the resource id for the currently selected tab.
- */
- @IdRes
- public int getCurrentTabId() {
- return getCurrentTab().getId();
- }
-
- /**
- * Get the currently selected tab position.
- */
- public int getCurrentTabPosition() {
- return currentTabPosition;
- }
-
- /**
- * Find the tabs' position in the container by id.
- */
- public int findPositionForTabWithId(@IdRes int tabId) {
- return getTabWithId(tabId).getIndexInTabContainer();
- }
-
- /**
- * Find a BottomBarTab with the corresponding id.
- */
- public BottomBarTab getTabWithId(@IdRes int tabId) {
- return (BottomBarTab) tabContainer.findViewById(tabId);
- }
-
- /**
- * Controls whether the long pressed tab title should be displayed in
- * a helpful Toast if the title is not currently visible.
- *
- * @param enabled true if toasts should be shown to indicate the title
- * of a long pressed tab, false otherwise.
- */
- public void setLongPressHintsEnabled(boolean enabled) {
- longPressHintsEnabled = enabled;
- }
-
- /**
- * Set alpha value used for inactive BottomBarTabs.
- */
- public void setInActiveTabAlpha(float alpha) {
- inActiveTabAlpha = alpha;
-
- batchPropertyApplier.applyToAllTabs(new BatchTabPropertyApplier.TabPropertyUpdater() {
- @Override
- public void update(BottomBarTab tab) {
- tab.setInActiveAlpha(inActiveTabAlpha);
- }
- });
- }
-
- /**
- * Set alpha value used for active BottomBarTabs.
- */
- public void setActiveTabAlpha(float alpha) {
- activeTabAlpha = alpha;
-
- batchPropertyApplier.applyToAllTabs(new BatchTabPropertyApplier.TabPropertyUpdater() {
- @Override
- public void update(BottomBarTab tab) {
- tab.setActiveAlpha(activeTabAlpha);
- }
- });
- }
-
- public void setInActiveTabColor(@ColorInt int color) {
- inActiveTabColor = color;
-
- batchPropertyApplier.applyToAllTabs(new BatchTabPropertyApplier.TabPropertyUpdater() {
- @Override
- public void update(BottomBarTab tab) {
- tab.setInActiveColor(inActiveTabColor);
- }
- });
- }
-
- /**
- * Set active color used for selected BottomBarTabs.
- */
- public void setActiveTabColor(@ColorInt int color) {
- activeTabColor = color;
-
- batchPropertyApplier.applyToAllTabs(new BatchTabPropertyApplier.TabPropertyUpdater() {
- @Override
- public void update(BottomBarTab tab) {
- tab.setActiveColor(activeTabColor);
- }
- });
- }
-
- /**
- * Set background color for the badge.
- */
- public void setBadgeBackgroundColor(@ColorInt int color) {
- badgeBackgroundColor = color;
-
- batchPropertyApplier.applyToAllTabs(new BatchTabPropertyApplier.TabPropertyUpdater() {
- @Override
- public void update(BottomBarTab tab) {
- tab.setBadgeBackgroundColor(badgeBackgroundColor);
- }
- });
- }
-
- /**
- * Controls whether the badge (if any) for active tabs
- * should be hidden or not.
- */
- public void setBadgesHideWhenActive(final boolean hideWhenSelected) {
- hideBadgeWhenActive = hideWhenSelected;
- batchPropertyApplier.applyToAllTabs(new BatchTabPropertyApplier.TabPropertyUpdater() {
- @Override
- public void update(BottomBarTab tab) {
- tab.setBadgeHidesWhenActive(hideWhenSelected);
- }
- });
- }
-
- /**
- * Set custom text apperance for all BottomBarTabs.
- */
- public void setTabTitleTextAppearance(int textAppearance) {
- titleTextAppearance = textAppearance;
-
- batchPropertyApplier.applyToAllTabs(new BatchTabPropertyApplier.TabPropertyUpdater() {
- @Override
- public void update(BottomBarTab tab) {
- tab.setTitleTextAppearance(titleTextAppearance);
- }
- });
- }
-
- /**
- * Set a custom typeface for all tab's titles.
- *
- * @param fontPath path for your custom font file, such as fonts/MySuperDuperFont.ttf.
- * In that case your font path would look like src/main/assets/fonts/MySuperDuperFont.ttf,
- * but you only need to provide fonts/MySuperDuperFont.ttf, as the asset folder
- * will be auto-filled for you.
- */
- public void setTabTitleTypeface(String fontPath) {
- Typeface actualTypeface = getTypeFaceFromAsset(fontPath);
- setTabTitleTypeface(actualTypeface);
- }
-
- /**
- * Set a custom typeface for all tab's titles.
- */
- public void setTabTitleTypeface(Typeface typeface) {
- titleTypeFace = typeface;
-
- batchPropertyApplier.applyToAllTabs(new BatchTabPropertyApplier.TabPropertyUpdater() {
- @Override
- public void update(BottomBarTab tab) {
- tab.setTitleTypeface(titleTypeFace);
- }
- });
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- if (changed) {
- if (!isTabletMode) {
- resizeTabsToCorrectSizes(currentTabs);
- }
-
- updateTitleBottomPadding();
-
- if (isShy()) {
- initializeShyBehavior();
- }
-
- if (drawUnderNav()) {
- resizeForDrawingUnderNavbar();
- }
- }
- }
-
- private void updateTitleBottomPadding() {
- if (isIconsOnlyMode()) {
- return;
- }
-
- int tabCount = getTabCount();
-
- if (tabContainer == null || tabCount == 0 || !isShiftingMode()) {
- return;
- }
-
- for (int i = 0; i < tabCount; i++) {
- BottomBarTab tab = getTabAtPosition(i);
- TextView title = tab.getTitleView();
-
- if (title == null) {
- continue;
- }
-
- int baseline = title.getBaseline();
- int height = title.getHeight();
- int paddingInsideTitle = height - baseline;
- int missingPadding = tenDp - paddingInsideTitle;
-
- if (missingPadding > 0) {
- title.setPadding(title.getPaddingLeft(), title.getPaddingTop(),
- title.getPaddingRight(), missingPadding + title.getPaddingBottom());
- }
- }
- }
-
- private void initializeShyBehavior() {
- ViewParent parent = getParent();
-
- boolean hasAbusiveParent = parent != null
- && parent instanceof CoordinatorLayout;
-
- if (!hasAbusiveParent) {
- throw new RuntimeException("In order to have shy behavior, the " +
- "BottomBar must be a direct child of a CoordinatorLayout.");
- }
-
- if (!shyHeightAlreadyCalculated) {
- int height = getHeight();
-
- if (height != 0) {
- updateShyHeight(height);
- getShySettings().shyHeightCalculated();
- shyHeightAlreadyCalculated = true;
- }
- }
- }
-
- private void updateShyHeight(int height) {
- ((CoordinatorLayout.LayoutParams) getLayoutParams())
- .setBehavior(new BottomNavigationBehavior(height, 0, false));
- }
-
- private void resizeForDrawingUnderNavbar() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- int currentHeight = getHeight();
-
- if (currentHeight != 0 && !navBarAccountedHeightCalculated) {
- navBarAccountedHeightCalculated = true;
- tabContainer.getLayoutParams().height = currentHeight;
-
- int navbarHeight = NavbarUtils.INSTANCE.getNavbarHeight(getContext());
- int finalHeight = currentHeight + navbarHeight;
- getLayoutParams().height = finalHeight;
-
- if (isShy()) {
- updateShyHeight(finalHeight);
- }
- }
- }
- }
-
- @Override
- public Parcelable onSaveInstanceState() {
- Bundle bundle = saveState();
- bundle.putParcelable("superstate", super.onSaveInstanceState());
- return bundle;
- }
-
- @VisibleForTesting
- Bundle saveState() {
- Bundle outState = new Bundle();
- outState.putInt(STATE_CURRENT_SELECTED_TAB, currentTabPosition);
-
- return outState;
- }
-
- @Override
- public void onRestoreInstanceState(Parcelable state) {
- if (state instanceof Bundle) {
- Bundle bundle = (Bundle) state;
- restoreState(bundle);
-
- state = bundle.getParcelable("superstate");
- }
- super.onRestoreInstanceState(state);
- }
-
- @VisibleForTesting
- void restoreState(Bundle savedInstanceState) {
- if (savedInstanceState != null) {
- isComingFromRestoredState = true;
- ignoreTabReselectionListener = true;
-
- int restoredPosition = savedInstanceState.getInt(STATE_CURRENT_SELECTED_TAB, currentTabPosition);
- selectTabAtPosition(restoredPosition, false);
- }
- }
-
- @Override
- public void onClick(View target) {
- if (!(target instanceof BottomBarTab)) return;
- handleClick((BottomBarTab) target);
- }
-
- @Override
- public boolean onLongClick(View target) {
- return !(target instanceof BottomBarTab) || handleLongClick((BottomBarTab) target);
- }
-
- private BottomBarTab findTabInLayout(ViewGroup child) {
- for (int i = 0; i < child.getChildCount(); i++) {
- View candidate = child.getChildAt(i);
-
- if (candidate instanceof BottomBarTab) {
- return (BottomBarTab) candidate;
- }
- }
-
- return null;
- }
-
- private void handleClick(BottomBarTab newTab) {
- BottomBarTab oldTab = getCurrentTab();
-
- if (tabSelectionInterceptor != null
- && tabSelectionInterceptor.shouldInterceptTabSelection(oldTab.getId(), newTab.getId())) {
- return;
- }
-
- oldTab.deselect(true);
- newTab.select(true);
-
- shiftingMagic(oldTab, newTab, true);
- handleBackgroundColorChange(newTab, true);
- updateSelectedTab(newTab.getIndexInTabContainer());
- }
-
- private boolean handleLongClick(BottomBarTab longClickedTab) {
- boolean areInactiveTitlesHidden = isShiftingMode() || isTabletMode;
- boolean isClickedTitleHidden = !longClickedTab.isActive();
- boolean shouldShowHint = areInactiveTitlesHidden
- && isClickedTitleHidden
- && longPressHintsEnabled;
-
- if (shouldShowHint) {
- Toast.makeText(getContext(), longClickedTab.getTitle(), Toast.LENGTH_SHORT)
- .show();
- }
-
- return true;
- }
-
- private void updateSelectedTab(int newPosition) {
- int newTabId = getTabAtPosition(newPosition).getId();
-
- if (newPosition != currentTabPosition) {
- if (onTabSelectListener != null) {
- onTabSelectListener.onTabSelected(newTabId);
- }
- } else if (onTabReselectListener != null && !ignoreTabReselectionListener) {
- onTabReselectListener.onTabReSelected(newTabId);
- }
-
- currentTabPosition = newPosition;
-
- if (ignoreTabReselectionListener) {
- ignoreTabReselectionListener = false;
- }
- }
-
- private void shiftingMagic(BottomBarTab oldTab, BottomBarTab newTab, boolean animate) {
- if (isShiftingMode()) {
- oldTab.updateWidth(inActiveShiftingItemWidth, animate);
- newTab.updateWidth(activeShiftingItemWidth, animate);
- }
- }
-
- private void handleBackgroundColorChange(BottomBarTab tab, boolean animate) {
- int newColor = tab.getBarColorWhenSelected();
-
- if (currentBackgroundColor == newColor) {
- return;
- }
-
- if (!animate) {
- outerContainer.setBackgroundColor(newColor);
- return;
- }
-
- View clickedView = tab;
-
- if (tab.hasActiveBadge()) {
- clickedView = tab.getOuterView();
- }
-
- animateBGColorChange(clickedView, newColor);
- currentBackgroundColor = newColor;
- }
-
- private void animateBGColorChange(View clickedView, final int newColor) {
- prepareForBackgroundColorAnimation(newColor);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- if (!outerContainer.isAttachedToWindow()) {
- return;
- }
-
- backgroundCircularRevealAnimation(clickedView, newColor);
- } else {
- backgroundCrossfadeAnimation(newColor);
- }
- }
-
- private void prepareForBackgroundColorAnimation(int newColor) {
- outerContainer.clearAnimation();
- backgroundOverlay.clearAnimation();
-
- backgroundOverlay.setBackgroundColor(newColor);
- backgroundOverlay.setVisibility(View.VISIBLE);
- }
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- private void backgroundCircularRevealAnimation(View clickedView, final int newColor) {
- int centerX = (int) (ViewCompat.getX(clickedView) + (clickedView.getMeasuredWidth() / 2));
- int yOffset = isTabletMode ? (int) ViewCompat.getY(clickedView) : 0;
- int centerY = yOffset + clickedView.getMeasuredHeight() / 2;
- int startRadius = 0;
- int finalRadius = isTabletMode ? outerContainer.getHeight() : outerContainer.getWidth();
-
- Animator animator = ViewAnimationUtils.createCircularReveal(
- backgroundOverlay,
- centerX,
- centerY,
- startRadius,
- finalRadius
- );
-
- if (isTabletMode) {
- animator.setDuration(500);
- }
-
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- onEnd();
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- onEnd();
- }
-
- private void onEnd() {
- outerContainer.setBackgroundColor(newColor);
- backgroundOverlay.setVisibility(View.INVISIBLE);
- ViewCompat.setAlpha(backgroundOverlay, 1);
- }
- });
-
- animator.start();
- }
-
- private void backgroundCrossfadeAnimation(final int newColor) {
- ViewCompat.setAlpha(backgroundOverlay, 0);
- ViewCompat.animate(backgroundOverlay)
- .alpha(1)
- .setListener(new ViewPropertyAnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(View view) {
- onEnd();
- }
-
- @Override
- public void onAnimationCancel(View view) {
- onEnd();
- }
-
- private void onEnd() {
- outerContainer.setBackgroundColor(newColor);
- backgroundOverlay.setVisibility(View.INVISIBLE);
- ViewCompat.setAlpha(backgroundOverlay, 1);
- }
- })
- .start();
- }
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/BottomBarBadge.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/BottomBarBadge.java
deleted file mode 100644
index d7aa57294..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/BottomBarBadge.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.habitrpg.android.habitica.ui.views.bottombar;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.os.Build;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.TextView;
-
-import com.habitrpg.android.habitica.R;
-
-import androidx.appcompat.widget.AppCompatImageView;
-import androidx.appcompat.widget.AppCompatTextView;
-import androidx.core.view.ViewCompat;
-
-/*
- * BottomBar library for Android
- * Copyright (c) 2016 Iiro Krankka (http://github.com/roughike).
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-class BottomBarBadge extends AppCompatTextView {
- private int count;
- private boolean isVisible = false;
-
- BottomBarBadge(Context context) {
- super(context);
- }
-
- /**
- * Set the unread / new item / whatever count for this Badge.
- *
- * @param count the value this Badge should show.
- */
- void setCount(int count) {
- this.count = count;
- setText(String.valueOf(count));
- }
-
- /**
- * Get the currently showing count for this Badge.
- *
- * @return current count for the Badge.
- */
- int getCount() {
- return count;
- }
-
- /**
- * Shows the badge with a neat little scale animation.
- */
- void show() {
- isVisible = true;
- ViewCompat.animate(this)
- .setDuration(150)
- .alpha(1)
- .scaleX(1)
- .scaleY(1)
- .start();
- }
-
- /**
- * Hides the badge with a neat little scale animation.
- */
- void hide() {
- isVisible = false;
- ViewCompat.animate(this)
- .setDuration(150)
- .alpha(0)
- .scaleX(0)
- .scaleY(0)
- .start();
- }
-
- /**
- * Is this badge currently visible?
- *
- * @return true is this badge is visible, otherwise false.
- */
- boolean isVisible() {
- return isVisible;
- }
-
- void attachToTab(BottomBarTab tab, int backgroundColor) {
- ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-
- setLayoutParams(params);
- setGravity(Gravity.CENTER);
- MiscUtils.setTextAppearance(this, R.style.BB_BottomBarBadge_Text);
-
- setColoredCircleBackground(backgroundColor);
- wrapTabAndBadgeInSameContainer(tab);
- }
-
- void setColoredCircleBackground(int circleColor) {
- int innerPadding = MiscUtils.dpToPixel(getContext(), 1);
- ShapeDrawable backgroundCircle = BadgeCircle.make(innerPadding * 3, circleColor);
- setPadding(innerPadding, innerPadding, innerPadding, innerPadding);
- setBackgroundCompat(backgroundCircle);
- }
-
- private void wrapTabAndBadgeInSameContainer(final BottomBarTab tab) {
- ViewGroup tabContainer = (ViewGroup) tab.getParent();
- tabContainer.removeView(tab);
-
- final BadgeContainer badgeContainer = new BadgeContainer(getContext());
- badgeContainer.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
-
- badgeContainer.addView(tab);
- badgeContainer.addView(this);
-
- tabContainer.addView(badgeContainer, tab.getIndexInTabContainer());
-
- badgeContainer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- @SuppressWarnings("deprecation")
- @Override
- public void onGlobalLayout() {
- badgeContainer.getViewTreeObserver().removeGlobalOnLayoutListener(this);
- adjustPositionAndSize(tab);
- }
- });
- }
-
- void removeFromTab(BottomBarTab tab) {
- BadgeContainer badgeAndTabContainer = (BadgeContainer) getParent();
- ViewGroup originalTabContainer = (ViewGroup) badgeAndTabContainer.getParent();
-
- badgeAndTabContainer.removeView(tab);
- originalTabContainer.removeView(badgeAndTabContainer);
- originalTabContainer.addView(tab, tab.getIndexInTabContainer());
- }
-
- void adjustPositionAndSize(BottomBarTab tab) {
- AppCompatImageView iconView = tab.getIconView();
- ViewGroup.LayoutParams params = getLayoutParams();
-
- int size = Math.max(getWidth(), getHeight());
- float xOffset = (float) (iconView.getWidth() / 1.25);
-
- setX(iconView.getX() + xOffset);
- setTranslationY(10);
-
- if (params.width != size || params.height != size) {
- params.width = size;
- params.height = size;
- setLayoutParams(params);
- }
- }
-
- @SuppressWarnings("deprecation")
- private void setBackgroundCompat(Drawable background) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- setBackground(background);
- } else {
- setBackgroundDrawable(background);
- }
- }
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/BottomBarTab.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/BottomBarTab.java
deleted file mode 100644
index 88e9d8eaa..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/BottomBarTab.java
+++ /dev/null
@@ -1,730 +0,0 @@
-package com.habitrpg.android.habitica.ui.views.bottombar;
-
-import android.animation.ArgbEvaluator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Typeface;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcelable;
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.appcompat.widget.AppCompatImageView;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.ViewPropertyAnimatorCompat;
-
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.habitrpg.android.habitica.R;
-
-/*
- * BottomBar library for Android
- * Copyright (c) 2016 Iiro Krankka (http://github.com/roughike).
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-public class BottomBarTab extends LinearLayout {
- @VisibleForTesting
- static final String STATE_BADGE_COUNT = "STATE_BADGE_COUNT_FOR_TAB_";
-
- private static final long ANIMATION_DURATION = 150;
- private static final float ACTIVE_TITLE_SCALE = 1;
- private static final float INACTIVE_FIXED_TITLE_SCALE = 0.86f;
- private static final float ACTIVE_SHIFTING_TITLELESS_ICON_SCALE = 1.24f;
- private static final float INACTIVE_SHIFTING_TITLELESS_ICON_SCALE = 1f;
-
- private final int sixDps;
- private final int eightDps;
- private final int sixteenDps;
-
- @VisibleForTesting
- BottomBarBadge badge;
-
- private Type type = Type.FIXED;
- private boolean isTitleless;
- private int iconResId;
- private String title;
- private float inActiveAlpha;
- private float activeAlpha;
- private int inActiveColor;
- private int activeColor;
- private int barColorWhenSelected;
- private int badgeBackgroundColor;
- private boolean badgeHidesWhenActive;
- private AppCompatImageView iconView;
- private TextView titleView;
- private boolean isActive;
- private int indexInContainer;
- private int titleTextAppearanceResId;
- private Typeface titleTypeFace;
-
- BottomBarTab(Context context) {
- super(context);
-
- sixDps = MiscUtils.dpToPixel(context, 6);
- eightDps = MiscUtils.dpToPixel(context, 8);
- sixteenDps = MiscUtils.dpToPixel(context, 16);
- }
-
- void setConfig(@NonNull Config config) {
- setInActiveAlpha(config.inActiveTabAlpha);
- setActiveAlpha(config.activeTabAlpha);
- setInActiveColor(config.inActiveTabColor);
- setActiveColor(config.activeTabColor);
- setBarColorWhenSelected(config.barColorWhenSelected);
- setBadgeBackgroundColor(config.badgeBackgroundColor);
- setBadgeHidesWhenActive(config.badgeHidesWhenSelected);
- setTitleTextAppearance(config.titleTextAppearance);
- setTitleTypeface(config.titleTypeFace);
- }
-
- void prepareLayout() {
- inflate(getContext(), getLayoutResource(), this);
- setOrientation(VERTICAL);
- setGravity(isTitleless? Gravity.CENTER : Gravity.CENTER_HORIZONTAL);
- setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- setBackgroundResource(MiscUtils.getDrawableRes(getContext(), R.attr.selectableItemBackgroundBorderless));
-
- iconView = findViewById(R.id.bb_bottom_bar_icon);
- iconView.setImageResource(iconResId);
-
- if (type != Type.TABLET && !isTitleless) {
- titleView = findViewById(R.id.bb_bottom_bar_title);
- titleView.setVisibility(VISIBLE);
-
- if (type == Type.SHIFTING) {
- findViewById(R.id.spacer).setVisibility(VISIBLE);
- }
-
- updateTitle();
- }
-
- updateCustomTextAppearance();
- updateCustomTypeface();
- }
-
- @VisibleForTesting
- int getLayoutResource() {
- int layoutResource;
- switch (type) {
- case FIXED:
- layoutResource = R.layout.bb_bottom_bar_item_fixed;
- break;
- case SHIFTING:
- layoutResource = R.layout.bb_bottom_bar_item_shifting;
- break;
- case TABLET:
- layoutResource = R.layout.bb_bottom_bar_item_fixed_tablet;
- break;
- default:
- // should never happen
- throw new RuntimeException("Unknown BottomBarTab type.");
- }
- return layoutResource;
- }
-
- private void updateTitle() {
- if (titleView != null) {
- titleView.setText(title);
- }
- }
-
- @SuppressWarnings("deprecation")
- private void updateCustomTextAppearance() {
- if (titleView == null || titleTextAppearanceResId == 0) {
- return;
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- titleView.setTextAppearance(titleTextAppearanceResId);
- } else {
- titleView.setTextAppearance(getContext(), titleTextAppearanceResId);
- }
-
- titleView.setTag(R.id.bb_bottom_bar_appearance_id, titleTextAppearanceResId);
- }
-
- private void updateCustomTypeface() {
- if (titleTypeFace != null && titleView != null) {
- titleView.setTypeface(titleTypeFace);
- }
- }
-
- Type getType() {
- return type;
- }
-
- void setType(Type type) {
- this.type = type;
- }
-
- boolean isTitleless() {
- return isTitleless;
- }
-
- void setIsTitleless(boolean isTitleless) {
- if (isTitleless && getIconResId() == 0) {
- throw new IllegalStateException("This tab is supposed to be " +
- "icon only, yet it has no icon specified. Index in " +
- "container: " + getIndexInTabContainer());
- }
-
- this.isTitleless = isTitleless;
- }
-
- public ViewGroup getOuterView() {
- return (ViewGroup) getParent();
- }
-
- AppCompatImageView getIconView() {
- return iconView;
- }
-
- int getIconResId() {
- return iconResId;
- }
-
- void setIconResId(int iconResId) {
- this.iconResId = iconResId;
- }
-
- TextView getTitleView() {
- return titleView;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- updateTitle();
- }
-
- public float getInActiveAlpha() {
- return inActiveAlpha;
- }
-
- public void setInActiveAlpha(float inActiveAlpha) {
- this.inActiveAlpha = inActiveAlpha;
-
- if (!isActive) {
- setAlphas(inActiveAlpha);
- }
- }
-
- public float getActiveAlpha() {
- return activeAlpha;
- }
-
- public void setActiveAlpha(float activeAlpha) {
- this.activeAlpha = activeAlpha;
-
- if (isActive) {
- setAlphas(activeAlpha);
- }
- }
-
- public int getInActiveColor() {
- return inActiveColor;
- }
-
- public void setInActiveColor(int inActiveColor) {
- this.inActiveColor = inActiveColor;
-
- if (!isActive) {
- setColors(inActiveColor);
- }
- }
-
- public int getActiveColor() {
- return activeColor;
- }
-
- public void setActiveColor(int activeIconColor) {
- this.activeColor = activeIconColor;
-
- if (isActive) {
- setColors(activeColor);
- }
- }
-
- public int getBarColorWhenSelected() {
- return barColorWhenSelected;
- }
-
- public void setBarColorWhenSelected(int barColorWhenSelected) {
- this.barColorWhenSelected = barColorWhenSelected;
- }
-
- public int getBadgeBackgroundColor() {
- return badgeBackgroundColor;
- }
-
- public void setBadgeBackgroundColor(int badgeBackgroundColor) {
- this.badgeBackgroundColor = badgeBackgroundColor;
-
- if (badge != null) {
- badge.setColoredCircleBackground(badgeBackgroundColor);
- }
- }
-
- public boolean getBadgeHidesWhenActive() {
- return badgeHidesWhenActive;
- }
-
- public void setBadgeHidesWhenActive(boolean hideWhenActive) {
- this.badgeHidesWhenActive = hideWhenActive;
- }
-
- int getCurrentDisplayedIconColor() {
- Object tag = iconView.getTag(R.id.bb_bottom_bar_color_id);
-
- if (tag instanceof Integer) {
- return (int) tag;
- }
-
- return 0;
- }
-
- int getCurrentDisplayedTitleColor() {
- if (titleView != null) {
- return titleView.getCurrentTextColor();
- }
-
- return 0;
- }
-
- int getCurrentDisplayedTextAppearance() {
- Object tag = titleView.getTag(R.id.bb_bottom_bar_appearance_id);
-
- if (titleView != null && tag instanceof Integer) {
- return (int) tag;
- }
-
- return 0;
- }
-
- public void setBadgeCount(int count) {
- if (count <= 0) {
- if (badge != null) {
- badge.removeFromTab(this);
- badge = null;
- }
-
- return;
- }
-
- if (badge == null) {
- badge = new BottomBarBadge(getContext());
- badge.attachToTab(this, badgeBackgroundColor);
- }
-
- badge.setCount(count);
-
- if (isActive && badgeHidesWhenActive) {
- badge.hide();
- }
- }
-
- public void removeBadge() {
- setBadgeCount(0);
- }
-
- boolean isActive() {
- return isActive;
- }
-
- boolean hasActiveBadge() {
- return badge != null;
- }
-
- int getIndexInTabContainer() {
- return indexInContainer;
- }
-
- void setIndexInContainer(int indexInContainer) {
- this.indexInContainer = indexInContainer;
- }
-
- void setIconTint(int tint) {
- iconView.setColorFilter(tint);
- }
-
- public int getTitleTextAppearance() {
- return titleTextAppearanceResId;
- }
-
- @SuppressWarnings("deprecation")
- void setTitleTextAppearance(int resId) {
- this.titleTextAppearanceResId = resId;
- updateCustomTextAppearance();
- }
-
- public void setTitleTypeface(Typeface typeface) {
- this.titleTypeFace = typeface;
- updateCustomTypeface();
- }
-
- public Typeface getTitleTypeFace() {
- return titleTypeFace;
- }
-
- void select(boolean animate) {
- isActive = true;
-
- if (animate) {
- animateIcon(activeAlpha, ACTIVE_SHIFTING_TITLELESS_ICON_SCALE);
- animateTitle(sixDps, ACTIVE_TITLE_SCALE, activeAlpha);
- animateColors(inActiveColor, activeColor);
- } else {
- setTitleScale(ACTIVE_TITLE_SCALE);
- setTopPadding(sixDps);
- setIconScale(ACTIVE_SHIFTING_TITLELESS_ICON_SCALE);
- setColors(activeColor);
- setAlphas(activeAlpha);
- }
-
- setSelected(true);
-
- if (badge != null && badgeHidesWhenActive) {
- badge.hide();
- }
- }
-
- void deselect(boolean animate) {
- isActive = false;
-
- boolean isShifting = type == Type.SHIFTING;
-
- float titleScale = isShifting ? 0 : INACTIVE_FIXED_TITLE_SCALE;
- int iconPaddingTop = isShifting ? sixteenDps : eightDps;
-
- if (animate) {
- animateTitle(iconPaddingTop, titleScale, inActiveAlpha);
- animateIcon(inActiveAlpha, INACTIVE_SHIFTING_TITLELESS_ICON_SCALE);
- animateColors(activeColor, inActiveColor);
- } else {
- setTitleScale(titleScale);
- setTopPadding(iconPaddingTop);
- setIconScale(INACTIVE_SHIFTING_TITLELESS_ICON_SCALE);
- setColors(inActiveColor);
- setAlphas(inActiveAlpha);
- }
-
- setSelected(false);
-
- if (!isShifting && badge != null && !badge.isVisible()) {
- badge.show();
- }
- }
-
- private void animateColors(int previousColor, int color) {
- ValueAnimator anim = new ValueAnimator();
- anim.setIntValues(previousColor, color);
- anim.setEvaluator(new ArgbEvaluator());
- anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- setColors((Integer) valueAnimator.getAnimatedValue());
- }
- });
-
- anim.setDuration(150);
- anim.start();
- }
-
- private void setColors(int color) {
- if (iconView != null) {
- iconView.setColorFilter(color);
- iconView.setTag(R.id.bb_bottom_bar_color_id, color);
- }
-
- if (titleView != null) {
- titleView.setTextColor(color);
- }
- }
-
- private void setAlphas(float alpha) {
- if (iconView != null) {
- ViewCompat.setAlpha(iconView, alpha);
- }
-
- if (titleView != null) {
- ViewCompat.setAlpha(titleView, alpha);
- }
- }
-
- void updateWidth(float endWidth, boolean animated) {
- if (!animated) {
- getLayoutParams().width = (int) endWidth;
-
- if (!isActive && badge != null) {
- badge.adjustPositionAndSize(this);
- badge.show();
- }
- return;
- }
-
- float start = getWidth();
-
- ValueAnimator animator = ValueAnimator.ofFloat(start, endWidth);
- animator.setDuration(150);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animator) {
- ViewGroup.LayoutParams params = getLayoutParams();
- if (params == null) return;
-
- params.width = Math.round((float) animator.getAnimatedValue());
- setLayoutParams(params);
- }
- });
-
- // Workaround to avoid using faulty onAnimationEnd() listener
- postDelayed(new Runnable() {
- @Override
- public void run() {
- if (!isActive && badge != null) {
- clearAnimation();
- badge.adjustPositionAndSize(BottomBarTab.this);
- badge.show();
- }
- }
- }, animator.getDuration());
-
- animator.start();
- }
-
- private void updateBadgePosition() {
- if (badge != null) {
- badge.adjustPositionAndSize(this);
- }
- }
-
- private void setTopPaddingAnimated(int start, int end) {
- if (type == Type.TABLET || isTitleless) {
- return;
- }
-
- ValueAnimator paddingAnimator = ValueAnimator.ofInt(start, end);
- paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- iconView.setPadding(
- iconView.getPaddingLeft(),
- (Integer) animation.getAnimatedValue(),
- iconView.getPaddingRight(),
- iconView.getPaddingBottom()
- );
- }
- });
-
- paddingAnimator.setDuration(ANIMATION_DURATION);
- paddingAnimator.start();
- }
-
- private void animateTitle(int padding, float scale, float alpha) {
- if (type == Type.TABLET && isTitleless) {
- return;
- }
-
- setTopPaddingAnimated(iconView.getPaddingTop(), padding);
-
- ViewPropertyAnimatorCompat titleAnimator = ViewCompat.animate(titleView)
- .setDuration(ANIMATION_DURATION)
- .scaleX(scale)
- .scaleY(scale);
- titleAnimator.alpha(alpha);
- titleAnimator.start();
- }
-
- private void animateIconScale(float scale) {
- ViewCompat.animate(iconView)
- .setDuration(ANIMATION_DURATION)
- .scaleX(scale)
- .scaleY(scale)
- .start();
- }
-
- private void animateIcon(float alpha, float scale) {
- ViewCompat.animate(iconView)
- .setDuration(ANIMATION_DURATION)
- .alpha(alpha)
- .start();
-
- if (isTitleless && type == Type.SHIFTING) {
- animateIconScale(scale);
- }
- }
-
- private void setTopPadding(int topPadding) {
- if (type == Type.TABLET || isTitleless) {
- return;
- }
-
- iconView.setPadding(
- iconView.getPaddingLeft(),
- topPadding,
- iconView.getPaddingRight(),
- iconView.getPaddingBottom()
- );
- }
-
- private void setTitleScale(float scale) {
- if (type == Type.TABLET || isTitleless) {
- return;
- }
-
- ViewCompat.setScaleX(titleView, scale);
- ViewCompat.setScaleY(titleView, scale);
- }
-
- private void setIconScale(float scale) {
- if (isTitleless && type == Type.SHIFTING) {
- ViewCompat.setScaleX(iconView, scale);
- ViewCompat.setScaleY(iconView, scale);
- }
- }
-
- @Override
- public Parcelable onSaveInstanceState() {
- if (badge != null) {
- Bundle bundle = saveState();
- bundle.putParcelable("superstate", super.onSaveInstanceState());
-
- return bundle;
- }
-
- return super.onSaveInstanceState();
- }
-
- @VisibleForTesting
- Bundle saveState() {
- Bundle outState = new Bundle();
- outState.putInt(STATE_BADGE_COUNT + getIndexInTabContainer(), badge.getCount());
-
- return outState;
- }
-
- @Override
- public void onRestoreInstanceState(Parcelable state) {
- if (state instanceof Bundle) {
- Bundle bundle = (Bundle) state;
- restoreState(bundle);
-
- state = bundle.getParcelable("superstate");
- }
-
- super.onRestoreInstanceState(state);
- }
-
- @VisibleForTesting
- void restoreState(Bundle savedInstanceState) {
- int previousBadgeCount = savedInstanceState.getInt(STATE_BADGE_COUNT + getIndexInTabContainer());
- setBadgeCount(previousBadgeCount);
- }
-
- enum Type {
- FIXED, SHIFTING, TABLET
- }
-
- public static class Config {
- private final float inActiveTabAlpha;
- private final float activeTabAlpha;
- private final int inActiveTabColor;
- private final int activeTabColor;
- private final int barColorWhenSelected;
- private final int badgeBackgroundColor;
- private final int titleTextAppearance;
- private final Typeface titleTypeFace;
- private boolean badgeHidesWhenSelected = true;
-
- private Config(Builder builder) {
- this.inActiveTabAlpha = builder.inActiveTabAlpha;
- this.activeTabAlpha = builder.activeTabAlpha;
- this.inActiveTabColor = builder.inActiveTabColor;
- this.activeTabColor = builder.activeTabColor;
- this.barColorWhenSelected = builder.barColorWhenSelected;
- this.badgeBackgroundColor = builder.badgeBackgroundColor;
- this.badgeHidesWhenSelected = builder.hidesBadgeWhenSelected;
- this.titleTextAppearance = builder.titleTextAppearance;
- this.titleTypeFace = builder.titleTypeFace;
- }
-
- public static class Builder {
- private float inActiveTabAlpha;
- private float activeTabAlpha;
- private int inActiveTabColor;
- private int activeTabColor;
- private int barColorWhenSelected;
- private int badgeBackgroundColor;
- private boolean hidesBadgeWhenSelected = true;
- private int titleTextAppearance;
- private Typeface titleTypeFace;
-
- public Builder inActiveTabAlpha(float alpha) {
- this.inActiveTabAlpha = alpha;
- return this;
- }
-
- public Builder activeTabAlpha(float alpha) {
- this.activeTabAlpha = alpha;
- return this;
- }
-
- public Builder inActiveTabColor(@ColorInt int color) {
- this.inActiveTabColor = color;
- return this;
- }
-
- public Builder activeTabColor(@ColorInt int color) {
- this.activeTabColor = color;
- return this;
- }
-
- public Builder barColorWhenSelected(@ColorInt int color) {
- this.barColorWhenSelected = color;
- return this;
- }
-
- public Builder badgeBackgroundColor(@ColorInt int color) {
- this.badgeBackgroundColor = color;
- return this;
- }
-
- public Builder hideBadgeWhenSelected(boolean hide) {
- this.hidesBadgeWhenSelected = hide;
- return this;
- }
-
- public Builder titleTextAppearance(int titleTextAppearance) {
- this.titleTextAppearance = titleTextAppearance;
- return this;
- }
-
- public Builder titleTypeFace(Typeface titleTypeFace) {
- this.titleTypeFace = titleTypeFace;
- return this;
- }
-
- public Config build() {
- return new Config(this);
- }
- }
- }
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/BottomNavigationBehavior.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/BottomNavigationBehavior.java
deleted file mode 100644
index e4e2c554f..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/BottomNavigationBehavior.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.habitrpg.android.habitica.ui.views.bottombar;
-
-import android.os.Build;
-import androidx.annotation.NonNull;
-import androidx.coordinatorlayout.widget.CoordinatorLayout;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.ViewPropertyAnimatorCompat;
-import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
-
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.Interpolator;
-
-import com.google.android.material.snackbar.Snackbar;
-
-/**
- * Created by Nikola D. on 3/15/2016.
- *
- * Credit goes to Nikola Despotoski:
- * https://github.com/NikolaDespotoski
- */
-class BottomNavigationBehavior
- * This listener is fired when the current {@link BottomBar} is about to change. This gives
- * an opportunity to interrupt the {@link BottomBarTab} change.
- *
- * @param oldTabId the currently visible {@link BottomBarTab}
- * @param newTabId the {@link BottomBarTab} that will be switched to
- * @return true if you want to override/stop the tab change, false to continue as normal
- */
- boolean shouldInterceptTabSelection(@IdRes int oldTabId, @IdRes int newTabId);
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/VerticalScrollingBehavior.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/VerticalScrollingBehavior.java
deleted file mode 100644
index ab1e5bea8..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/bottombar/VerticalScrollingBehavior.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package com.habitrpg.android.habitica.ui.views.bottombar;
-
-import android.content.Context;
-import android.os.Parcelable;
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.coordinatorlayout.widget.CoordinatorLayout;
-import androidx.core.view.WindowInsetsCompat;
-
-import android.util.AttributeSet;
-import android.view.View;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Created by Nikola D. on 11/22/2015.
- *
- * Credit goes to Nikola Despotoski:
- * https://github.com/NikolaDespotoski
- */
-abstract class VerticalScrollingBehavior