{
-
- /**
- * The threshold of the gestures, which are created by the builder.
- */
- protected int threshold;
-
- /**
- * The bounds of the onscreen area, which is taken into consideration for recognizing the
- * drag gestures, which are created by the builder.
- */
- protected RectF touchableArea;
-
- /**
- * Returns a reference to the builder.
- *
- * @return A reference to the builder, casted to the generic type Builder. The reference may
- * not be null
- */
- @NonNull
- @SuppressWarnings("unchecked")
- protected final BuilderType self() {
- return (BuilderType) this;
- }
-
- /**
- * Creates a new builder, which allows to configure and create instances of the class {@link
- * DragGesture}.
- */
- public Builder() {
- setThreshold(-1);
- setTouchableArea(null);
- }
-
- /**
- * Creates and returns the drag gesture.
- *
- * @return The drag gesture, which has been created, as an instance of the generic type
- * DragGesture. The drag gesture may not be null
- */
- public abstract GestureType create();
-
- /**
- * Sets the threshold of the drag gestures, which are created by the builder.
- *
- * @param threshold
- * The threshold, which should be set, in pixels as a {@link Integer} value. The
- * threshold must be at least 0 or -1, if the default threshold should be used
- * @return The builder, this method has been called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public final BuilderType setThreshold(final int threshold) {
- Condition.INSTANCE.ensureAtLeast(threshold, -1, "The threshold must be at least -1");
- this.threshold = threshold;
- return self();
- }
-
- /**
- * Sets the bounds of the onscreen area, which should be taken into consideration for
- * recognizing the drag gestures, which are create by the builder. drag gestures.
- *
- * @param left
- * The coordinate of the left edge in pixels as a {@link Float} value. The
- * coordinate must be at least 0
- * @param top
- * The coordinate of the top edge in pixels as a {@link Float} value. The coordinate
- * must be at least 0
- * @param right
- * The coordinate of the right edge in pixels as a {@link Float} value. The
- * coordinate must be greater than the coordinate of the left edge
- * @param bottom
- * The coordinate of the bottom edge in pixels as a {@link Float} value. The
- * coordinate must be greater than the coordinate of the top edge
- * @return The builder, this method has been called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public final BuilderType setTouchableArea(final float left, final float top,
- final float right, final float bottom) {
- Condition.INSTANCE.ensureAtLeast(left, 0, "The left coordinate must be at least 0");
- Condition.INSTANCE.ensureAtLeast(top, 0, "The top coordinate must be at least 0");
- Condition.INSTANCE.ensureGreater(right, left,
- "The right coordinate must be greater than " + left);
- Condition.INSTANCE.ensureGreater(bottom, top,
- "The bottom coordinate must be greater than " + top);
- return setTouchableArea(new RectF(left, top, right, bottom));
- }
-
- /**
- * Sets the bounds of the onscreen area, which should be taken into consideration for
- * recognizing the drag gestures, which are create by the builder. drag gestures.
- *
- * @param bounds
- * The bounds, which should be set, as an instance of the class {@link RectF} or
- * null, if the area should not be restricted
- * @return The builder, this method has been called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public final BuilderType setTouchableArea(@Nullable final RectF bounds) {
- this.touchableArea = bounds;
- return self();
- }
-
- }
-
- /**
- * The distance in pixels, the gesture must last until it is recognized.
- */
- private final int threshold;
-
- /**
- * The bounds of the onscreen area, which is taken into consideration for recognizing the drag
- * gesture.
- */
- private final RectF touchableArea;
-
- /**
- * Creates a new drag gesture, which can be used to perform certain action when dragging in a
- * particular direction.
- *
- * @param threshold
- * The distance in pixels, the gesture must last until it is recognized, as an {@link
- * Integer} value. The distance must be at least 0 or -1, if the default distance should
- * be used
- * @param touchableArea
- * The bounds of the onscreen area, which should be taken into consideration for
- * recognizing the drag gesture, as an instance of the class {@link RectF} or null, if
- * the area should not be restricted
- */
- protected DragGesture(final int threshold, @Nullable final RectF touchableArea) {
- Condition.INSTANCE.ensureAtLeast(threshold, -1, "The threshold must be at least -1");
- this.threshold = threshold;
- this.touchableArea = touchableArea;
- }
-
- /**
- * Returns the distance in pixels, the gesture must last until it is recognized.
- *
- * The distance in pixels, the gesture must last until it is recognized, as an {@link Integer}
- * value. The distance must be at least 0 or -1, if the default distance should be used
- */
- public final int getThreshold() {
- return threshold;
- }
-
- /**
- * Returns the bounds of the onscreen area, which is taken into consideration for recognizing
- * the drag gesture.
- *
- * @return The bounds of the onscreen area, which is taken into consideration for recognizing
- * the drag gesture, as an instance of the class {@link RectF} or null, if the area is not
- * restricted
- */
- @Nullable
- public final RectF getTouchableArea() {
- return touchableArea;
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/Layout.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/Layout.java
deleted file mode 100644
index 29726a23..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/Layout.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-/**
- * Contains all possible layouts of a {@link TabSwitcher}.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public enum Layout {
-
- /**
- * The layout, which is used on smartphones and phablet devices, when in portrait mode.
- */
- PHONE_PORTRAIT,
-
- /**
- * The layout, which is used on smartphones and phablet devices, when in landscape mode.
- */
- PHONE_LANDSCAPE,
-
- /**
- * The layout, which is used on tablets.
- */
- TABLET
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/LayoutPolicy.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/LayoutPolicy.java
deleted file mode 100644
index 73f7ab93..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/LayoutPolicy.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-/**
- * Contains all possible layout policies of a {@link TabSwitcher}.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public enum LayoutPolicy {
-
- /**
- * If the layout should automatically adapted, depending on whether the device is a smartphone
- * or tablet.
- */
- AUTO(0),
-
- /**
- * If the smartphone layout should be used, regardless of the device.
- */
- PHONE(1),
-
- /**
- * If the tablet layout should be used, regardless of the device.
- */
- TABLET(2);
-
- /**
- * The value of the layout policy.
- */
- private final int value;
-
- /**
- * Creates a new layout policy.
- *
- * @param value
- * The value of the layout policy as an {@link Integer} value
- */
- LayoutPolicy(final int value) {
- this.value = value;
- }
-
- /**
- * Returns the value of the layout policy.
- *
- * @return The value of the layout policy as an {@link Integer} value
- */
- public final int getValue() {
- return value;
- }
-
- /**
- * Returns the layout policy, which corresponds to a specific value.
- *
- * @param value
- * The value of the layout policy, which should be returned, as an {@link Integer}
- * value
- * @return The layout policy, which corresponds to the given value, as a value of the enum
- * {@link LayoutPolicy}
- */
- public static LayoutPolicy fromValue(final int value) {
- for (LayoutPolicy layoutPolicy : values()) {
- if (layoutPolicy.getValue() == value) {
- return layoutPolicy;
- }
- }
-
- throw new IllegalArgumentException("Invalid enum value: " + value);
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/PeekAnimation.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/PeekAnimation.java
deleted file mode 100644
index 771881dc..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/PeekAnimation.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import android.view.animation.Interpolator;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * A peek animation, which animates the size of a tab starting at a specific position in order to
- * show the tab for a short time at the end of a {@link TabSwitcher}. Peek animations can be used to
- * add tabs while the tab switcher is not shown and when using the smartphone layout. They are meant
- * to be used when adding a tab without selecting it and enable the user to peek at the added tab
- * for a short moment.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class PeekAnimation extends Animation {
-
- /**
- * A builder, which allows to configure and create instances of the class {@link
- * PeekAnimation}.
- */
- public static class Builder extends Animation.Builder {
-
- /**
- * The horizontal position, the animations, which are created by the builder, start at.
- */
- private float x;
-
- /**
- * The vertical position, the animations, which are created by the builder, start at.
- */
- private float y;
-
- /**
- * Creates a new builder, which allows to configure and create instances of the class {@link
- * PeekAnimation}.
- */
- public Builder() {
- setX(0);
- setY(0);
- }
-
- /**
- * Sets the horizontal position, the animations, which are created by the builder, should
- * start at.
- *
- * @param x
- * The horizontal position, which should be set, in pixels as a {@link Float} value
- * @return The builder, this method has be called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public final Builder setX(final float x) {
- this.x = x;
- return self();
- }
-
- /**
- * Sets the vertical position, the animations, which are created by the builder, should
- * start at.
- *
- * @param y
- * The vertical position, which should be set, in pixels as a {@link Float} value
- * @return The builder, this method has be called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public final Builder setY(final float y) {
- this.y = y;
- return self();
- }
-
- @NonNull
- @Override
- public final PeekAnimation create() {
- return new PeekAnimation(duration, interpolator, x, y);
- }
-
- }
-
- /**
- * The horizontal position, the animation starts at.
- */
- private final float x;
-
- /**
- * The vertical position, the animation starts at.
- */
- private final float y;
-
- /**
- * Creates a new reveal animation.
- *
- * @param x
- * The horizontal position, the animation should start at, in pixels as a {@link Float}
- * value
- * @param y
- * The vertical position, the animation should start at, in pixels as a {@link Float}
- * value
- */
- private PeekAnimation(final long duration, @Nullable final Interpolator interpolator,
- final float x, final float y) {
- super(duration, interpolator);
- this.x = x;
- this.y = y;
- }
-
- /**
- * Returns the horizontal position, the animation starts at.
- *
- * @return The horizontal position, the animation starts at, in pixels as a {@link Float} value
- */
- public final float getX() {
- return x;
- }
-
- /**
- * Returns the vertical position, the animation starts at.
- *
- * @return The vertical position, the animation starts at, in pixels as a {@link Float} value
- */
- public final float getY() {
- return y;
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/PullDownGesture.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/PullDownGesture.java
deleted file mode 100644
index 90b238c3..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/PullDownGesture.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import android.graphics.RectF;
-
-import androidx.annotation.Nullable;
-
-/**
- * A drag gesture, which can be used to show the tab switcher by pulling down the currently selected
- * tab, when using the smartphone layout.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public class PullDownGesture extends DragGesture {
-
- /**
- * A builder, which allows to configure and create instances of the class {@link
- * PullDownGesture}.
- */
- public static class Builder extends DragGesture.Builder {
-
- @Override
- public final PullDownGesture create() {
- return new PullDownGesture(threshold, touchableArea);
- }
-
- }
-
- /**
- * Creates a new drag gesture, which can be used to show the tab switcher by pulling down the
- * currently selected tab, when using the smartphone layout.
- *
- * @param threshold
- * The distance in pixels, the gesture must last until it is recognized, as an {@link
- * Integer} value. The distance must be at least 0 or -1, if the default distance should
- * be used
- * @param touchableArea
- * The bounds of the onscreen area, which should be taken into consideration for
- * recognizing the drag gesture, as an instance of the class {@link RectF} or null, if
- * the area should not be restricted
- */
- private PullDownGesture(final int threshold, @Nullable final RectF touchableArea) {
- super(threshold, touchableArea);
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/RevealAnimation.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/RevealAnimation.java
deleted file mode 100644
index a0de3fde..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/RevealAnimation.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import android.view.animation.Interpolator;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * A reveal animation, which animates the size of a tab starting at a specific position. Reveal
- * animations can be used to add tabs to a {@link TabSwitcher} when using the smartphone layout.
- * Tabs, which have been added by using a reveal animation, are selected automatically.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class RevealAnimation extends Animation {
-
- /**
- * A builder, which allows to configure and create instances of the class {@link
- * RevealAnimation}.
- */
- public static class Builder extends Animation.Builder {
-
- /**
- * The horizontal position, the animations, which are created by the builder, start at.
- */
- private float x;
-
- /**
- * The vertical position, the animations, which are created by the builder, start at.
- */
- private float y;
-
- /**
- * Creates a new builder, which allows to configure and create instances of the class {@link
- * RevealAnimation}.
- */
- public Builder() {
- setX(0);
- setY(0);
- }
-
- /**
- * Sets the horizontal position, the animations, which are created by the builder, should
- * start at.
- *
- * @param x
- * The horizontal position, which should be set, in pixels as a {@link Float} value
- * @return The builder, this method has be called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public final Builder setX(final float x) {
- this.x = x;
- return self();
- }
-
- /**
- * Sets the vertical position, the animations, which are created by the builder, should
- * start at.
- *
- * @param y
- * The vertical position, which should be set, in pixels as a {@link Float} value
- * @return The builder, this method has be called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public final Builder setY(final float y) {
- this.y = y;
- return self();
- }
-
- @NonNull
- @Override
- public final RevealAnimation create() {
- return new RevealAnimation(duration, interpolator, x, y);
- }
-
- }
-
- /**
- * The horizontal position, the animation starts at.
- */
- private final float x;
-
- /**
- * The vertical position, the animation starts at.
- */
- private final float y;
-
- /**
- * Creates a new reveal animation.
- *
- * @param x
- * The horizontal position, the animation should start at, in pixels as a {@link Float}
- * value
- * @param y
- * The vertical position, the animation should start at, in pixels as a {@link Float}
- * value
- */
- private RevealAnimation(final long duration, @Nullable final Interpolator interpolator,
- final float x, final float y) {
- super(duration, interpolator);
- this.x = x;
- this.y = y;
- }
-
- /**
- * Returns the horizontal position, the animation starts at.
- *
- * @return The horizontal position, the animation starts at, in pixels as a {@link Float} value
- */
- public final float getX() {
- return x;
- }
-
- /**
- * Returns the vertical position, the animation starts at.
- *
- * @return The vertical position, the animation starts at, in pixels as a {@link Float} value
- */
- public final float getY() {
- return y;
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/StatefulTabSwitcherDecorator.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/StatefulTabSwitcherDecorator.java
deleted file mode 100644
index 5374769d..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/StatefulTabSwitcherDecorator.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.lang.ref.SoftReference;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.android.tabswitcher.model.Restorable;
-import de.mrapp.util.Condition;
-
-/**
- * A {@link TabSwitcherDecorator}, which allows to store any arbitrary state for each tab of the
- * associated {@link TabSwitcher}. The state is kept even if the tab is currently not shown.
- * However, it is possible that states are vanished, if few memory is available, because they are
- * stored using {@link SoftReference}s. Unlike the parameters, which can be set for an individual
- * {@link Tab} using the method {@link Tab#setParameters(Bundle)}, these states are not restored
- * when restoring the state of a {@link TabSwitcher}, e.g. after orientation changes. Instead the
- * state is vanished and will be created from scratch when the tab is shown for the next time.
- *
- * If it is necessary to store some data from a state, it can be put into the bundle, which is
- * passed to the {@link #onSaveInstanceState(View, Tab, int, int, Object, Bundle)} method. The data
- * can later be retrieved from the bundle when the method
- * {@link #onCreateState(Context, TabSwitcher, View, Tab, int, int, Bundle)} is invoked for the next
- * time.
- *
- * It is recommended to use the class {@link AbstractState} as a base class for implementing states.
- * This is not necessary though. Said class stores a reference to the tab, it corresponds to and
- * implements the interface {@link Restorable} to be able to store and restore its state. By
- * implementing the methods of this interface and calling them in the decorator's {@link
- * #onSaveInstanceState(View, Tab, int, int, Object, Bundle)}, respectively {@link
- * #onCreateState(Context, TabSwitcher, View, Tab, int, int, Bundle)} method, the selected
- * properties of the state can be stored and restored.
- *
- * If {@link TabSwitcher#areSavedStatesClearedWhenRemovingTabs()} returns true, the state of tabs is
- * cleared when a tab has been removed from the {@link TabSwitcher}. This can be prevented by using
- * the method {@link TabSwitcher#clearSavedStatesWhenRemovingTabs(boolean)}. To manually remove the
- * state of a specific tab, the method {@link #clearState(Tab)} can be used. The method {@link
- * #clearAllStates()} allows to remove the states of all tabs accordingly.
- *
- * IMPORTANT: States must not store references to views, which have been inflated in the decorator's
- * {@link #onInflateView(LayoutInflater, ViewGroup, int)} method, because these views can be reused
- * across all tabs of the {@link TabSwitcher} and therefore are not guaranteed to belong to the same
- * tab for the whole lifetime of the decorator.
- *
- * @param
- * The type of the states, which are stored by the decorator
- * @author Michael Rapp
- * @since 0.2.4
- */
-public abstract class StatefulTabSwitcherDecorator extends TabSwitcherDecorator {
-
- /**
- * A sparse array, which is used to store the states of tabs.
- */
- private SparseArray> states;
-
- /**
- * The method, which is invoked on subclasses in order to create the state for a specific tab.
- * This method is invoked, when a tab is shown or refreshed and no corresponding state exists
- * yet.
- *
- * @param context
- * The context, the tab switcher belongs to, as an instance of the class {@link
- * Context}. The context may not be null
- * @param tabSwitcher
- * The tab switcher, whose tabs are visualized by the decorator, as an instance of the
- * type {@link TabSwitcher}. The tab switcher may not be null
- * @param view
- * The view, which is used to visualize the tab, as an instance of the class {@link
- * View}. The view may not be null
- * @param tab
- * The tab, for which a state should be created, as an instance of the class {@link
- * Tab}. The tab may not be null
- * @param index
- * The index of the tab, for which a state should be created, as an {@link Integer}
- * value
- * @param viewType
- * The view type of the tab, for which a state should be created, as an {@link Integer}
- * value
- * @param savedInstanceState
- * The bundle, which has previously been used to save the state of the tab as an
- * instance of the class {@link Bundle} or null, if no saved state is available
- * @return The state, which has been created, as an instance of the generic type {@link
- * StateType} or null, if no state has been created
- */
- @Nullable
- protected abstract StateType onCreateState(@NonNull final Context context,
- @NonNull final TabSwitcher tabSwitcher,
- @NonNull final View view, @NonNull final Tab tab,
- final int index, final int viewType,
- @Nullable final Bundle savedInstanceState);
-
- /**
- * The method, which is invoked on subclasses, when a state is cleared using the {@link
- * #clearState(Tab)} or {@link #clearAllStates()} method.
- *
- * @param state
- * The state, which is cleared, as an instance of the generic type {@link StateType}.
- * The state may not be null
- */
- protected void onClearState(@NonNull final StateType state) {
-
- }
-
- /**
- * The method which is invoked, when the view, which is used to visualize a tab, should be
- * shown, respectively when it should be refreshed. The purpose of this method is to customize
- * the appearance of the view, which is used to visualize the corresponding tab, depending on
- * its state and whether the tab switcher is currently shown, or not.
- *
- * @param context
- * The context, the tab switcher belongs to, as an instance of the class {@link
- * Context}. The context may not be null
- * @param tabSwitcher
- * The tab switcher, whose tabs are visualized by the decorator, as an instance of the
- * type {@link TabSwitcher}. The tab switcher may not be null
- * @param view
- * The view, which is used to visualize the tab, as an instance of the class {@link
- * View}. The view may not be null
- * @param tab
- * The tab, which should be visualized, as an instance of the class {@link Tab}. The tab
- * may not be null
- * @param index
- * The index of the tab, which should be visualized, as an {@link Integer} value
- * @param viewType
- * The view type of the tab, which should be visualized, as an {@link Integer} value
- * @param state
- * The state of the tab, which should be visualized, as an instance of the generic type
- * {@link StateType} or null, if no state has been created yet
- * @param savedInstanceState
- * The bundle, which has previously been used to save the state of the view as an
- * instance of the class {@link Bundle} or null, if no saved state is available
- * @see #onShowTab(Context, TabSwitcher, View, Tab, int, int, Bundle)
- */
- protected abstract void onShowTab(@NonNull final Context context,
- @NonNull final TabSwitcher tabSwitcher,
- @NonNull final View view, @NonNull final Tab tab,
- final int index, final int viewType,
- @Nullable final StateType state,
- @Nullable final Bundle savedInstanceState);
-
- /**
- * The method, which is invoked, when the view, which is used to visualize a tab, is removed.
- * The purpose of this method is to save the current state of the tab in a bundle.
- *
- * @param view
- * The view, which is used to visualize the tab, as an instance of the class {@link
- * View}
- * @param tab
- * The tab, whose state should be saved, as an instance of the class {@link Tab}. The
- * tab may not be null
- * @param index
- * The index of the tab, whose state should be saved, as an {@link Integer} value
- * @param viewType
- * The view type of the tab, whose state should be saved, as an {@link Integer} value
- * @param state
- * The state of tab, whose state should be saved, as an instance of the generic type
- * {@link StateType} or null, if no state has been created yet
- * @param outState
- * The bundle, the state of the tab should be saved to, as an instance of the class
- * {@link Bundle}. The bundle may not be null
- * @see #onSaveInstanceState(View, Tab, int, int, Bundle)
- */
- protected void onSaveInstanceState(@NonNull final View view, @NonNull final Tab tab,
- final int index, final int viewType,
- @Nullable final StateType state,
- @NonNull final Bundle outState) {
-
- }
-
- /**
- * Returns the state of a specific tab.
- *
- * @param tab
- * The tab, whose state should be returned, as an instance of the class {@link Tab}. The
- * tab may not be null
- * @return The state of the given tab as an instance of the generic type {@link StateType} or
- * null, if no state has been created yet or if it was removed
- */
- @Nullable
- public final StateType getState(@NonNull final Tab tab) {
- Condition.INSTANCE.ensureNotNull(tab, "The tab may not be null");
-
- if (states != null) {
- SoftReference reference = states.get(tab.hashCode());
-
- if (reference != null) {
- return reference.get();
- }
- }
-
- return null;
- }
-
- /**
- * Removes the state of a specific tab.
- *
- * @param tab
- * The tab, whose state should be removed, as an instance of the class {@link Tab}. The
- * tab may not be null
- */
- public final void clearState(@NonNull final Tab tab) {
- Condition.INSTANCE.ensureNotNull(tab, "The tab may not be null");
-
- if (states != null) {
- SoftReference reference = states.get(tab.hashCode());
-
- if (reference != null) {
- StateType state = reference.get();
-
- if (state != null) {
- onClearState(state);
- }
-
- states.remove(tab.hashCode());
-
- if (states.size() == 0) {
- states = null;
- }
- }
- }
- }
-
- /**
- * Removes the states of all tabs.
- */
- public final void clearAllStates() {
- if (states != null) {
- for (int i = 0; i < states.size(); i++) {
- SoftReference reference = states.valueAt(i);
- StateType state = reference.get();
-
- if (state != null) {
- onClearState(state);
- }
- }
-
- states.clear();
- states = null;
- }
- }
-
- @Override
- public final void onShowTab(@NonNull final Context context,
- @NonNull final TabSwitcher tabSwitcher, @NonNull final View view,
- @NonNull final Tab tab, final int index, final int viewType,
- @Nullable final Bundle savedInstanceState) {
- if (states == null) {
- states = new SparseArray<>();
- }
-
- StateType state = getState(tab);
-
- if (state == null) {
- state = onCreateState(context, tabSwitcher, view, tab, index, viewType,
- savedInstanceState);
-
- if (state != null) {
- states.put(tab.hashCode(), new SoftReference<>(state));
- }
- }
-
- onShowTab(context, tabSwitcher, view, tab, index, viewType, state, savedInstanceState);
- }
-
- @Override
- public final void onSaveInstanceState(@NonNull final View view, @NonNull final Tab tab,
- final int index, final int viewType,
- @NonNull final Bundle outState) {
- StateType state = getState(tab);
- onSaveInstanceState(view, tab, index, viewType, state, outState);
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/SwipeAnimation.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/SwipeAnimation.java
deleted file mode 100644
index ccc306e9..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/SwipeAnimation.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import android.view.animation.Interpolator;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.util.Condition;
-
-/**
- * A swipe animation, which moves tabs on the orthogonal axis. When using the smartphone layout,
- * their size and opacity is animated at the same time. Swipe animations can be used to add or
- * remove tabs to a {@link TabSwitcher}.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class SwipeAnimation extends Animation {
-
- /**
- * Contains all possible directions of a swipe animation.
- */
- public enum SwipeDirection {
-
- /**
- * When the tab should be moved to/from the left, respectively the top when in landscape
- * mode.
- */
- LEFT_OR_TOP,
-
- /**
- * When the tab should be moved to/from the right, respectively the bottom when in landscape
- * mode.
- */
- RIGHT_OR_BOTTOM
-
- }
-
- /**
- * A builder, which allows to configure and create instances of the class {@link
- * SwipeAnimation}.
- */
- public static class Builder extends Animation.Builder {
-
- /**
- * The direction of the animations, which are created by the builder.
- */
- private SwipeDirection direction;
-
- /**
- * The duration of the animations, which are used to relocate the other tabs, when a tabs
- * has been added or removed.
- */
- private long relocateAnimationDuration;
-
- /**
- * Creates a new builder, which allows to configure and create instances of the class {@link
- * SwipeAnimation}.
- */
- public Builder() {
- setDirection(SwipeDirection.RIGHT_OR_BOTTOM);
- setRelocateAnimationDuration(-1);
- }
-
- /**
- * Sets the direction of the animations, which are created by the builder.
- *
- * @param direction
- * The direction, which should be set, as a value of the enum {@link
- * SwipeDirection}. The direction may either be {@link SwipeDirection#LEFT_OR_TOP}
- * or {@link SwipeDirection#RIGHT_OR_BOTTOM}
- * @return The builder, this method has be called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public final Builder setDirection(@NonNull final SwipeDirection direction) {
- Condition.INSTANCE.ensureNotNull(direction, "The direction may not be null");
- this.direction = direction;
- return self();
- }
-
- /**
- * Sets the duration of the animations, which are used to relocate the other tabs, when a
- * tab has been added or removed.
- *
- * @param relocateAnimationDuration
- * The duration, which should be set, in milliseconds as a {@link Long} value or -1,
- * if the default duration should be used
- * @return The builder, this method has be called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public final Builder setRelocateAnimationDuration(final long relocateAnimationDuration) {
- Condition.INSTANCE.ensureAtLeast(relocateAnimationDuration, -1,
- "The relocate animation duration must be at least -1");
- this.relocateAnimationDuration = relocateAnimationDuration;
- return self();
- }
-
- @NonNull
- @Override
- public final SwipeAnimation create() {
- return new SwipeAnimation(duration, interpolator, direction, relocateAnimationDuration);
- }
-
- }
-
- /**
- * The direction of the swipe animation.
- */
- private final SwipeDirection direction;
-
- /**
- * The duration of the animations, which are used to relocate the other tabs, when a tabs has
- * been added or removed.
- */
- private final long relocateAnimationDuration;
-
- /**
- * Creates a new swipe animation.
- *
- * @param duration
- * The duration of the animation in milliseconds as a {@link Long} value or -1, if the
- * default duration should be used
- * @param interpolator
- * The interpolator, which should be used by the animation, as an instance of the type
- * {@link Interpolator} or null, if the default interpolator should be used
- * @param direction
- * The direction of the swipe animation as a value of the enum {@link SwipeDirection}.
- * The direction may not be null
- * @param relocateAnimationDuration
- * The duration of the animations, which are used to relocate other tabs, when a tab has
- * been added or removed, in milliseconds as a {@link Long} value or -1, if the default
- * duration should be used
- */
- private SwipeAnimation(final long duration, @Nullable final Interpolator interpolator,
- @NonNull final SwipeDirection direction,
- final long relocateAnimationDuration) {
- super(duration, interpolator);
- Condition.INSTANCE.ensureNotNull(direction, "The direction may not be null");
- Condition.INSTANCE.ensureAtLeast(relocateAnimationDuration, -1,
- "The relocate animation duration must be at least -1");
- this.direction = direction;
- this.relocateAnimationDuration = relocateAnimationDuration;
- }
-
- /**
- * Returns the direction of the swipe animation.
- *
- * @return The direction of the swipe animation as a value of the enum {@link SwipeDirection}.
- * The direction may not be null
- */
- @NonNull
- public final SwipeDirection getDirection() {
- return direction;
- }
-
- /**
- * Returns the duration of the animations, which are used to relocate the other tabs, when a tab
- * has been added or removed.
- *
- * @return The duration of the animations, which are used to relocate the other tabs, when a tab
- * has been added or removed, in milliseconds as a {@link Long} value or -1, if the default
- * duration is used
- */
- public final long getRelocateAnimationDuration() {
- return relocateAnimationDuration;
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/SwipeGesture.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/SwipeGesture.java
deleted file mode 100644
index 51602d78..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/SwipeGesture.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import android.graphics.RectF;
-
-import androidx.annotation.Nullable;
-import de.mrapp.util.Condition;
-
-/**
- * A drag gesture, which allows to switch between tabs, when swiping horizontally.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public class SwipeGesture extends DragGesture {
-
- /**
- * A builder, which allows to configure and create instances of the class {@link SwipeGesture}.
- */
- public static class Builder extends DragGesture.Builder {
-
- /**
- * The duration of the swipe animation of the gestures, which are created by the builder.
- */
- private long animationDuration;
-
- /**
- * Creates a new builder, which allows to configure and create instances of the class {@link
- * SwipeGesture}.
- */
- public Builder() {
- animationDuration = -1;
- }
-
- /**
- * Sets the duration of the swipe animation of the gestures, which are created by the
- * builder.
- *
- * @param animationDuration
- * The duration, which should be set, in milliseconds as a {@link Long} value or -1,
- * if the default duration should be used
- * @return The builder, this method has been called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- public Builder setAnimationDuration(final long animationDuration) {
- Condition.INSTANCE.ensureAtLeast(animationDuration, -1,
- "The animation duration must be at least -1");
- this.animationDuration = animationDuration;
- return self();
- }
-
- @Override
- public final SwipeGesture create() {
- return new SwipeGesture(threshold, touchableArea, animationDuration);
- }
-
- }
-
- /**
- * The duration of the swipe animation in milliseconds.
- */
- private final long animationDuration;
-
- /**
- * Creates a new drag gesture, which allows to switch between tabs, when swiping horizontally.
- *
- * @param threshold
- * The distance in pixels, the gesture must last until it is recognized, as an {@link
- * Integer} value. The distance must be at least 0 or -1, if the default distance should
- * be used
- * @param touchableArea
- * The bounds of the onscreen area, which should be taken into consideration for
- * recognizing the drag gesture, as an instance of the class {@link RectF} or null, if
- * the area should not be restricted
- * @param animationDuration
- * The duration of the swipe animation in milliseconds as a {@link Long} value. The
- * duration must be at least -1
- */
- private SwipeGesture(final int threshold, @Nullable final RectF touchableArea,
- final long animationDuration) {
- super(threshold, touchableArea);
- Condition.INSTANCE
- .ensureAtLeast(animationDuration, -1, "The animation duration must be at least -1");
- this.animationDuration = animationDuration;
- }
-
- /**
- * Returns the duration of the swipe animation.
- *
- * @return The duration of the swipe animation in milliseconds as a {@link Long} value or -1, if
- * the default duration should be used
- */
- public final long getAnimationDuration() {
- return animationDuration;
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/Tab.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/Tab.java
deleted file mode 100644
index 73e906c8..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/Tab.java
+++ /dev/null
@@ -1,863 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Bitmap;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-import androidx.appcompat.content.res.AppCompatResources;
-import de.mrapp.util.Condition;
-import de.mrapp.util.datastructure.ListenerList;
-
-/**
- * A tab, which can be added to a {@link TabSwitcher} widget. It has a title, as well as an optional
- * icon. Furthermore, it is possible to set a custom color and to specify, whether the tab should be
- * closeable, or not.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class Tab implements Parcelable {
-
- /**
- * The name of the parameter, which specifies, whether the tab was already shown in a {@link
- * TabSwitcher}, or not. This parameter should be not be set or modified manually.
- */
- public static final String WAS_SHOWN_PARAMETER = Tab.class.getName() + "::wasShown";
-
- /**
- * A creator, which allows to create instances of the class {@link Tab} from parcels.
- */
- public static final Creator CREATOR = new Creator() {
-
- @Override
- public Tab createFromParcel(final Parcel source) {
- return new Tab(source);
- }
-
- @Override
- public Tab[] newArray(final int size) {
- return new Tab[size];
- }
-
- };
-
- /**
- * Defines the interface, a class, which should be notified, when a tab's properties have been
- * changed, must implement.
- */
- public interface Callback {
-
- /**
- * The method, which is invoked, when the tab's title has been changed.
- *
- * @param tab
- * The observed tab as an instance of the class {@link Tab}. The tab may not be
- * null
- */
- void onTitleChanged(@NonNull Tab tab);
-
- /**
- * The method, which is invoked, when the tab's icon has been changed.
- *
- * @param tab
- * The observed tab as an instance of the class {@link Tab}. The tab may not be
- * null
- */
- void onIconChanged(@NonNull Tab tab);
-
- /**
- * The method, which is invoked, when it has been changed, whether the tab is closeable, or
- * not.
- *
- * @param tab
- * The observed tab as an instance of the class {@link Tab}. The tab may not be
- * null
- */
- void onCloseableChanged(@NonNull Tab tab);
-
- /**
- * The method, which is invoked, when the icon of the tab's close button has been changed.
- *
- * @param tab
- * The observed tab as an instance of the class {@link Tab}. The tab may not be
- * null
- */
- void onCloseButtonIconChanged(@NonNull Tab tab);
-
- /**
- * The method, which is invoked, when the tab's background color has been changed.
- *
- * @param tab
- * The observed tab as an instance of the class {@link Tab}. The tab may not be
- * null
- */
- void onBackgroundColorChanged(@NonNull Tab tab);
-
- /**
- * The method, which is invoked, when the background color of the tab's content has been
- * changed.
- *
- * @param tab
- * The observed tab as an instance of the class {@link Tab}. The tab may not be
- * null
- */
- void onContentBackgroundColorChanged(@NonNull Tab tab);
-
- /**
- * The method, which is invoked, when the text color of the tab's title has been changed.
- *
- * @param tab
- * The observed tab as an instance of the class {@link Tab}. The tab may not be
- * null
- */
- void onTitleTextColorChanged(@NonNull Tab tab);
-
- /**
- * The method, which is invoked, when the visibility of the tab's progress bar has been
- * changed.
- *
- * @param tab
- * The observed tab as an instance of the class {@link Tab}. The tab may not be
- * null
- */
- void onProgressBarVisibilityChanged(@NonNull Tab tab);
-
- /**
- * The method, which is invoked, when the color of the tab's progress bar has been changed.
- *
- * @param tab
- * The observed tab as an instance of the class {@link Tab}. The tab may not be
- * null
- */
- void onProgressBarColorChanged(@NonNull Tab tab);
-
- }
-
- /**
- * A set, which contains the callbacks, which have been registered to be notified, when the
- * tab's properties have been changed.
- */
- private final ListenerList callbacks = new ListenerList<>();
-
- /**
- * The tab's title.
- */
- private CharSequence title;
-
- /**
- * The resource id of the tab's icon.
- */
- private int iconId;
-
- /**
- * The tab's icon as a bitmap.
- */
- private Bitmap iconBitmap;
-
- /**
- * The color state list, which is used to tint the tab's icon.
- */
- private ColorStateList iconTintList;
-
- /**
- * The mode, which is used to tint the tab's icon.
- */
- private PorterDuff.Mode iconTintMode;
-
- /**
- * True, if the tab is closeable, false otherwise.
- */
- private boolean closeable;
-
- /**
- * The resource id of the icon of the tab's close button.
- */
- private int closeButtonIconId;
-
- /**
- * The bitmap of the icon of the tab's close button.
- */
- private Bitmap closeButtonIconBitmap;
-
- /**
- * The color state list, which is used to tint the tab's close button.
- */
- private ColorStateList closeButtonIconTintList;
-
- /**
- * The mode, which is used to tint the tab's close button.
- */
- private PorterDuff.Mode closeButtonIconTintMode;
-
- /**
- * The background color of the tab.
- */
- private ColorStateList backgroundColor;
-
- /**
- * The background color of the tab's content.
- */
- private int contentBackgroundColor;
-
- /**
- * The text color of the tab's title.
- */
- private ColorStateList titleTextColor;
-
- /**
- * True, if the tab's progress bar is shown, false otherwise.
- */
- private boolean progressBarShown;
-
- /**
- * The color of the tab's progress bar.
- */
- private int progressBarColor;
-
- /**
- * Optional parameters, which are associated with the tab.
- */
- private Bundle parameters;
-
- /**
- * Notifies all callbacks, that the tab's title has been changed.
- */
- private void notifyOnTitleChanged() {
- for (Callback callback : callbacks) {
- callback.onTitleChanged(this);
- }
- }
-
- /**
- * Notifies all callbacks, that the tab's icon has been changed.
- */
- private void notifyOnIconChanged() {
- for (Callback callback : callbacks) {
- callback.onIconChanged(this);
- }
- }
-
- /**
- * Notifies all callbacks, that it has been changed, whether the tab is closeable, or not.
- */
- private void notifyOnCloseableChanged() {
- for (Callback callback : callbacks) {
- callback.onCloseableChanged(this);
- }
- }
-
- /**
- * Notifies all callbacks, that the icon of the tab's close button has been changed.
- */
- private void notifyOnCloseButtonIconChanged() {
- for (Callback callback : callbacks) {
- callback.onCloseButtonIconChanged(this);
- }
- }
-
- /**
- * Notifies all callbacks, that the background color of the tab has been changed.
- */
- private void notifyOnBackgroundColorChanged() {
- for (Callback callback : callbacks) {
- callback.onBackgroundColorChanged(this);
- }
- }
-
- /**
- * Notifies all callbacks, that the background color of the tab's content has been changed.
- */
- private void notifyOnContentBackgroundColorChanged() {
- for (Callback callback : callbacks) {
- callback.onContentBackgroundColorChanged(this);
- }
- }
-
- /**
- * Notifies all callbacks, that the text color of the tab has been changed.
- */
- private void notifyOnTitleTextColorChanged() {
- for (Callback callback : callbacks) {
- callback.onTitleTextColorChanged(this);
- }
- }
-
- /**
- * Notifies all callbacks, that the visibility of the tab's progress bar has been changed.
- */
- private void notifyOnProgressBarVisibilityChanged() {
- for (Callback callback : callbacks) {
- callback.onProgressBarVisibilityChanged(this);
- }
- }
-
- /**
- * Notifies all callbacks, that the color of the tab's progress bar has been changed.
- */
- private void notifyOnProgressBarColorChanged() {
- for (Callback callback : callbacks) {
- callback.onProgressBarColorChanged(this);
- }
- }
-
- /**
- * Creates a new tab, which can be added to a {@link TabSwitcher} widget.
- *
- * @param source
- * The parcel, the tab should be created from, as an instance of the class {@link
- * Parcel}. The parcel may not be null
- */
- private Tab(@NonNull final Parcel source) {
- this.title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
- this.iconId = source.readInt();
- this.iconBitmap = source.readParcelable(getClass().getClassLoader());
- this.iconTintList = source.readParcelable(getClass().getClassLoader());
- this.iconTintMode = (PorterDuff.Mode) source.readSerializable();
- this.closeable = source.readInt() > 0;
- this.closeButtonIconId = source.readInt();
- this.closeButtonIconBitmap = source.readParcelable(getClass().getClassLoader());
- this.closeButtonIconTintList = source.readParcelable(getClass().getClassLoader());
- this.closeButtonIconTintMode = (PorterDuff.Mode) source.readSerializable();
- this.backgroundColor = source.readParcelable(getClass().getClassLoader());
- this.contentBackgroundColor = source.readInt();
- this.titleTextColor = source.readParcelable(getClass().getClassLoader());
- this.progressBarShown = source.readInt() > 0;
- this.progressBarColor = source.readInt();
- this.parameters = source.readBundle(getClass().getClassLoader());
- }
-
- /**
- * Creates a new tab, which can be added to a {@link TabSwitcher} widget.
- *
- * @param title
- * The tab's title as an instance of the type {@link CharSequence}. The title may not be
- * neither be null, nor empty
- */
- public Tab(@NonNull final CharSequence title) {
- setTitle(title);
- this.closeable = true;
- this.closeButtonIconId = -1;
- this.closeButtonIconBitmap = null;
- this.closeButtonIconTintList = null;
- this.closeButtonIconTintMode = null;
- this.iconId = -1;
- this.iconBitmap = null;
- this.iconTintList = null;
- this.iconTintMode = null;
- this.backgroundColor = null;
- this.contentBackgroundColor = -1;
- this.titleTextColor = null;
- this.progressBarShown = false;
- this.progressBarColor = -1;
- this.parameters = null;
- }
-
- /**
- * Creates a new tab, which can be added to a {@link TabSwitcher} widget.
- *
- * @param context
- * The context, which should be used, as an instance of the class {@link Context}. The
- * context may not be null
- * @param resourceId
- * The resource id of the tab's title as an {@link Integer} value. The resource id must
- * correspond to a valid string resource
- */
- public Tab(@NonNull final Context context, @StringRes final int resourceId) {
- this(context.getString(resourceId));
- }
-
- /**
- * Returns the tab's title.
- *
- * @return The tab's title as an instance of the type {@link CharSequence}. The title may
- * neither be null, nor empty
- */
- @NonNull
- public final CharSequence getTitle() {
- return title;
- }
-
- /**
- * Sets the tab's title.
- *
- * @param title
- * The title, which should be set, as an instance of the type {@link CharSequence}. The
- * title may neither be null, nor empty
- */
- public final void setTitle(@NonNull final CharSequence title) {
- Condition.INSTANCE.ensureNotNull(title, "The title may not be null");
- Condition.INSTANCE.ensureNotEmpty(title, "The title may not be empty");
- this.title = title;
- notifyOnTitleChanged();
- }
-
- /**
- * Sets the tab's title.
- *
- * @param context
- * The context, which should be used, as an instance of the class {@link Context}. The
- * context may not be null
- * @param resourceId
- * The resource id of the title, which should be set, as an {@link Integer} value. The
- * resource id must correspond to a valid string resource
- */
- public final void setTitle(@NonNull final Context context, @StringRes final int resourceId) {
- setTitle(context.getText(resourceId));
- }
-
- /**
- * Returns the tab's icon.
- *
- * @param context
- * The context, which should be used, as an instance of the class {@link Context}. The
- * context may not be null
- * @return The tab's icon as an instance of the class {@link Drawable} or null, if no custom
- * icon is set
- */
- @Nullable
- public final Drawable getIcon(@NonNull final Context context) {
- Condition.INSTANCE.ensureNotNull(context, "The context may not be null");
-
- if (iconId != -1) {
- return AppCompatResources.getDrawable(context, iconId);
- } else {
- return iconBitmap != null ? new BitmapDrawable(context.getResources(), iconBitmap) :
- null;
- }
- }
-
- /**
- * Sets the tab's icon.
- *
- * @param resourceId
- * The resource id of the icon, which should be set, as an {@link Integer} value. The
- * resource id must correspond to a valid drawable resource
- */
- public final void setIcon(@DrawableRes final int resourceId) {
- this.iconId = resourceId;
- this.iconBitmap = null;
- notifyOnIconChanged();
- }
-
- /**
- * Sets the tab's icon.
- *
- * @param icon
- * The icon, which should be set, as an instance of the class {@link Bitmap} or null, if
- * no custom icon should be set
- */
- public final void setIcon(@Nullable final Bitmap icon) {
- this.iconId = -1;
- this.iconBitmap = icon;
- notifyOnIconChanged();
- }
-
- /**
- * Returns the color state list, which is used to tint the tab's icon.
- *
- * @return The color state list, which is used to tint the tab's icon, as an instance of the
- * class {@link ColorStateList} or null, if the icon is not tinted
- */
- public final ColorStateList getIconTintList() {
- return iconTintList;
- }
-
- /**
- * Sets the color, which should be used to tint the tab's icon.
- *
- * @param color
- * The color, which should be set, as an {@link Integer} value
- */
- public final void setIconTint(@ColorInt final int color) {
- setIconTintList(ColorStateList.valueOf(color));
- }
-
- /**
- * Sets the color state list, which should be used to tint the tab's icon.
- *
- * @param tintList
- * The color state list, which should be set, as an instance of the class {@link
- * ColorStateList} or null, if the icon should not be tinted
- */
- public final void setIconTintList(@Nullable final ColorStateList tintList) {
- this.iconTintList = tintList;
- notifyOnIconChanged();
- }
-
- /**
- * Returns the mode, which is used to tint the tab's icon.
- *
- * @return The mode, which is used to tint the tab's icon, as a value of the enum {@link
- * PorterDuff.Mode} or null, if the default mode is used
- */
- public final PorterDuff.Mode getIconTintMode() {
- return iconTintMode;
- }
-
- /**
- * Sets the mode, which should be used to tint the tab's icon.
- *
- * @param mode
- * The mode, which should be set, as a value of enum {@link PorterDuff.Mode} or null, if
- * the default mode should be used
- */
- public final void setIconTintMode(@Nullable final PorterDuff.Mode mode) {
- this.iconTintMode = mode;
- notifyOnIconChanged();
- }
-
- /**
- * Returns, whether the tab is closeable, or not.
- *
- * @return True, if the tab is closeable, false otherwise
- */
- public final boolean isCloseable() {
- return closeable;
- }
-
- /**
- * Sets, whether the tab should be closeable, or not.
- *
- * @param closeable
- * True, if the tab should be closeable, false otherwise
- */
- public final void setCloseable(final boolean closeable) {
- this.closeable = closeable;
- notifyOnCloseableChanged();
- }
-
- /**
- * Returns the icon of the tab's close button.
- *
- * @param context
- * The context, which should be used to retrieve the icon, as an instance of the class
- * {@link Context}. The context may not be null
- * @return The icon of the tab's close button as an instance of the class {@link Drawable} or
- * null, if no custom icon is set
- */
- @Nullable
- public final Drawable getCloseButtonIcon(@NonNull final Context context) {
- Condition.INSTANCE.ensureNotNull(context, "The context may not be null");
-
- if (closeButtonIconId != -1) {
- return AppCompatResources.getDrawable(context, closeButtonIconId);
- } else {
- return closeButtonIconBitmap != null ?
- new BitmapDrawable(context.getResources(), closeButtonIconBitmap) : null;
- }
- }
-
- /**
- * Sets the icon of the tab's close button.
- *
- * @param resourceId
- * The resource id of the icon, which should be set, as an {@link Integer} value. The
- * resource id must correspond to a valid drawable resource
- */
- public final void setCloseButtonIcon(@DrawableRes final int resourceId) {
- this.closeButtonIconId = resourceId;
- this.closeButtonIconBitmap = null;
- notifyOnCloseButtonIconChanged();
- }
-
- /**
- * Sets the icon of the tab's close button.
- *
- * @param icon
- * The icon, which should be set, as an instance of the class {@link Bitmap} or null, if
- * no custom icon should be set
- */
- public final void setCloseButtonIcon(@Nullable final Bitmap icon) {
- this.closeButtonIconId = -1;
- this.closeButtonIconBitmap = icon;
- notifyOnCloseButtonIconChanged();
- }
-
- /**
- * Returns the color state list, which is used to tint the tab's close button.
- *
- * @return The color state list, which is used to tint the tab's close button, as an instance of
- * the class {@link ColorStateList} or null, if the close button is not tinted
- */
- public final ColorStateList getCloseButtonIconTintList() {
- return closeButtonIconTintList;
- }
-
- /**
- * Sets the color, which should be used to tint the tab's close button.
- *
- * @param color
- * The color, which should be set, as an {@link Integer} value
- */
- public final void setCloseButtonIconTint(@ColorInt final int color) {
- setCloseButtonIconTintList(ColorStateList.valueOf(color));
- }
-
- /**
- * Sets the color state list, which should be used to tint the tab's close button.
- *
- * @param tintList
- * The color state list, which should be set, as an instance of the class {@link
- * ColorStateList} or null, if the close button should not be tinted
- */
- public final void setCloseButtonIconTintList(@Nullable final ColorStateList tintList) {
- this.closeButtonIconTintList = tintList;
- notifyOnCloseButtonIconChanged();
- }
-
- /**
- * Returns the mode, which is used to tint the tab's close button.
- *
- * @return The mode, which is used to tint the tab's close button, as a value of the enum {@link
- * PorterDuff.Mode} or null, if the default mode is used
- */
- public final PorterDuff.Mode getCloseButtonIconTintMode() {
- return closeButtonIconTintMode;
- }
-
- /**
- * Sets the mode, which should be used to tint the tab's close button.
- *
- * @param mode
- * The mode, which should be set, as a value of enum {@link PorterDuff.Mode} or null, if
- * the default mode should be used
- */
- public final void setCloseButtonIconTintMode(@Nullable final PorterDuff.Mode mode) {
- this.closeButtonIconTintMode = mode;
- notifyOnCloseButtonIconChanged();
- }
-
- /**
- * Returns the background color of the tab.
- *
- * @return The background color of the tab as an instance of the class {@link ColorStateList} or
- * -1, if no custom color is set
- */
- @Nullable
- public final ColorStateList getBackgroundColor() {
- return backgroundColor;
- }
-
- /**
- * Sets the tab's background color.
- *
- * @param color
- * The color, which should be set, as an {@link Integer} value or -1, if no custom color
- * should be set
- */
- public final void setBackgroundColor(@ColorInt final int color) {
- setBackgroundColor(color != -1 ? ColorStateList.valueOf(color) : null);
- }
-
- /**
- * Sets the tab's background color.
- *
- * @param colorStateList
- * The color state list, which should be set, as an instance of the class {@link
- * ColorStateList} or null, if no custom color should be set
- */
- public final void setBackgroundColor(@Nullable final ColorStateList colorStateList) {
- this.backgroundColor = colorStateList;
- notifyOnBackgroundColorChanged();
- }
-
- /**
- * Returns the background color of the tab's content.
- *
- * @return The background color of the tab's content as an {@link Integer} value or -1, if no
- * custom color is set
- */
- @ColorInt
- public final int getContentBackgroundColor() {
- return contentBackgroundColor;
- }
-
- /**
- * Sets the background color of the tab's content.
- *
- * @param color
- * The color, which should be set, as an {@link Integer} value or -1, if no custom color
- * should be set
- */
- public final void setContentBackgroundColor(@ColorInt final int color) {
- this.contentBackgroundColor = color;
- notifyOnContentBackgroundColorChanged();
- }
-
- /**
- * Returns the text color of the tab's title.
- *
- * @return The text color of the tab's title as an instance of the class {@link ColorStateList}
- * or null, if no custom color is set
- */
- @Nullable
- public final ColorStateList getTitleTextColor() {
- return titleTextColor;
- }
-
- /**
- * Sets the text color of the tab's title.
- *
- * @param color
- * The color, which should be set, as an {@link Integer} value or -1, if no custom color
- * should be set
- */
- public final void setTitleTextColor(@ColorInt final int color) {
- setTitleTextColor(color != -1 ? ColorStateList.valueOf(color) : null);
- }
-
- /**
- * Sets the text color of the tab's title.
- *
- * @param colorStateList
- * The color state list, which should be set, as an instance of the class {@link
- * ColorStateList} or null, if no custom color should be set
- */
- public final void setTitleTextColor(@Nullable final ColorStateList colorStateList) {
- this.titleTextColor = colorStateList;
- notifyOnTitleTextColorChanged();
- }
-
- /**
- * Returns, whether the tab's progress bar is shown, or not.
- *
- * @return True, if the tab's progress bar is shown, false otherwise
- */
- public final boolean isProgressBarShown() {
- return progressBarShown;
- }
-
- /**
- * Sets, whether the tab's progress bar should be shown, or not.
- *
- * @param show
- * True, if the progress bar should be shown, false otherwise
- */
- public final void showProgressBar(final boolean show) {
- this.progressBarShown = show;
- notifyOnProgressBarVisibilityChanged();
- }
-
- /**
- * Returns the color of the tab's progress bar.
- *
- * @return The color of the tab's progress bar as an {@link Integer} value or -1, if the default
- * color should be used
- */
- @ColorInt
- public final int getProgressBarColor() {
- return progressBarColor;
- }
-
- /**
- * Sets the color of the tab's progress bar.
- *
- * @param color
- * The color, which should be set, as an {@link Integer} value or -1, if the default
- * color should be used
- */
- public final void setProgressBarColor(@ColorInt final int color) {
- this.progressBarColor = color;
- notifyOnProgressBarColorChanged();
- }
-
- /**
- * Returns a bundle, which contains the optional parameters, which are associated with the tab.
- *
- * @return A bundle, which contains the optional parameters, which are associated with the tab,
- * as an instance of the class {@link Bundle} or null, if no parameters are associated with the
- * tab
- */
- @Nullable
- public final Bundle getParameters() {
- return parameters;
- }
-
- /**
- * Sets a bundle, which contains the optional parameters, which should be associated with the
- * tab.
- *
- * @param parameters
- * The bundle, which should be set, as an instance of the class {@link Bundle} or null,
- * if no parameters should be associated with the tab
- */
- public final void setParameters(@Nullable final Bundle parameters) {
- this.parameters = parameters;
- }
-
- /**
- * Adds a new callback, which should be notified, when the tab's properties have been changed.
- *
- * @param callback
- * The callback, which should be added, as an instance of the type {@link Callback}. The
- * callback may not be null
- */
- public final void addCallback(@NonNull final Callback callback) {
- Condition.INSTANCE.ensureNotNull(callback, "The callback may not be null");
- this.callbacks.add(callback);
- }
-
- /**
- * Removes a specific callback, which should not be notified, when the tab's properties have
- * been changed, anymore.
- *
- * @param callback
- * The callback, which should be removed, as an instance of the type {@link Callback}.
- * The callback may not be null
- */
- public final void removeCallback(@NonNull final Callback callback) {
- Condition.INSTANCE.ensureNotNull(callback, "The callback may not be null");
- this.callbacks.remove(callback);
- }
-
- @Override
- public final int describeContents() {
- return 0;
- }
-
- @Override
- public final void writeToParcel(final Parcel parcel, final int flags) {
- TextUtils.writeToParcel(title, parcel, flags);
- parcel.writeInt(iconId);
- parcel.writeParcelable(iconBitmap, flags);
- parcel.writeParcelable(iconTintList, flags);
- parcel.writeSerializable(iconTintMode);
- parcel.writeInt(closeable ? 1 : 0);
- parcel.writeInt(closeButtonIconId);
- parcel.writeParcelable(closeButtonIconBitmap, flags);
- parcel.writeParcelable(closeButtonIconTintList, flags);
- parcel.writeSerializable(closeButtonIconTintMode);
- parcel.writeParcelable(backgroundColor, flags);
- parcel.writeInt(contentBackgroundColor);
- parcel.writeParcelable(titleTextColor, flags);
- parcel.writeInt(progressBarShown ? 1 : 0);
- parcel.writeInt(progressBarColor);
- parcel.writeBundle(parameters);
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabCloseListener.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabCloseListener.java
deleted file mode 100644
index c9acdf25..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabCloseListener.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import androidx.annotation.NonNull;
-
-/**
- * Defines the interface, a class, which should be notified, when a tab is about to be closed by
- * clicking its close button, must implement.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public interface TabCloseListener {
-
- /**
- * The method, which is invoked, when a tab is about to be closed by clicking its close button.
- *
- * @param tabSwitcher
- * The tab switcher, the tab belongs to, as an instance of the class {@link
- * TabSwitcher}. The tab switcher may not be null
- * @param tab
- * The tab, which is about to be closed, as an instance of the class {@link Tab}. The
- * tab may not be null
- * @return True, if the tab should be closed, false otherwise
- */
- boolean onCloseTab(@NonNull TabSwitcher tabSwitcher, @NonNull Tab tab);
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabPreviewListener.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabPreviewListener.java
deleted file mode 100644
index 23b73983..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabPreviewListener.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import androidx.annotation.NonNull;
-
-/**
- * Defines the interface, a class, which should be notified, when the preview of a tab is about to
- * be loaded, must implement.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public interface TabPreviewListener {
-
- /**
- * The method, which is invoked, when the preview of a tab is about to be loaded.
- *
- * @param tabSwitcher
- * The tab switcher, which contains the tab, whose preview is about to be loaded, as an
- * instance of the class {@link TabSwitcher}. The tab switcher may not be null
- * @param tab
- * The tab, whose preview is about to be loaded, as an instance of the class {@link
- * Tab}. The tab may not be null
- * @return True, if loading the preview should be proceeded, false otherwise. When returning
- * false, the method gets invoked repeatedly until true is returned.
- */
- boolean onLoadTabPreview(@NonNull TabSwitcher tabSwitcher, @NonNull Tab tab);
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabSwitcher.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabSwitcher.java
deleted file mode 100644
index 042641f8..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabSwitcher.java
+++ /dev/null
@@ -1,2054 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources.NotFoundException;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.widget.FrameLayout;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Queue;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-import androidx.annotation.AttrRes;
-import androidx.annotation.ColorInt;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.LayoutRes;
-import androidx.annotation.MenuRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-import androidx.annotation.StyleRes;
-import androidx.appcompat.content.res.AppCompatResources;
-import androidx.appcompat.widget.Toolbar;
-import androidx.appcompat.widget.Toolbar.OnMenuItemClickListener;
-import androidx.core.util.Pair;
-import androidx.core.view.ViewCompat;
-import de.mrapp.android.tabswitcher.gesture.AbstractTouchEventHandler;
-import de.mrapp.android.tabswitcher.gesture.DragGestureEventHandlerFactory;
-import de.mrapp.android.tabswitcher.gesture.TouchEventDispatcher;
-import de.mrapp.android.tabswitcher.layout.AbstractTabSwitcherLayout;
-import de.mrapp.android.tabswitcher.layout.AbstractTabSwitcherLayout.LayoutListenerWrapper;
-import de.mrapp.android.tabswitcher.layout.ContentRecyclerAdapter;
-import de.mrapp.android.tabswitcher.layout.TabSwitcherLayout;
-import de.mrapp.android.tabswitcher.layout.phone.PhoneArithmetics;
-import de.mrapp.android.tabswitcher.layout.phone.PhoneTabSwitcherLayout;
-import de.mrapp.android.tabswitcher.model.Model;
-import de.mrapp.android.tabswitcher.model.TabSwitcherModel;
-import de.mrapp.android.tabswitcher.model.TabSwitcherStyle;
-import de.mrapp.android.tabswitcher.util.ThemeHelper;
-import de.mrapp.android.tabswitcher.view.TabSwitcherButton;
-import de.mrapp.android.util.DisplayUtil.Orientation;
-import de.mrapp.android.util.ViewUtil;
-import de.mrapp.android.util.logging.LogLevel;
-import de.mrapp.android.util.view.AbstractSavedState;
-import de.mrapp.android.util.view.AbstractViewRecycler;
-import de.mrapp.util.Condition;
-
-import static de.mrapp.android.util.DisplayUtil.getOrientation;
-
-/**
- * A tab switcher, which allows to switch between multiple tabs. It it is designed similar to the
- * tab switcher of the Google Chrome Android app.
- *
- * In order to specify the appearance of individual tabs, a class, which extends from the abstract
- * class {@link TabSwitcherDecorator}, must be implemented and set to the tab switcher via the
- * setDecorator
-method.
- *
- * The currently selected tab is shown fullscreen by default. When displaying the switcher via the
- * showSwitcher-method
, an overview of all tabs is shown, allowing to select an other
- * tab by clicking it. By swiping a tab or by clicking its close button, it can be removed,
- * resulting in the selected tab to be altered automatically. The switcher can programmatically be
- * hidden by calling the hideSwitcher
-method. By calling the
- * setSelectedTab
-method programmatically, a tab is selected and shown fullscreen.
- *
- * Individual tabs are represented by instances of the class {@link Tab}. Such tabs can dynamically
- * be added to the tab switcher by using the addTab
-methods. In order to remove them
- * afterwards, the removeTab
can be used. If the switcher is currently shown, calling
- * these methods results in the tabs being added or removed in an animated manner.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class TabSwitcher extends FrameLayout implements TabSwitcherLayout, Model {
-
- /**
- * A saved state, which allows to store the state of a {@link TabSwitcher}.
- */
- private static class TabSwitcherState extends AbstractSavedState {
-
- /**
- * A creator, which allows to create instances of the class {@link TabSwitcherState}.
- */
- public static Creator CREATOR = new Creator() {
-
- @Override
- public TabSwitcherState createFromParcel(final Parcel source) {
- return new TabSwitcherState(source);
- }
-
- @Override
- public TabSwitcherState[] newArray(final int size) {
- return new TabSwitcherState[size];
- }
-
- };
-
- /**
- * The saved layout policy, which is used by the tab switcher.
- */
- private LayoutPolicy layoutPolicy;
-
- /**
- * The saved state of the model, which is used by the tab switcher.
- */
- private Bundle modelState;
-
- /**
- * Creates a new saved state, which allows to store the state of a {@link TabSwitcher}.
- *
- * @param source
- * The parcel to read read from as a instance of the class {@link Parcel}. The
- * parcel may not be null
- */
- private TabSwitcherState(@NonNull final Parcel source) {
- super(source);
- layoutPolicy = (LayoutPolicy) source.readSerializable();
- modelState = source.readBundle(getClass().getClassLoader());
- }
-
- /**
- * Creates a new saved state, which allows to store the state of a {@link TabSwitcher}.
- *
- * @param superState
- * The state of the superclass of the view, this saved state corresponds to, as an
- * instance of the type {@link Parcelable} or null if no state is available
- */
- TabSwitcherState(@Nullable final Parcelable superState) {
- super(superState);
- }
-
- @Override
- public void writeToParcel(final Parcel dest, final int flags) {
- super.writeToParcel(dest, flags);
- dest.writeSerializable(layoutPolicy);
- dest.writeBundle(modelState);
- }
-
- }
-
- /**
- * The index of the primary toolbar as returned by the method {@link
- * TabSwitcher#getToolbars()}.
- */
- public static final int PRIMARY_TOOLBAR_INDEX = 0;
-
- /**
- * The index of the secondary toolbar as returned by the method {@link
- * TabSwitcher#getToolbars()}.
- */
- public static final int SECONDARY_TOOLBAR_INDEX = 1;
-
- /**
- * A queue, which contains all pending actions.
- */
- private Queue pendingActions;
-
- /**
- * A set, which contains the listeners, which should be notified about the tab switcher's
- * events.
- */
- private Set listeners;
-
- /**
- * The layout policy, which is used by the tab switcher.
- */
- private LayoutPolicy layoutPolicy;
-
- /**
- * The model, which is used by the tab switcher.
- */
- private TabSwitcherModel model;
-
- /**
- * The style, which allows to retrieve the style attributes of the tab switcher.
- */
- private TabSwitcherStyle style;
-
- /**
- * The theme helper, which allows to retrieve resources, depending on the tab switcher's theme.
- */
- private ThemeHelper themeHelper;
-
- /**
- * The dispatcher, which is used to dispatch touch events.
- */
- private TouchEventDispatcher touchEventDispatcher;
-
- /**
- * The layout, which is used by the tab switcher, depending on whether the device is a
- * smartphone or tablet and the set layout policy.
- */
- private AbstractTabSwitcherLayout layout;
-
- /**
- * Whether to preserve the tab switcher's state, or not.
- */
- private boolean preserveState = true;
-
- /**
- * Initializes the view.
- *
- * @param attributeSet
- * The attribute set, which should be used to initialize the view, as an instance of the
- * type {@link AttributeSet} or null, if no attributes should be obtained
- * @param defaultStyle
- * The default style to apply to this view. If 0, no style will be applied (beyond what
- * is included in the theme). This may either be an attribute resource, whose value will
- * be retrieved from the current theme, or an explicit style resource
- * @param defaultStyleResource
- * A resource identifier of a style resource that supplies default values for the view,
- * used only if the default style is 0 or can not be found in the theme. Can be 0 to not
- * look for defaults
- */
- private void initialize(@Nullable final AttributeSet attributeSet,
- @AttrRes final int defaultStyle,
- @StyleRes final int defaultStyleResource) {
- pendingActions = new LinkedList<>();
- listeners = new CopyOnWriteArraySet<>();
- model = new TabSwitcherModel(this);
- model.addListener(createModelListener());
- touchEventDispatcher = new TouchEventDispatcher();
- setPadding(super.getPaddingLeft(), super.getPaddingTop(), super.getPaddingRight(),
- super.getPaddingBottom());
- obtainStyledAttributes(attributeSet, defaultStyle, defaultStyleResource);
- getViewTreeObserver().addOnGlobalLayoutListener(
- new LayoutListenerWrapper(this, createGlobalLayoutListener(false)));
- }
-
- /**
- * Initializes a specific layout.
- *
- * @param inflatedTabsOnly
- * True, if only the tabs should be inflated, false otherwise
- * @param layout
- * The layout, which should be initialized, as a value of the enum {@link Layout}. The
- * layout may not be null
- */
- private void initializeLayout(@NonNull final Layout layout, final boolean inflatedTabsOnly) {
- if (layout == Layout.TABLET) {
- // TODO: Use tablet layout once implemented
- this.layout = new PhoneTabSwitcherLayout(TabSwitcher.this, model,
- new PhoneArithmetics(TabSwitcher.this), style, touchEventDispatcher);
- } else {
- this.layout = new PhoneTabSwitcherLayout(TabSwitcher.this, model,
- new PhoneArithmetics(TabSwitcher.this), style, touchEventDispatcher);
- }
-
- this.layout.setCallback(createLayoutCallback());
- this.model.addListener(this.layout);
- this.layout.inflateLayout(inflatedTabsOnly);
- this.touchEventDispatcher.addEventHandler(this.layout.getDragHandler());
- final ViewGroup tabContainer = getTabContainer();
- assert tabContainer != null;
-
- if (ViewCompat.isLaidOut(tabContainer)) {
- this.layout.onGlobalLayout();
- } else {
- tabContainer.getViewTreeObserver()
- .addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
-
- @Override
- public void onGlobalLayout() {
- ViewUtil.removeOnGlobalLayoutListener(
- tabContainer.getViewTreeObserver(), this);
- TabSwitcher.this.layout.onGlobalLayout();
- }
-
- });
- }
- }
-
- /**
- * Obtains all attributes from a specific attribute set.
- *
- * @param attributeSet
- * The attribute set, the attributes should be obtained from, as an instance of the type
- * {@link AttributeSet} or null, if no attributes should be obtained
- * @param defaultStyle
- * The default style to apply to this view. If 0, no style will be applied (beyond what
- * is included in the theme). This may either be an attribute resource, whose value will
- * be retrieved from the current theme, or an explicit style resource
- * @param defaultStyleResource
- * A resource identifier of a style resource that supplies default values for the view,
- * used only if the default style is 0 or can not be found in the theme. Can be 0 to not
- * look for defaults
- */
- private void obtainStyledAttributes(@Nullable final AttributeSet attributeSet,
- @AttrRes final int defaultStyle,
- @StyleRes final int defaultStyleResource) {
- TypedArray typedArray = getContext()
- .obtainStyledAttributes(attributeSet, R.styleable.TabSwitcher, defaultStyle,
- defaultStyleResource);
-
- try {
- int globalTheme = typedArray.getResourceId(R.styleable.TabSwitcher_themeGlobal, 0);
- int phoneTheme = typedArray.getResourceId(R.styleable.TabSwitcher_themePhone, 0);
- int tabletTheme = typedArray.getResourceId(R.styleable.TabSwitcher_themeTablet, 0);
- themeHelper = new ThemeHelper(getContext(), globalTheme, phoneTheme, tabletTheme);
- style = new TabSwitcherStyle(this, model, themeHelper);
- obtainPreserveState(typedArray);
- obtainLayoutPolicy(typedArray);
- obtainBackground(typedArray);
- obtainTabIcon(typedArray);
- obtainTabIconTint(typedArray);
- obtainTabBackgroundColor(typedArray);
- obtainTabContentBackgroundColor(typedArray);
- obtainAddTabButtonColor(typedArray);
- obtainTabTitleTextColor(typedArray);
- obtainTabCloseButtonIcon(typedArray);
- obtainTabCloseButtonIconTint(typedArray);
- obtainShowToolbars(typedArray);
- obtainToolbarTitle(typedArray);
- obtainToolbarNavigationIcon(typedArray);
- obtainToolbarNavigationIconTint(typedArray);
- obtainToolbarMenu(typedArray);
- obtainTabPreviewFadeThreshold(typedArray);
- obtainTabPreviewFadeDuration(typedArray);
- obtainEmptyView(typedArray);
- } finally {
- typedArray.recycle();
- }
- }
-
- /**
- * Obtains whether the tab switcher's state should be preserved, or not, from a specific typed
- * array.
- *
- * @param typedArray
- * The typed array, it should be obtained from, whether the tab switcher's state should
- * be preserved, as an instance of the class {@link TypedArray}. The typed array may not
- * be null
- */
- private void obtainPreserveState(@NonNull final TypedArray typedArray) {
- setPreserveState(typedArray.getBoolean(R.styleable.TabSwitcher_preserveState, false));
- }
-
- /**
- * Obtains the layout policy from a specific typed array.
- *
- * @param typedArray
- * The typed array, the layout policy should be obtained from, as an instance of the
- * class {@link TypedArray}. The typed array may not be null
- */
- private void obtainLayoutPolicy(@NonNull final TypedArray typedArray) {
- int value = typedArray.getInt(R.styleable.TabSwitcher_layoutPolicy, 0);
-
- if (value == 0) {
- value = themeHelper.getInteger(getLayout(), R.attr.tabSwitcherLayoutPolicy, 0);
- }
-
- setLayoutPolicy(LayoutPolicy.fromValue(value));
- }
-
- /**
- * Obtains the view's background from a specific typed array.
- *
- * @param typedArray
- * The typed array, the background should be obtained from, as an instance of the class
- * {@link TypedArray}. The typed array may not be null
- */
- private void obtainBackground(@NonNull final TypedArray typedArray) {
- Drawable background = typedArray.getDrawable(R.styleable.TabSwitcher_android_background);
-
- if (background == null) {
- try {
- background = themeHelper.getDrawable(getLayout(), R.attr.tabSwitcherBackground);
- } catch (NotFoundException e) {
- // There's nothing we can do
- }
- }
-
- if (background != null) {
- ViewUtil.setBackground(this, background);
- }
- }
-
- /**
- * Obtains the icon of a tab from a specific typed array.
- *
- * @param typedArray
- * The typed array, the icon should be obtained from, as an instance of the class {@link
- * TypedArray}. The typed array may not be null
- */
- private void obtainTabIcon(@NonNull final TypedArray typedArray) {
- int resourceId = typedArray.getResourceId(R.styleable.TabSwitcher_tabIcon, 0);
-
- if (resourceId != 0) {
- setTabIcon(resourceId);
- }
- }
-
- /**
- * Obtains the color state list, which should be used to tint the icon of a tab, from a specific
- * typed array.
- *
- * @param typedArray
- * The typed array, the color state list should be obtained from, as an instance of the
- * class {@link TypedArray}. The typed array may not be null
- */
- private void obtainTabIconTint(@NonNull final TypedArray typedArray) {
- setTabIconTintList(typedArray.getColorStateList(R.styleable.TabSwitcher_tabIconTint));
- }
-
- /**
- * Obtains the background color of a tab from a specific typed array.
- *
- * @param typedArray
- * The typed array, the background color should be obtained from, as an instance of the
- * class {@link TypedArray}. The typed array may not be null
- */
- private void obtainTabBackgroundColor(@NonNull final TypedArray typedArray) {
- setTabBackgroundColor(
- typedArray.getColorStateList(R.styleable.TabSwitcher_tabBackgroundColor));
- }
-
- /**
- * Obtains the background color of a tab's content from a specific typed array.
- *
- * @param typedArray
- * The typed array, the background color should be obtained from, as an instance of the
- * class {@link TypedArray}. The typed array may not be null
- */
- private void obtainTabContentBackgroundColor(@NonNull final TypedArray typedArray) {
- setTabContentBackgroundColor(
- typedArray.getColor(R.styleable.TabSwitcher_tabContentBackgroundColor, -1));
- }
-
- /**
- * Obtains the background color of the button, which allows to add a new tab, from a specific
- * typed array.
- *
- * @param typedArray
- * The typed array, the color should be obtained from, as an instance of the class
- * {@link TypedArray}. The typed array may not be null
- */
- private void obtainAddTabButtonColor(@NonNull final TypedArray typedArray) {
- setAddTabButtonColor(
- typedArray.getColorStateList(R.styleable.TabSwitcher_addTabButtonColor));
- }
-
- /**
- * Obtains the text color of a tab's title from a specific typed array.
- *
- * @param typedArray
- * The typed array, the text color should be obtained from, as an instance of the class
- * {@link TypedArray}. The typed array may not be null
- */
- private void obtainTabTitleTextColor(@NonNull final TypedArray typedArray) {
- setTabTitleTextColor(
- typedArray.getColorStateList(R.styleable.TabSwitcher_tabTitleTextColor));
- }
-
- /**
- * Obtains the icon of a tab's close button from a specific typed array.
- *
- * @param typedArray
- * The typed array, the icon should be obtained from, as an instance of the class {@link
- * TypedArray}. The typed array may not be null
- */
- private void obtainTabCloseButtonIcon(@NonNull final TypedArray typedArray) {
- int resourceId = typedArray.getResourceId(R.styleable.TabSwitcher_tabCloseButtonIcon, 0);
-
- if (resourceId != 0) {
- setTabCloseButtonIcon(resourceId);
- }
- }
-
- /**
- * Obtains the color state list, which should be used to tint the close button of a tab, from a
- * specific typed array.
- *
- * @param typedArray
- * The typed array, the color state list should be obtained from, as an instance of the
- * class {@link TypedArray}. The typed array may not be null
- */
- private void obtainTabCloseButtonIconTint(@NonNull final TypedArray typedArray) {
- setTabIconTintList(
- typedArray.getColorStateList(R.styleable.TabSwitcher_tabCloseButtonIconTint));
- }
-
- /**
- * Obtains, whether the tab switcher's toolbars should be shown, or not, from a specific typed
- * array.
- *
- * @param typedArray
- * The typed array, it should be obtained from, whether the toolbars should be shown, as
- * an instance of the class {@link TypedArray}. The typed array may not be null
- */
- private void obtainShowToolbars(@NonNull final TypedArray typedArray) {
- showToolbars(typedArray.getBoolean(R.styleable.TabSwitcher_showToolbars, false));
- }
-
- /**
- * Obtains the title of the toolbar, which is shown, when the tab switcher is shown, from a
- * specific typed array.
- *
- * @param typedArray
- * The typed array, the title should be obtained from, as an instance of the class
- * {@link TypedArray}. The typed array may not be null
- */
- private void obtainToolbarTitle(@NonNull final TypedArray typedArray) {
- setToolbarTitle(typedArray.getText(R.styleable.TabSwitcher_toolbarTitle));
- }
-
- /**
- * Obtains the navigation icon of the toolbar, which is shown, when the tab switcher is shown,
- * from a specific typed array.
- *
- * @param typedArray
- * The typed array, the navigation icon should be obtained from, as an instance of the
- * class {@link TypedArray}. The typed array may not be null
- */
- private void obtainToolbarNavigationIcon(@NonNull final TypedArray typedArray) {
- int resourceId =
- typedArray.getResourceId(R.styleable.TabSwitcher_toolbarNavigationIcon, -1);
- Drawable navigationIcon = null;
-
- if (resourceId != -1) {
- navigationIcon = AppCompatResources.getDrawable(getContext(), resourceId);
- }
-
- setToolbarNavigationIcon(navigationIcon, null);
- }
-
- /**
- * Obtains the color state list, which should be used to tint the navigation icon of the
- * toolbar, which is shown, when the tab switcher is shown, from a specific typed array.
- *
- * @param typedArray
- * The typed array, the color state list should be obtained from, as an instance of the
- * class {@link TypedArray}. The typed array may not be null
- */
- private void obtainToolbarNavigationIconTint(@NonNull final TypedArray typedArray) {
- setToolbarNavigationIconTintList(
- typedArray.getColorStateList(R.styleable.TabSwitcher_toolbarNavigationIconTint));
- }
-
- /**
- * Obtains the menu of the toolbar, which is shown, when the tab switcher is shown, from a
- * specific typed array.
- *
- * @param typedArray
- * The typed array, the menu should be obtained from, as an instance of the class {@link
- * TypedArray}. The typed array may not be null
- */
- private void obtainToolbarMenu(@NonNull final TypedArray typedArray) {
- int resourceId = typedArray.getResourceId(R.styleable.TabSwitcher_toolbarMenu, 0);
-
- if (resourceId == 0) {
- resourceId = themeHelper.getResourceId(getLayout(), R.attr.tabSwitcherToolbarMenu, 0);
- }
-
- if (resourceId != 0) {
- inflateToolbarMenu(resourceId, null);
- }
- }
-
- /**
- * Obtains the duration, which must be reached when loading the preview of tabs to use a fade
- * duration, from a specific typed array.
- *
- * @param typedArray
- * The typed array, the duration should be obtained from, as an instance of the class
- * {@link TypedArray}. The typed array may not be null
- */
- private void obtainTabPreviewFadeThreshold(@NonNull final TypedArray typedArray) {
- int threshold = typedArray.getInteger(R.styleable.TabSwitcher_tabPreviewFadeThreshold, -1);
-
- if (threshold == -1) {
- threshold = themeHelper
- .getInteger(getLayout(), R.attr.tabSwitcherTabToolbarPreviewFadeThreshold, -1);
- }
-
- if (threshold != -1) {
- setTabPreviewFadeThreshold(threshold);
- }
- }
-
- /**
- * Sets the duration of the fade animation, which is used to show the previews of tabs.
- *
- * @param typedArray
- * The typed array, the duration should be obtained from, as an instance of the class
- * {@link TypedArray}. The typed array may not be null
- */
- private void obtainTabPreviewFadeDuration(@NonNull final TypedArray typedArray) {
- int duration = typedArray.getInteger(R.styleable.TabSwitcher_tabPreviewFadeDuration, -1);
-
- if (duration == -1) {
- duration = themeHelper
- .getInteger(getLayout(), R.attr.tabSwitcherTabToolbarPreviewFadeDuration, -1);
- }
-
- if (duration != -1) {
- setTabPreviewFadeDuration(duration);
- }
- }
-
- /**
- * Obtains the view, which should be shown, when the tab switcher is empty, from a specific
- * typed array.
- *
- * @param typedArray
- * The typed array, trhe view should be obtained from, as an instance of the class
- * {@link TypedArray}. The typed array may not be null
- */
- private void obtainEmptyView(@NonNull final TypedArray typedArray) {
- int resourceId = typedArray.getResourceId(R.styleable.TabSwitcher_emptyView, 0);
-
- if (resourceId == 0) {
- resourceId = themeHelper.getResourceId(getLayout(), R.attr.tabSwitcherEmptyView, 0);
- }
-
- if (resourceId != 0) {
- long animationDuration =
- typedArray.getInteger(R.styleable.TabSwitcher_emptyViewAnimationDuration, -2);
-
- if (animationDuration < -1) {
- animationDuration = themeHelper
- .getInteger(getLayout(), R.attr.tabSwitcherEmptyViewAnimationDuration, -1);
- }
-
- setEmptyView(resourceId, animationDuration);
- }
- }
-
- /**
- * Enqueues a specific action to be executed, when no animation is running.
- *
- * @param action
- * The action, which should be enqueued as an instance of the type {@link Runnable}. The
- * action may not be null
- */
- private void enqueuePendingAction(@NonNull final Runnable action) {
- Condition.INSTANCE.ensureNotNull(action, "The action may not be null");
- pendingActions.add(action);
- executePendingAction();
- }
-
- /**
- * Executes the next pending action.
- */
- private void executePendingAction() {
- if (!isAnimationRunning()) {
- final Runnable action = pendingActions.poll();
-
- if (action != null) {
- new Runnable() {
-
- @Override
- public void run() {
- action.run();
- executePendingAction();
- }
-
- }.run();
- }
- }
- }
-
- /**
- * Creates and returns a listener, which allows to observe, when the tab switcher's model is
- * modified.
- *
- * @return The listener, which has been created, as an instance of the type {@link
- * Model.Listener}. The listener may not be null
- */
- @NonNull
- private Model.Listener createModelListener() {
- return new Model.Listener() {
-
- @Override
- public void onLogLevelChanged(@NonNull final LogLevel logLevel) {
-
- }
-
- @Override
- public void onDecoratorChanged(@NonNull final TabSwitcherDecorator decorator) {
-
- }
-
- @Override
- public void onSwitcherShown() {
- notifyOnSwitcherShown();
- }
-
- @Override
- public void onSwitcherHidden() {
- notifyOnSwitcherHidden();
- }
-
- @Override
- public void onSelectionChanged(final int previousIndex, final int index,
- @Nullable final Tab selectedTab,
- final boolean switcherHidden) {
- notifyOnSelectionChanged(index, selectedTab);
-
- if (switcherHidden) {
- notifyOnSwitcherHidden();
- }
- }
-
- @Override
- public void onTabAdded(final int index, @NonNull final Tab tab,
- final int previousSelectedTabIndex, final int selectedTabIndex,
- final boolean selectionChanged,
- final boolean switcherVisibilityChanged,
- @NonNull final Animation animation) {
- notifyOnTabAdded(index, tab, animation);
-
- if (selectionChanged) {
- notifyOnSelectionChanged(selectedTabIndex,
- selectedTabIndex != -1 ? getTab(selectedTabIndex) : null);
- }
-
- if (switcherVisibilityChanged) {
- notifyOnSwitcherHidden();
- }
- }
-
- @Override
- public void onAllTabsAdded(final int index, @NonNull final Tab[] tabs,
- final int previousSelectedTabIndex,
- final int selectedTabIndex, final boolean selectionChanged,
- @NonNull final Animation animation) {
- for (Tab tab : tabs) {
- notifyOnTabAdded(index, tab, animation);
- }
-
- if (selectionChanged) {
- notifyOnSelectionChanged(selectedTabIndex,
- selectedTabIndex != -1 ? getTab(selectedTabIndex) : null);
- }
- }
-
- @Override
- public void onTabRemoved(final int index, @NonNull final Tab tab,
- final int previousSelectedTabIndex, final int selectedTabIndex,
- final boolean selectionChanged,
- @NonNull final Animation animation) {
- notifyOnTabRemoved(index, tab, animation);
-
- if (selectionChanged) {
- notifyOnSelectionChanged(selectedTabIndex,
- selectedTabIndex != -1 ? getTab(selectedTabIndex) : null);
- }
- }
-
- @Override
- public void onAllTabsRemoved(@NonNull final Tab[] tabs,
- @NonNull final Animation animation) {
- notifyOnAllTabsRemoved(tabs, animation);
- notifyOnSelectionChanged(-1, null);
- }
-
- @Override
- public void onPaddingChanged(final int left, final int top, final int right,
- final int bottom) {
-
- }
-
- @Override
- public void onApplyPaddingToTabsChanged(final boolean applyPaddingToTabs) {
-
- }
-
- @Override
- public void onTabIconChanged(@Nullable final Drawable icon) {
-
- }
-
- @Override
- public void onTabBackgroundColorChanged(@Nullable final ColorStateList colorStateList) {
-
- }
-
- @Override
- public void onTabContentBackgroundColorChanged(@ColorInt final int color) {
-
- }
-
- @Override
- public void onTabTitleColorChanged(@Nullable final ColorStateList colorStateList) {
-
- }
-
- @Override
- public void onTabCloseButtonIconChanged(@Nullable final Drawable icon) {
-
- }
-
- @Override
- public void onTabProgressBarColorChanged(@ColorInt final int color) {
-
- }
-
- @Override
- public void onAddTabButtonVisibilityChanged(final boolean visible) {
-
- }
-
- @Override
- public void onAddTabButtonColorChanged(@Nullable final ColorStateList colorStateList) {
-
- }
-
- @Override
- public void onToolbarVisibilityChanged(final boolean visible) {
-
- }
-
- @Override
- public void onToolbarTitleChanged(@Nullable final CharSequence title) {
-
- }
-
- @Override
- public void onToolbarNavigationIconChanged(@Nullable final Drawable icon,
- @Nullable final OnClickListener listener) {
-
- }
-
- @Override
- public void onToolbarMenuInflated(@MenuRes final int resourceId,
- @Nullable final OnMenuItemClickListener listener) {
-
- }
-
- @Override
- public void onEmptyViewChanged(@Nullable final View view,
- final long animationDuration) {
-
- }
-
- };
- }
-
- /**
- * Creates and returns a callback, which allows to observe, when all pending animations of a
- * layout have been ended.
- *
- * @return The callback, which has been created, as an instance of the type {@link
- * AbstractTabSwitcherLayout.Callback}. The callback may not be null
- */
- @NonNull
- private AbstractTabSwitcherLayout.Callback createLayoutCallback() {
- return new AbstractTabSwitcherLayout.Callback() {
-
- @Override
- public void onAnimationsEnded() {
- executePendingAction();
- }
-
- };
- }
-
- /**
- * Creates and returns a listener, which allows to inflate the view's layout once the view is
- * laid out.
- *
- * @param inflateTabsOnly
- * True, if only the tabs should be inflated, false otherwise
- * @return The listener, which has been created, as an instance of the type {@link
- * OnGlobalLayoutListener}. The listener may not be null
- */
- @NonNull
- private OnGlobalLayoutListener createGlobalLayoutListener(final boolean inflateTabsOnly) {
- return new OnGlobalLayoutListener() {
-
- @Override
- public void onGlobalLayout() {
- Condition.INSTANCE.ensureNotNull(getDecorator(), "No decorator has been set",
- IllegalStateException.class);
- initializeLayout(getLayout(), inflateTabsOnly);
- }
-
- };
- }
-
- /**
- * Notifies all listeners, that the tab switcher has been shown.
- */
- private void notifyOnSwitcherShown() {
- for (TabSwitcherListener listener : listeners) {
- listener.onSwitcherShown(this);
- }
- }
-
- /**
- * Notifies all listeners, that the tab switcher has been hidden.
- */
- private void notifyOnSwitcherHidden() {
- for (TabSwitcherListener listener : listeners) {
- listener.onSwitcherHidden(this);
- }
- }
-
- /**
- * Notifies all listeners, that the selected tab has been changed.
- *
- * @param selectedTabIndex
- * The index of the currently selected tab as an {@link Integer} value or -1, if no tab
- * is currently selected
- * @param selectedTab
- * The currently selected tab as an instance of the class {@link Tab} or null, if no
- * tab is currently selected
- */
- private void notifyOnSelectionChanged(final int selectedTabIndex,
- @Nullable final Tab selectedTab) {
- for (TabSwitcherListener listener : listeners) {
- listener.onSelectionChanged(this, selectedTabIndex, selectedTab);
- }
- }
-
- /**
- * Notifies all listeners, that a specific tab has been added to the tab switcher.
- *
- * @param index
- * The index of the tab, which has been added, as an {@link Integer} value
- * @param tab
- * The tab, which has been added, as an instance of the class {@link Tab}. The tab may
- * not be null
- * @param animation
- * The animation, which has been used to add the tab, as an instance of the class {@link
- * Animation}. The animation may not be null
- */
- private void notifyOnTabAdded(final int index, @NonNull final Tab tab,
- @NonNull final Animation animation) {
- for (TabSwitcherListener listener : listeners) {
- listener.onTabAdded(this, index, tab, animation);
- }
- }
-
- /**
- * Notifies all listeners, that a specific tab has been removed from the tab switcher.
- *
- * @param index
- * The index of the tab, which has been removed, as an {@link Integer} value
- * @param tab
- * The tab, which has been removed, as an instance of the class {@link Tab}. The tab may
- * not be null
- * @param animation
- * The animation, which has been used to remove the tab, as an instance of the class
- * {@link Animation}. The animation may not be null
- */
- private void notifyOnTabRemoved(final int index, @NonNull final Tab tab,
- @NonNull final Animation animation) {
- for (TabSwitcherListener listener : listeners) {
- listener.onTabRemoved(this, index, tab, animation);
- }
- }
-
- /**
- * Notifies all listeners, that all tabs have been removed from the tab switcher.
- *
- * @param tabs
- * An array, which contains the tabs, which have been removed, as an array of the type
- * {@link Tab} or an empty array, if no tabs have been removed
- * @param animation
- * The animation, which has been used to remove the tabs, as an instance of the class
- * {@link Animation}. The animation may not be null
- */
- private void notifyOnAllTabsRemoved(@NonNull final Tab[] tabs,
- @NonNull final Animation animation) {
- for (TabSwitcherListener listener : listeners) {
- listener.onAllTabsRemoved(this, tabs, animation);
- }
- }
-
- /**
- * Creates a new tab switcher, which allows to switch between multiple tabs.
- *
- * @param context
- * The context, which should be used by the view, as an instance of the class {@link
- * Context}. The context may not be null
- */
- public TabSwitcher(@NonNull final Context context) {
- this(context, null);
- }
-
- /**
- * Creates a new tab switcher, which allows to switch between multiple tabs.
- *
- * @param context
- * The context, which should be used by the view, as an instance of the class {@link
- * Context}. The context may not be null
- * @param attributeSet
- * The attribute set, the view's attributes should be obtained from, as an instance of
- * the type {@link AttributeSet} or null, if no attributes should be obtained
- */
- public TabSwitcher(@NonNull final Context context, @Nullable final AttributeSet attributeSet) {
- super(context, attributeSet);
- initialize(attributeSet, 0, 0);
- }
-
- /**
- * Creates a new tab switcher, which allows to switch between multiple tabs.
- *
- * @param context
- * The context, which should be used by the view, as an instance of the class {@link
- * Context}. The context may not be null
- * @param attributeSet
- * The attribute set, the view's attributes should be obtained from, as an instance of
- * the type {@link AttributeSet} or null, if no attributes should be obtained
- * @param defaultStyle
- * The default style to apply to this view. If 0, no style will be applied (beyond what
- * is included in the theme). This may either be an attribute resource, whose value will
- * be retrieved from the current theme, or an explicit style resource
- */
- public TabSwitcher(@NonNull final Context context, @Nullable final AttributeSet attributeSet,
- @AttrRes final int defaultStyle) {
- super(context, attributeSet, defaultStyle);
- initialize(attributeSet, defaultStyle, 0);
- }
-
- /**
- * Creates a new tab switcher, which allows to switch between multiple tabs.
- *
- * @param context
- * The context, which should be used by the view, as an instance of the class {@link
- * Context}. The context may not be null
- * @param attributeSet
- * The attribute set, the view's attributes should be obtained from, as an instance of
- * the type {@link AttributeSet} or null, if no attributes should be obtained
- * @param defaultStyle
- * The default style to apply to this view. If 0, no style will be applied (beyond what
- * is included in the theme). This may either be an attribute resource, whose value will
- * be retrieved from the current theme, or an explicit style resource
- * @param defaultStyleResource
- * A resource identifier of a style resource that supplies default values for the view,
- * used only if the default style is 0 or can not be found in the theme. Can be 0 to not
- * look for defaults
- */
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public TabSwitcher(@NonNull final Context context, @Nullable final AttributeSet attributeSet,
- @AttrRes final int defaultStyle, @StyleRes final int defaultStyleResource) {
- super(context, attributeSet, defaultStyle, defaultStyleResource);
- initialize(attributeSet, defaultStyle, defaultStyleResource);
- }
-
- /**
- * Setups the tab switcher to be associated with those menu items of its own toolbar menu, which
- * use a {@link TabSwitcherButton} as their action view. The icon of such menu items will
- * automatically be updated, when the number of tabs, which are contained by the tab switcher,
- * changes.
- *
- * Calling this method is basically the same as calling setupWithMenu(tabSwitcher,
- * tabSwitcher.getToolbarMenu(), listener)
. However, if the {@link Menu}, which is
- * returned by tabSwitcher.getToolbarMenu()
is null, a {@link
- * OnGlobalLayoutListener} is registered at the given tab switcher to setup the tab switcher as
- * soon as the menu is initialized.
- *
- * @param tabSwitcher
- * The tab switcher, which should become associated with the menu items, as an instance
- * of the class {@link TabSwitcher}. The tab switcher may not be null
- * @param listener
- * The listener, which should be set to the menu items, which use a {@link
- * TabSwitcherButton} as their action view, as an instance of the type {@link
- * OnClickListener} or null, if no listener should be set
- */
- public static void setupWithMenu(@NonNull final TabSwitcher tabSwitcher,
- @Nullable final OnClickListener listener) {
- Condition.INSTANCE.ensureNotNull(tabSwitcher, "The tab switcher may not be null");
- Menu menu = tabSwitcher.getToolbarMenu();
-
- if (menu != null) {
- setupWithMenu(tabSwitcher, menu, listener);
- } else {
- tabSwitcher.getViewTreeObserver()
- .addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
-
- @Override
- public void onGlobalLayout() {
- ViewUtil.removeOnGlobalLayoutListener(tabSwitcher.getViewTreeObserver(),
- this);
- Menu menu = tabSwitcher.getToolbarMenu();
-
- if (menu != null) {
- TabSwitcher.setupWithMenu(tabSwitcher, menu, listener);
- }
- }
-
- });
- }
- }
-
- /**
- * Setups the tab switcher to be associated with those menu items of a specific menu, which use
- * a {@link TabSwitcherButton} as their action view. The icon of such menu items will
- * automatically be updated, when the number of tabs, which are contained by the tab switcher,
- * changes.
- *
- * @param tabSwitcher
- * The tab switcher, which should become associated with the menu items, as an instance
- * of the class {@link TabSwitcher}. The tab switcher may not be null
- * @param menu
- * The menu, whose menu items should become associated with the given tab switcher, as
- * an instance of the type {@link Menu}. The menu may not be null
- * @param listener
- * The listener, which should be set to the menu items, which use a {@link
- * TabSwitcherButton} as their action view, as an instance of the type {@link
- * OnClickListener} or null, if no listener should be set
- */
- public static void setupWithMenu(@NonNull final TabSwitcher tabSwitcher,
- @NonNull final Menu menu,
- @Nullable final OnClickListener listener) {
- Condition.INSTANCE.ensureNotNull(tabSwitcher, "The tab switcher may not be null");
- Condition.INSTANCE.ensureNotNull(menu, "The menu may not be null");
-
- for (int i = 0; i < menu.size(); i++) {
- MenuItem menuItem = menu.getItem(i);
- View view = menuItem.getActionView();
-
- if (view instanceof TabSwitcherButton) {
- TabSwitcherButton tabSwitcherButton = (TabSwitcherButton) view;
- tabSwitcherButton.setOnClickListener(listener);
- tabSwitcherButton.setCount(tabSwitcher.getCount());
- tabSwitcher.addListener(tabSwitcherButton);
- }
- }
- }
-
- /**
- * Adds a listener, which should be notified about the tab switcher's events.
- *
- * @param listener
- * The listener, which should be added, as an instance of the type {@link
- * TabSwitcherListener}. The listener may not be null
- */
- public final void addListener(@NonNull final TabSwitcherListener listener) {
- Condition.INSTANCE.ensureNotNull(listener, "The listener may not be null");
- this.listeners.add(listener);
- }
-
- /**
- * Removes a specific listener, which should not be notified about the tab switcher's events,
- * anymore.
- *
- * @param listener
- * The listener, which should be removed, as an instance of the type {@link
- * TabSwitcherListener}. The listener may not be null
- */
- public final void removeListener(@NonNull final TabSwitcherListener listener) {
- Condition.INSTANCE.ensureNotNull(listener, "The listener may not be null");
- this.listeners.remove(listener);
- }
-
- /**
- * Returns the layout policy, which is used by the tab switcher.
- *
- * @return The layout policy, which is used by the tab switcher, as a value of the enum {@link
- * LayoutPolicy}. The layout policy may either be {@link LayoutPolicy#AUTO}, {@link
- * LayoutPolicy#PHONE} or {@link LayoutPolicy#TABLET}
- */
- @NonNull
- public final LayoutPolicy getLayoutPolicy() {
- return layoutPolicy;
- }
-
- /**
- * Sets the layout policy, which should be used by the tab switcher.
- *
- * Changing the layout policy after the view has been laid out does not have any effect.
- *
- * @param layoutPolicy
- * The layout policy, which should be set, as a value of the enum {@link LayoutPolicy}.
- * The layout policy may either be {@link LayoutPolicy#AUTO}, {@link LayoutPolicy#PHONE}
- * or {@link LayoutPolicy#TABLET}
- */
- public final void setLayoutPolicy(@NonNull final LayoutPolicy layoutPolicy) {
- Condition.INSTANCE.ensureNotNull(layoutPolicy, "The layout policy may not be null");
-
- if (this.layoutPolicy != layoutPolicy) {
- Layout previousLayout = getLayout();
- this.layoutPolicy = layoutPolicy;
-
- if (layout != null) {
- Layout newLayout = getLayout();
-
- if (previousLayout != newLayout) {
- layout.detachLayout(false);
- model.removeListener(layout);
- touchEventDispatcher.removeEventHandler(layout.getDragHandler());
- initializeLayout(newLayout, false);
- }
- }
- }
- }
-
- /**
- * Returns the layout of the tab switcher.
- *
- * @return The layout of the tab switcher as a value of the enum {@link Layout}. The layout may
- * either be {@link Layout#PHONE_PORTRAIT}, {@link Layout#PHONE_LANDSCAPE} or {@link
- * Layout#TABLET}
- */
- @NonNull
- public final Layout getLayout() {
- // TODO: Return Layout.TABLET once supported
- /*
- if (layoutPolicy == LayoutPolicy.TABLET || (layoutPolicy == LayoutPolicy.AUTO &&
- getDeviceType(getContext()) == DeviceType.TABLET)) {
- return Layout.TABLET;
- } else {
- */
- return getOrientation(getContext()) == Orientation.LANDSCAPE ? Layout.PHONE_LANDSCAPE :
- Layout.PHONE_PORTRAIT;
- //}
- }
-
- /**
- * Adds a specific drag gesture to the tab switcher.
- *
- * @param dragGesture
- * The drag gesture, which should be added, as an instance of the class {@link
- * DragGesture}. The drag gesture may not be null
- */
- public final void addDragGesture(@NonNull final DragGesture dragGesture) {
- Condition.INSTANCE.ensureNotNull(dragGesture, "The drag gesture may not be null");
- AbstractTouchEventHandler eventHandler =
- new DragGestureEventHandlerFactory(this).fromGesture(dragGesture);
- touchEventDispatcher.addEventHandler(eventHandler);
- }
-
- /**
- * Removes a specific drag gesture from the tab switcher.
- *
- * @param dragGesture
- * The drag gesture, which should be removed, as an instance of the class {@link
- * DragGesture}. The drag gesture may not be null
- */
- public final void removeDragGesture(@NonNull final DragGesture dragGesture) {
- Condition.INSTANCE.ensureNotNull(dragGesture, "The drag gesture may not be null");
- AbstractTouchEventHandler eventHandler =
- new DragGestureEventHandlerFactory(this).fromGesture(dragGesture);
- touchEventDispatcher.removeEventHandler(eventHandler);
- }
-
- /**
- * Sets, whether the sate of the tab switcher should be saved in the method
- * {@link #onSaveInstanceState()} and restored in the method
- * {@link #onRestoreInstanceState(Parcelable)}, or not.
- *
- * @param enabled
- * True, if the state of the tab switcher should be preserved, false otherwise
- */
- public void setPreserveState(final boolean enabled) {
- preserveState = enabled;
- }
-
- /**
- * Returns, whether the state of the tab switcher is saved in the method
- * {@link #onSaveInstanceState()} and restored in the method
- * {@link #onRestoreInstanceState(Parcelable)}, or not.
- *
- * @return True, if the state of the tab switcher is preserved, false otherwise
- */
- public boolean isStatePreserved() {
- return preserveState;
- }
-
- /**
- * Clears the saved state of a specific tab.
- *
- * @param tab
- * The tab, whose saved state should be cleared, as an instance of the class {@link
- * Tab}. The tab may not be null
- */
- public void clearSavedState(@NonNull final Tab tab) {
- Condition.INSTANCE.ensureNotNull(tab, "The tab may not be null");
- ContentRecyclerAdapter contentRecyclerAdapter = model.getContentRecyclerAdapter();
-
- if (contentRecyclerAdapter != null) {
- contentRecyclerAdapter.clearSavedState(tab);
- }
- }
-
- /**
- * Clears the saved states of all tabs.
- */
- public void clearAllSavedStates() {
- ContentRecyclerAdapter contentRecyclerAdapter = model.getContentRecyclerAdapter();
-
- if (contentRecyclerAdapter != null) {
- contentRecyclerAdapter.clearAllSavedStates();
- }
- }
-
- /**
- * Notifies the tab switcher that a specific tab has changed. This will cause the content of the
- * tab to be updated by utilizing the tab switcher's adapter.
- *
- * @param tab
- * The tab, which has changed, as an instance of the class {@link Tab}. The tab may not
- * be null
- */
- public final void notifyTabChanged(@NonNull final Tab tab) {
- Condition.INSTANCE.ensureNotNull(tab, "The tab may not be null");
-
- if (layout != null) {
- AbstractViewRecycler contentViewRecycler = layout.getContentViewRecycler();
-
- if (contentViewRecycler != null) {
- contentViewRecycler.notifyItemChanged(tab);
- }
- }
- }
-
- @Override
- public final void addTab(@NonNull final Tab tab) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.addTab(tab);
- }
-
- });
- }
-
- @Override
- public final void addTab(@NonNull final Tab tab, final int index) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.addTab(tab, index);
- }
-
- });
- }
-
- @Override
- public final void addTab(@NonNull final Tab tab, final int index,
- @NonNull final Animation animation) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.addTab(tab, index, animation);
- }
-
- });
- }
-
- @Override
- public final void addAllTabs(@NonNull final Collection extends Tab> tabs) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.addAllTabs(tabs);
- }
-
- });
- }
-
- @Override
- public final void addAllTabs(@NonNull final Collection extends Tab> tabs, final int index) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.addAllTabs(tabs, index);
- }
-
- });
- }
-
- @Override
- public final void addAllTabs(@NonNull final Collection extends Tab> tabs, final int index,
- @NonNull final Animation animation) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.addAllTabs(tabs, index, animation);
- }
-
- });
- }
-
- @Override
- public final void addAllTabs(@NonNull final Tab[] tabs) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.addAllTabs(tabs);
- }
-
- });
- }
-
- @Override
- public final void addAllTabs(@NonNull final Tab[] tabs, final int index) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.addAllTabs(tabs, index);
- }
-
- });
- }
-
- @Override
- public final void addAllTabs(@NonNull final Tab[] tabs, final int index,
- @NonNull final Animation animation) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.addAllTabs(tabs, index, animation);
- }
-
- });
- }
-
- @Override
- public final void removeTab(@NonNull final Tab tab) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.removeTab(tab);
- }
-
- });
- }
-
- @Override
- public final void removeTab(@NonNull final Tab tab, @NonNull final Animation animation) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.removeTab(tab, animation);
- }
-
- });
- }
-
- @Override
- public final void clear() {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.clear();
- }
-
- });
- }
-
- @Override
- public final void clear(@NonNull final Animation animationType) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.clear(animationType);
- }
-
- });
- }
-
- @Override
- public final void selectTab(@NonNull final Tab tab) {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.selectTab(tab);
- }
-
- });
- }
-
- @Override
- public final void selectTab(final int index) {
- model.selectTab(index);
- }
-
- @Nullable
- @Override
- public final Tab getSelectedTab() {
- return model.getSelectedTab();
- }
-
- @Override
- public final int getSelectedTabIndex() {
- return model.getSelectedTabIndex();
- }
-
- @Override
- public final Iterator iterator() {
- return model.iterator();
- }
-
- @Override
- public final boolean isEmpty() {
- return model.isEmpty();
- }
-
- @Override
- public final int getCount() {
- return model.getCount();
- }
-
- @NonNull
- @Override
- public final Tab getTab(final int index) {
- return model.getTab(index);
- }
-
- @Override
- public final int indexOf(@NonNull final Tab tab) {
- return model.indexOf(tab);
- }
-
- @Override
- public final boolean isSwitcherShown() {
- return model.isSwitcherShown();
- }
-
- @Override
- public final void showSwitcher() {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.showSwitcher();
- }
-
- });
- }
-
- @Override
- public final void hideSwitcher() {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.hideSwitcher();
- }
-
- });
- }
-
- @Override
- public final void toggleSwitcherVisibility() {
- enqueuePendingAction(new Runnable() {
-
- @Override
- public void run() {
- model.toggleSwitcherVisibility();
- }
-
- });
- }
-
- @Override
- public final void setDecorator(@NonNull final TabSwitcherDecorator decorator) {
- model.setDecorator(decorator);
- }
-
- @Override
- public final TabSwitcherDecorator getDecorator() {
- return model.getDecorator();
- }
-
- @NonNull
- @Override
- public final LogLevel getLogLevel() {
- return model.getLogLevel();
- }
-
- @Override
- public final void setLogLevel(@NonNull final LogLevel logLevel) {
- model.setLogLevel(logLevel);
- }
-
- @Override
- public final void setPadding(final int left, final int top, final int right, final int bottom) {
- // The model might be null on old API levels, where the super constructor implicitly invokes
- // the setPadding-method. We can simply ignore such method call and will set the correct
- // padding later on
- if (model != null) {
- model.setPadding(left, top, right, bottom);
- }
- }
-
- @Override
- public final int getPaddingLeft() {
- return model.getPaddingLeft();
- }
-
- @Override
- public final int getPaddingTop() {
- return model.getPaddingTop();
- }
-
- @Override
- public final int getPaddingRight() {
- return model.getPaddingRight();
- }
-
- @Override
- public final int getPaddingBottom() {
- return model.getPaddingBottom();
- }
-
- @Override
- public final int getPaddingStart() {
- return model.getPaddingStart();
- }
-
- @Override
- public final int getPaddingEnd() {
- return model.getPaddingEnd();
- }
-
- @Override
- public final void applyPaddingToTabs(final boolean applyPaddingToTabs) {
- model.applyPaddingToTabs(applyPaddingToTabs);
- }
-
- @Override
- public final boolean isPaddingAppliedToTabs() {
- return model.isPaddingAppliedToTabs();
- }
-
- @Nullable
- @Override
- public final Drawable getTabIcon() {
- return model.getTabIcon();
- }
-
- @Override
- public final void setTabIcon(@DrawableRes final int resourceId) {
- model.setTabIcon(resourceId);
- }
-
- @Override
- public final void setTabIcon(@Nullable final Bitmap icon) {
- model.setTabIcon(icon);
- }
-
- @Override
- public final ColorStateList getTabIconTintList() {
- return model.getTabIconTintList();
- }
-
- @Override
- public final void setTabIconTint(@ColorInt final int color) {
- model.setTabIconTint(color);
- }
-
- @Override
- public final void setTabIconTintList(@Nullable final ColorStateList tintList) {
- model.setTabIconTintList(tintList);
- }
-
- @Override
- public final PorterDuff.Mode getTabIconTintMode() {
- return model.getTabIconTintMode();
- }
-
- @Override
- public final void setTabIconTintMode(@Nullable final PorterDuff.Mode mode) {
- model.setTabIconTintMode(mode);
- }
-
- @Nullable
- @Override
- public final ColorStateList getTabBackgroundColor() {
- return model.getTabBackgroundColor();
- }
-
- @Override
- public final void setTabBackgroundColor(@ColorInt final int color) {
- model.setTabBackgroundColor(color);
- }
-
- @Override
- public final void setTabBackgroundColor(@Nullable final ColorStateList colorStateList) {
- model.setTabBackgroundColor(colorStateList);
- }
-
- @ColorInt
- @Override
- public final int getTabContentBackgroundColor() {
- return model.getTabContentBackgroundColor();
- }
-
- @Override
- public final void setTabContentBackgroundColor(@ColorInt final int color) {
- model.setTabContentBackgroundColor(color);
- }
-
- @Nullable
- @Override
- public final ColorStateList getTabTitleTextColor() {
- return model.getTabTitleTextColor();
- }
-
- @Override
- public final void setTabTitleTextColor(@ColorInt final int color) {
- model.setTabTitleTextColor(color);
- }
-
- @Override
- public final void setTabTitleTextColor(@Nullable final ColorStateList colorStateList) {
- model.setTabTitleTextColor(colorStateList);
- }
-
- @Nullable
- @Override
- public final Drawable getTabCloseButtonIcon() {
- return model.getTabCloseButtonIcon();
- }
-
- @Override
- public final int getTabProgressBarColor() {
- return model.getTabProgressBarColor();
- }
-
- @Override
- public final void setTabProgressBarColor(@ColorInt final int color) {
- model.setTabProgressBarColor(color);
- }
-
- @Override
- public final void setTabCloseButtonIcon(@DrawableRes final int resourceId) {
- model.setTabCloseButtonIcon(resourceId);
- }
-
- @Override
- public final void setTabCloseButtonIcon(@Nullable final Bitmap icon) {
- model.setTabCloseButtonIcon(icon);
- }
-
- @Override
- public final ColorStateList getTabCloseButtonIconTintList() {
- return model.getTabCloseButtonIconTintList();
- }
-
- @Override
- public final void setTabCloseButtonIconTint(@ColorInt final int color) {
- model.setTabCloseButtonIconTint(color);
- }
-
- @Override
- public final void setTabCloseButtonIconTintList(@Nullable final ColorStateList tintList) {
- model.setTabCloseButtonIconTintList(tintList);
- }
-
- @Override
- public final PorterDuff.Mode getTabCloseButtonIconTintMode() {
- return model.getTabCloseButtonIconTintMode();
- }
-
- @Override
- public final void setTabCloseButtonIconTintMode(@Nullable final PorterDuff.Mode mode) {
- model.setTabCloseButtonIconTintMode(mode);
- }
-
- @Override
- public final boolean isAddTabButtonShown() {
- return model.isAddTabButtonShown();
- }
-
- @Override
- public final void showAddTabButton(@Nullable final AddTabButtonListener listener) {
- model.showAddTabButton(listener);
- }
-
- @Nullable
- @Override
- public final ColorStateList getAddTabButtonColor() {
- return model.getAddTabButtonColor();
- }
-
- @Override
- public final void setAddTabButtonColor(@ColorInt final int color) {
- model.setAddTabButtonColor(color);
- }
-
- @Override
- public final void setAddTabButtonColor(@Nullable final ColorStateList colorStateList) {
- model.setAddTabButtonColor(colorStateList);
- }
-
- @Override
- public final boolean areToolbarsShown() {
- return model.areToolbarsShown();
- }
-
- @Override
- public final void showToolbars(final boolean show) {
- model.showToolbars(show);
- }
-
- @Nullable
- @Override
- public final CharSequence getToolbarTitle() {
- Toolbar[] toolbars = getToolbars();
- return toolbars != null ? toolbars[PRIMARY_TOOLBAR_INDEX].getTitle() :
- model.getToolbarTitle();
- }
-
- @Override
- public final void setToolbarTitle(@StringRes final int resourceId) {
- model.setToolbarTitle(resourceId);
- }
-
- @Override
- public final void setToolbarTitle(@Nullable final CharSequence title) {
- model.setToolbarTitle(title);
- }
-
- @Nullable
- @Override
- public final Drawable getToolbarNavigationIcon() {
- Toolbar[] toolbars = getToolbars();
- return toolbars != null ? toolbars[PRIMARY_TOOLBAR_INDEX].getNavigationIcon() :
- model.getToolbarNavigationIcon();
- }
-
- @Override
- public final void setToolbarNavigationIcon(@Nullable final Drawable icon,
- @Nullable final OnClickListener listener) {
- model.setToolbarNavigationIcon(icon, listener);
- }
-
- @Override
- public final void setToolbarNavigationIcon(@DrawableRes final int resourceId,
- @Nullable final OnClickListener listener) {
- model.setToolbarNavigationIcon(resourceId, listener);
- }
-
- @Override
- public final ColorStateList getToolbarNavigationIconTintList() {
- return model.getToolbarNavigationIconTintList();
- }
-
- @Override
- public final void setToolbarNavigationIconTint(@ColorInt final int color) {
- model.setToolbarNavigationIconTint(color);
- }
-
- @Override
- public final void setToolbarNavigationIconTintList(@Nullable final ColorStateList tintList) {
- model.setToolbarNavigationIconTintList(tintList);
- }
-
- @Override
- public final PorterDuff.Mode getToolbarNavigationIconTintMode() {
- return model.getToolbarNavigationIconTintMode();
- }
-
- @Override
- public final void setToolbarNavigationIconTintMode(@Nullable final PorterDuff.Mode mode) {
- model.setToolbarNavigationIconTintMode(mode);
- }
-
- @Override
- public final void inflateToolbarMenu(@MenuRes final int resourceId,
- @Nullable final OnMenuItemClickListener listener) {
- model.inflateToolbarMenu(resourceId, listener);
- }
-
- @Override
- public final long getTabPreviewFadeThreshold() {
- return model.getTabPreviewFadeThreshold();
- }
-
- @Override
- public final void setTabPreviewFadeThreshold(final long threshold) {
- model.setTabPreviewFadeThreshold(threshold);
- }
-
- @Override
- public final long getTabPreviewFadeDuration() {
- return model.getTabPreviewFadeDuration();
- }
-
- @Override
- public final void setTabPreviewFadeDuration(final long duration) {
- model.setTabPreviewFadeDuration(duration);
- }
-
- @Nullable
- @Override
- public final View getEmptyView() {
- return model.getEmptyView();
- }
-
- @Override
- public void setEmptyView(@Nullable final View view) {
- model.setEmptyView(view);
- }
-
- @Override
- public final void setEmptyView(@Nullable final View view, final long animationDuration) {
- model.setEmptyView(view, animationDuration);
- }
-
- @Override
- public final void setEmptyView(@LayoutRes final int resourceId) {
- model.setEmptyView(resourceId);
- }
-
- @Override
- public final void setEmptyView(@LayoutRes final int resourceId, final long animationDuration) {
- model.setEmptyView(resourceId);
- }
-
- @Override
- public final boolean areSavedStatesClearedWhenRemovingTabs() {
- return model.areSavedStatesClearedWhenRemovingTabs();
- }
-
- @Override
- public final void clearSavedStatesWhenRemovingTabs(final boolean clear) {
- model.clearSavedStatesWhenRemovingTabs(clear);
- }
-
- @Override
- public final void addCloseTabListener(@NonNull final TabCloseListener listener) {
- model.addCloseTabListener(listener);
- }
-
- @Override
- public final void removeCloseTabListener(@NonNull final TabCloseListener listener) {
- model.removeCloseTabListener(listener);
- }
-
- @Override
- public final void addTabPreviewListener(@NonNull final TabPreviewListener listener) {
- model.addTabPreviewListener(listener);
- }
-
- @Override
- public final void removeTabPreviewListener(@NonNull final TabPreviewListener listener) {
- model.removeTabPreviewListener(listener);
- }
-
- @Override
- public final boolean isAnimationRunning() {
- return layout != null && layout.isAnimationRunning();
- }
-
- @Nullable
- @Override
- public final ViewGroup getTabContainer() {
- return layout != null ? layout.getTabContainer() : null;
- }
-
- @Override
- public final Toolbar[] getToolbars() {
- return layout != null ? layout.getToolbars() : null;
- }
-
- @Nullable
- @Override
- public final Menu getToolbarMenu() {
- return layout != null ? layout.getToolbarMenu() : null;
- }
-
- @Override
- public final boolean onTouchEvent(final MotionEvent event) {
- return touchEventDispatcher.handleTouchEvent(event) || super.onTouchEvent(event);
- }
-
- @Override
- public final Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
-
- if (layout != null && preserveState) {
- TabSwitcherState savedState = new TabSwitcherState(superState);
- savedState.layoutPolicy = layoutPolicy;
- savedState.modelState = new Bundle();
- Pair pair = layout.detachLayout(true);
-
- if (pair != null) {
- savedState.modelState
- .putInt(TabSwitcherModel.REFERENCE_TAB_INDEX_EXTRA, pair.first);
- savedState.modelState
- .putFloat(TabSwitcherModel.REFERENCE_TAB_POSITION_EXTRA, pair.second);
- model.setReferenceTabIndex(pair.first);
- model.setReferenceTabPosition(pair.second);
- } else {
- model.setReferenceTabPosition(-1);
- model.setReferenceTabIndex(-1);
- }
-
- model.removeListener(layout);
- layout = null;
- executePendingAction();
- getViewTreeObserver().addOnGlobalLayoutListener(
- new LayoutListenerWrapper(this, createGlobalLayoutListener(true)));
- model.saveInstanceState(savedState.modelState);
- return savedState;
- }
-
- return superState;
- }
-
- @Override
- public final void onRestoreInstanceState(final Parcelable state) {
- if (state instanceof TabSwitcherState && preserveState) {
- TabSwitcherState savedState = (TabSwitcherState) state;
- this.layoutPolicy = savedState.layoutPolicy;
- model.restoreInstanceState(savedState.modelState);
- super.onRestoreInstanceState(savedState.getSuperState());
- } else {
- super.onRestoreInstanceState(state);
- }
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabSwitcherDecorator.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabSwitcherDecorator.java
deleted file mode 100644
index d1a3a9d9..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabSwitcherDecorator.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.android.util.view.AbstractViewHolderAdapter;
-
-/**
- * An abstract base class for all decorators, which are responsible for inflating views, which
- * should be used to visualize the tabs of a {@link TabSwitcher}.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public abstract class TabSwitcherDecorator extends AbstractViewHolderAdapter {
-
- /**
- * The name of the extra, which is used to store the state of a view hierarchy within a bundle.
- */
- private static final String VIEW_HIERARCHY_STATE_EXTRA =
- TabSwitcherDecorator.class.getName() + "::ViewHierarchyState";
-
- /**
- * The method which is invoked, when a view, which is used to visualize a tab, should be
- * inflated.
- *
- * @param inflater
- * The inflater, which should be used to inflate the view, as an instance of the class
- * {@link LayoutInflater}. The inflater may not be null
- * @param parent
- * The parent view of the view, which should be inflated, as an instance of the class
- * {@link ViewGroup} or null, if no parent view is available
- * @param viewType
- * The view type of the tab, which should be visualized, as an {@link Integer} value
- * @return The view, which has been inflated, as an instance of the class {@link View}. The view
- * may not be null
- */
- @NonNull
- public abstract View onInflateView(@NonNull final LayoutInflater inflater,
- @Nullable final ViewGroup parent, final int viewType);
-
- /**
- * The method which is invoked, when the view, which is used to visualize a tab, should be
- * shown, respectively when it should be refreshed. The purpose of this method is to customize
- * the appearance of the view, which is used to visualize the corresponding tab, depending on
- * its state and whether the tab switcher is currently shown, or not.
- *
- * @param context
- * The context, the tab switcher belongs to, as an instance of the class {@link
- * Context}. The context may not be null
- * @param tabSwitcher
- * The tab switcher, whose tabs are visualized by the decorator, as an instance of the
- * type {@link TabSwitcher}. The tab switcher may not be null
- * @param view
- * The view, which is used to visualize the tab, as an instance of the class {@link
- * View}. The view may not be null
- * @param tab
- * The tab, which should be visualized, as an instance of the class {@link Tab}. The tab
- * may not be null
- * @param index
- * The index of the tab, which should be visualized, as an {@link Integer} value
- * @param viewType
- * The view type of the tab, which should be visualized, as an {@link Integer} value
- * @param savedInstanceState
- * The bundle, which has previously been used to save the state of the view as an
- * instance of the class {@link Bundle} or null, if no saved state is available
- */
- public abstract void onShowTab(@NonNull final Context context,
- @NonNull final TabSwitcher tabSwitcher, @NonNull final View view,
- @NonNull final Tab tab, final int index, final int viewType,
- @Nullable final Bundle savedInstanceState);
-
- /**
- * The method, which is invoked, when the view, which is used to visualize a tab has been
- * recycled. The purpose of this method is to reset the appearance of the view to the default
- * state, as it might still display the content of tab for which it was previously used. This
- * method is called prior to invoking the method {@link #onShowTab(Context, TabSwitcher, View,
- * Tab, int, int, Bundle)}.
- *
- * @param context
- * The context, the tab switcher belongs to, as an instance of the class {@link
- * Context}. The context may not be null
- * @param tabSwitcher
- * The tab switcher, whose tabs are visualized by the decorator, as an instance of the
- * type {@link TabSwitcher}. The tab switcher may not be null
- * @param view
- * The view, which is used to visualize the tab, as an instance of the class {@link
- * View}. The view may not be null
- * @param tab
- * The tab, which should be visualized, as an instance of the class {@link Tab}. The tab
- * may not be null
- * @param index
- * The index of the tab, which should be visualized, as an {@link Integer} value
- * @param viewType
- * The view type of the tab, which should be visualized, as an {@link Integer} value
- * @param savedInstanceState
- * The bundle, which has previously been used to save the state of the view as an
- * instance of the class {@link Bundle} or null, if no saved state is available
- */
- public void onRecycleView(@NonNull final Context context,
- @NonNull final TabSwitcher tabSwitcher, @NonNull final View view,
- @NonNull final Tab tab, final int index, final int viewType,
- @Nullable final Bundle savedInstanceState) {
-
- }
-
- /**
- * The method, which is invoked, when the view, which is used to visualize a tab, is removed.
- * The purpose of this method is to save the current state of the tab in a bundle.
- *
- * @param view
- * The view, which is used to visualize the tab, as an instance of the class {@link
- * View}
- * @param tab
- * The tab, whose state should be saved, as an instance of the class {@link Tab}. The
- * tab may not be null
- * @param index
- * The index of the tab, whose state should be saved, as an {@link Integer} value
- * @param viewType
- * The view type of the tab, whose state should be saved, as an {@link Integer} value
- * @param outState
- * The bundle, the state of the tab should be saved to, as an instance of the class
- * {@link Bundle}. The bundle may not be null
- */
- public void onSaveInstanceState(@NonNull final View view, @NonNull final Tab tab,
- final int index, final int viewType,
- @NonNull final Bundle outState) {
-
- }
-
- /**
- * Returns the view type, which corresponds to a specific tab. For each layout, which is
- * inflated by the onInflateView
-method, a distinct view type must be returned.
- *
- * @param tab
- * The tab, whose view type should be returned, as an instance of the class {@link Tab}.
- * The tab may not be null
- * @param index
- * The index of the tab, whose view type should be returned, as an {@link Integer}
- * value
- * @return The view type, which corresponds to the given tab, as an {@link Integer} value
- */
- public int getViewType(@NonNull final Tab tab, final int index) {
- return 0;
- }
-
- /**
- * Returns the number of view types, which are used by the decorator.
- *
- * @return The number of view types, which are used by the decorator, as an {@link Integer}
- * value. The number of view types must correspond to the number of distinct values, which are
- * returned by the getViewType
-method
- */
- public int getViewTypeCount() {
- return 1;
- }
-
- /**
- * The method, which is invoked by a {@link TabSwitcher} to inflate the view, which should be
- * used to visualize a specific tab.
- *
- * @param inflater
- * The inflater, which should be used to inflate the view, as an instance of the class
- * {@link LayoutInflater}. The inflater may not be null
- * @param parent
- * The parent view of the view, which should be inflated, as an instance of the class
- * {@link ViewGroup} or null, if no parent view is available
- * @param tab
- * The tab, which should be visualized, as an instance of the class {@link Tab}. The tab
- * may not be null
- * @param index
- * The index of the tab, which should be visualized, as an {@link Integer} value
- * @return The view, which has been inflated, as an instance of the class {@link View}. The view
- * may not be null
- */
- @NonNull
- public final View inflateView(@NonNull final LayoutInflater inflater,
- @Nullable final ViewGroup parent, @NonNull final Tab tab,
- final int index) {
- int viewType = getViewType(tab, index);
- return onInflateView(inflater, parent, viewType);
- }
-
- /**
- * The method, which is invoked by a {@link TabSwitcher} to apply the decorator. It initializes
- * the view holder pattern, which is provided by the decorator and then delegates the method
- * call to the decorator's custom implementation of the method onShowTab(...):void
.
- *
- * @param context
- * The context, the tab switcher belongs to, as an instance of the class {@link
- * Context}. The context may not be null
- * @param tabSwitcher
- * The tab switcher, whose tabs are visualized by the decorator, as an instance of the
- * class {@link TabSwitcher}. The tab switcher may not be null
- * @param view
- * The view, which is used to visualize the tab, as an instance of the class {@link
- * View}. The view may not be null
- * @param tab
- * The tab, which should be visualized, as an instance of the class {@link Tab}. The tab
- * may not be null
- * @param index
- * The index of the tab, which should be visualized, as an {@link Integer} value
- * @param savedInstanceState
- * The bundle, which has previously been used to save the state of the view as an
- * instance of the class {@link Bundle} or null, if no saved state is available
- * @param inflated
- * True, if the view has been inflated, false, if it has been reused
- */
- public final void applyDecorator(@NonNull final Context context,
- @NonNull final TabSwitcher tabSwitcher,
- @NonNull final View view, @NonNull final Tab tab,
- final int index, @Nullable final Bundle savedInstanceState,
- final boolean inflated) {
- setCurrentParentView(view);
- int viewType = getViewType(tab, index);
-
- if (savedInstanceState != null) {
- SparseArray viewStates =
- savedInstanceState.getSparseParcelableArray(VIEW_HIERARCHY_STATE_EXTRA);
-
- if (viewStates != null) {
- view.restoreHierarchyState(viewStates);
- }
- }
-
- if (!inflated) {
- onRecycleView(context, tabSwitcher, view, tab, index, viewType, savedInstanceState);
- }
-
- onShowTab(context, tabSwitcher, view, tab, index, viewType, savedInstanceState);
- }
-
- /**
- * The method, which is invoked by a {@link TabSwitcher} to save the current state of a tab. It
- * initializes the view holder pattern, which is provided by the decorator and then delegates
- * the method call to the decorator's custom implementation of the method
- * onSaveInstanceState(...):void
.
- *
- * @param view
- * The view, which is used to visualize the tab, as an instance of the class {@link
- * View}
- * @param tab
- * The tab, whose state should be saved, as an instance of the class {@link Tab}. The
- * tab may not be null
- * @param index
- * The index of the tab, whose state should be saved, as an {@link Integer} value
- * @return The bundle, which has been used to save the state, as an instance of the class {@link
- * Bundle}. The bundle may not be null
- */
- @NonNull
- public final Bundle saveInstanceState(@NonNull final View view, @NonNull final Tab tab,
- final int index) {
- setCurrentParentView(view);
- int viewType = getViewType(tab, index);
- Bundle outState = new Bundle();
- SparseArray viewStates = new SparseArray<>();
- view.saveHierarchyState(viewStates);
- outState.putSparseParcelableArray(VIEW_HIERARCHY_STATE_EXTRA, viewStates);
- onSaveInstanceState(view, tab, index, viewType, outState);
- return outState;
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabSwitcherListener.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabSwitcherListener.java
deleted file mode 100644
index 80dd5102..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/TabSwitcherListener.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * Defines the interface, a class, which should be notified about a tab switcher's events, must
- * implement.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public interface TabSwitcherListener {
-
- /**
- * The method, which is invoked, when the tab switcher has been shown.
- *
- * @param tabSwitcher
- * The observed tab switcher as an instance of the class {@link TabSwitcher}. The tab
- * switcher may not be null
- */
- void onSwitcherShown(@NonNull TabSwitcher tabSwitcher);
-
- /**
- * The method, which is invoked, when the tab switcher has been hidden.
- *
- * @param tabSwitcher
- * The observed tab switcher as an instance of the class {@link TabSwitcher}. The tab
- * switcher may not be null
- */
- void onSwitcherHidden(@NonNull TabSwitcher tabSwitcher);
-
- /**
- * The method, which is invoked, when the currently selected tab has been changed.
- *
- * @param tabSwitcher
- * The observed tab switcher as an instance of the class {@link TabSwitcher}. The tab
- * switcher may not be null
- * @param selectedTabIndex
- * The index of the currently selected tab as an {@link Integer} value or -1, if the tab
- * switcher does not contain any tabs
- * @param selectedTab
- * The currently selected tab as an instance of the class {@link Tab} or null, if the
- * tab switcher does not contain any tabs
- */
- void onSelectionChanged(@NonNull TabSwitcher tabSwitcher, int selectedTabIndex,
- @Nullable Tab selectedTab);
-
- /**
- * The method, which is invoked, when a tab has been added to the tab switcher.
- *
- * @param tabSwitcher
- * The observed tab switcher as an instance of the class {@link TabSwitcher}. The tab
- * switcher may not be null
- * @param index
- * The index of the tab, which has been added, as an {@link Integer} value
- * @param tab
- * The tab, which has been added, as an instance of the class {@link Tab}. The tab may
- * not be null
- * @param animation
- * The animation, which has been used to add the tab, as an instance of the class {@link
- * Animation}. The animation may not be null
- */
- void onTabAdded(@NonNull TabSwitcher tabSwitcher, int index, @NonNull Tab tab,
- @NonNull Animation animation);
-
- /**
- * The method, which is invoked, when a tab has been removed from the tab switcher.
- *
- * @param tabSwitcher
- * The observed tab switcher as an instance of the class {@link TabSwitcher}. The tab
- * switcher may not be null
- * @param index
- * The index of the tab, which has been removed, as an {@link Integer} value
- * @param tab
- * The tab, which has been removed, as an instance of the class {@link Tab}. The tab may
- * not be null
- * @param animation
- * The animation, which has been used to remove the tab, as an instance of the class
- * {@link Animation}. The animation may not be null
- */
- void onTabRemoved(@NonNull TabSwitcher tabSwitcher, int index, @NonNull Tab tab,
- @NonNull Animation animation);
-
- /**
- * The method, which is invoked, when all tabs have been removed from the tab switcher.
- *
- * @param tabSwitcher
- * The observed tab switcher as an instance of the class {@link TabSwitcher}. The tab
- * switcher may not be null
- * @param tabs
- * An array, which contains the tabs, which have been removed, as an array of the type
- * {@link Tab} or an empty array, if no tabs have been removed
- * @param animation
- * The animation, which has been used to remove the tabs, as an instance of the class
- * {@link Animation}. The animation may not be null
- */
- void onAllTabsRemoved(@NonNull TabSwitcher tabSwitcher, @NonNull Tab[] tabs,
- @NonNull Animation animation);
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/drawable/TabSwitcherDrawable.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/drawable/TabSwitcherDrawable.java
deleted file mode 100644
index b7bc37b9..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/drawable/TabSwitcherDrawable.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.drawable;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.content.ContextCompat;
-import de.mrapp.android.tabswitcher.Animation;
-import de.mrapp.android.tabswitcher.R;
-import de.mrapp.android.tabswitcher.Tab;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.TabSwitcherListener;
-import de.mrapp.android.util.ThemeUtil;
-import de.mrapp.util.Condition;
-
-/**
- * A drawable, which allows to display the number of tabs, which are currently contained by a {@link
- * TabSwitcher}. It must be registered at a {@link TabSwitcher} instance in order to keep the
- * displayed label up to date. It therefore implements the interface {@link TabSwitcherListener}.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class TabSwitcherDrawable extends Drawable implements TabSwitcherListener {
-
- /**
- * The size of the drawable in pixels.
- */
- private final int size;
-
- /**
- * The default text size of the displayed label in pixels.
- */
- private final int textSizeNormal;
-
- /**
- * The text size of the displayed label, which is used when displaying a value greater than 99,
- * in pixels.
- */
- private final int textSizeSmall;
-
- /**
- * The drawable, which is shown as the background.
- */
- private final Drawable background;
-
- /**
- * The paint, which is used to draw the drawable's label.
- */
- private final Paint paint;
-
- /**
- * The currently displayed label.
- */
- private String label;
-
- /**
- * Creates a new drawable, which allows to display the number of tabs, which are currently
- * contained by a {@link TabSwitcher}.
- *
- * @param context
- * The context, which should be used by the drawable, as an instance of the class {@link
- * Context}. The context may not be null
- */
- public TabSwitcherDrawable(@NonNull final Context context) {
- Condition.INSTANCE.ensureNotNull(context, "The context may not be null");
- Resources resources = context.getResources();
- size = resources.getDimensionPixelSize(R.dimen.tab_switcher_drawable_size);
- textSizeNormal =
- resources.getDimensionPixelSize(R.dimen.tab_switcher_drawable_font_size_normal);
- textSizeSmall =
- resources.getDimensionPixelSize(R.dimen.tab_switcher_drawable_font_size_small);
- background = ContextCompat.getDrawable(context, R.drawable.tab_switcher_drawable_background)
- .mutate();
- paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setColor(Color.WHITE);
- paint.setTextAlign(Align.CENTER);
- paint.setTextSize(textSizeNormal);
- paint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
- label = Integer.toString(0);
- int tint = ThemeUtil.getColor(context, android.R.attr.textColorPrimary);
- setColorFilter(tint, PorterDuff.Mode.MULTIPLY);
- }
-
- /**
- * Updates the drawable to display a specific value.
- *
- * @param count
- * The value, which should be displayed, as an {@link Integer} value. The value must be
- * at least 0
- */
- public final void setCount(final int count) {
- Condition.INSTANCE.ensureAtLeast(count, 0, "The count must be at least 0");
- label = Integer.toString(count);
-
- if (label.length() > 2) {
- label = "99+";
- paint.setTextSize(textSizeSmall);
- } else {
- paint.setTextSize(textSizeNormal);
- }
-
- invalidateSelf();
- }
-
- @Override
- public final void draw(@NonNull final Canvas canvas) {
- Rect bounds = getBounds();
- int width = bounds.right;
- int height = bounds.bottom;
- int intrinsicWidth = background.getIntrinsicWidth();
- int intrinsicHeight = background.getIntrinsicHeight();
- int left = (width / 2) - (intrinsicWidth / 2);
- int top = (height / 2) - (intrinsicHeight / 2);
- background.setBounds(left, top, left + intrinsicWidth, top + intrinsicHeight);
- background.draw(canvas);
- float x = width / 2f;
- float y = (height / 2f) - ((paint.descent() + paint.ascent()) / 2f);
- canvas.drawText(label, x, y, paint);
- }
-
- @Override
- public final int getIntrinsicWidth() {
- return size;
- }
-
- @Override
- public final int getIntrinsicHeight() {
- return size;
- }
-
- @Override
- public final void setAlpha(final int alpha) {
- background.setAlpha(alpha);
- paint.setAlpha(alpha);
- }
-
- @Override
- public final void setColorFilter(@Nullable final ColorFilter colorFilter) {
- background.setColorFilter(colorFilter);
- paint.setColorFilter(colorFilter);
- }
-
- @Override
- public final int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- public final void onSwitcherShown(@NonNull final TabSwitcher tabSwitcher) {
-
- }
-
- @Override
- public final void onSwitcherHidden(@NonNull final TabSwitcher tabSwitcher) {
-
- }
-
- @Override
- public final void onSelectionChanged(@NonNull final TabSwitcher tabSwitcher,
- final int selectedTabIndex,
- @Nullable final Tab selectedTab) {
-
- }
-
- @Override
- public final void onTabAdded(@NonNull final TabSwitcher tabSwitcher, final int index,
- @NonNull final Tab tab, @NonNull final Animation animation) {
- setCount(tabSwitcher.getCount());
- }
-
- @Override
- public final void onTabRemoved(@NonNull final TabSwitcher tabSwitcher, final int index,
- @NonNull final Tab tab, @NonNull final Animation animation) {
- setCount(tabSwitcher.getCount());
- }
-
- @Override
- public final void onAllTabsRemoved(@NonNull final TabSwitcher tabSwitcher,
- @NonNull final Tab[] tab,
- @NonNull final Animation animation) {
- setCount(tabSwitcher.getCount());
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/AbstractDragGestureEventHandler.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/AbstractDragGestureEventHandler.java
deleted file mode 100644
index 2bcabca8..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/AbstractDragGestureEventHandler.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.gesture;
-
-import android.graphics.RectF;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-
-/**
- * An abstract base class for all event handlers, which allow to handle drag gestures.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public abstract class AbstractDragGestureEventHandler extends AbstractTouchEventHandler {
-
- /**
- * The bounds of the onscreen area, the handler takes into consideration for handling
- * touch events.
- */
- private final RectF touchableArea;
-
- /**
- * Creates a new handler, which can be managed by a {@link TouchEventDispatcher} in order to
- * dispatch touch events to it.
- *
- * @param tabSwitcher
- * The tab switcher, the event handler belongs to, as an instance of the class {@link
- * TabSwitcher}. The tab switcher may not be null
- * @param dragThreshold
- * The threshold of the drag helper, which is used to recognize drag gestures, in pixels
- * as an {@link Integer} value The threshold must be at least 0
- * @param touchableArea
- * The bounds of the onscreen area, the handler should take into consideration for
- * handling touch events, as an instance of the class {@link RectF} or null, if the are
- * should not be restricted
- */
- public AbstractDragGestureEventHandler(@NonNull final TabSwitcher tabSwitcher,
- final int dragThreshold,
- @Nullable final RectF touchableArea) {
- super(MAX_PRIORITY, tabSwitcher, dragThreshold);
- this.touchableArea = touchableArea;
- }
-
- @Nullable
- @Override
- public final RectF getTouchableArea() {
- return touchableArea;
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/AbstractTouchEventHandler.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/AbstractTouchEventHandler.java
deleted file mode 100644
index e999baf8..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/AbstractTouchEventHandler.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.gesture;
-
-import android.graphics.RectF;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-
-import java.util.Comparator;
-
-import androidx.annotation.CallSuper;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.util.gesture.DragHelper;
-import de.mrapp.util.Condition;
-
-/**
- * An abstract base class for all event handlers, which can be managed by a {@link
- * TouchEventDispatcher} in order to dispatch touch events to them.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public abstract class AbstractTouchEventHandler implements Comparator {
-
- /**
- * The maximum priority of an event handler.
- */
- protected static final int MAX_PRIORITY = Integer.MAX_VALUE;
-
- /**
- * The minimum priority of an event handler.
- */
- protected static final int MIN_PRIORITY = Integer.MIN_VALUE;
-
- /**
- * The priority of the event handler.
- */
- private final int priority;
-
- /**
- * The tab switcher, the event handler belongs to.
- */
- private final TabSwitcher tabSwitcher;
-
- /**
- * The drag helper, which is used by the touch handler to recognize drag gestures.
- */
- private final DragHelper dragHelper;
-
- /**
- * The current threshold of the drag helper, which is used to recognize drag gestures.
- */
- private int dragThreshold;
-
- /**
- * The velocity tracker, which is used by the touch handler to measure the velocity of drag
- * gestures.
- */
- private VelocityTracker velocityTracker;
-
- /**
- * The id of the pointer, which has been used to start the current drag gesture.
- */
- private int pointerId;
-
- /**
- * Handles, when a drag gesture has been started.
- *
- * @param event
- * The motion event, which started the drag gesture, as an instance of the class {@link
- * MotionEvent}. The motion event may not be null
- */
- private void handleDown(@NonNull final MotionEvent event) {
- pointerId = event.getPointerId(0);
-
- if (velocityTracker == null) {
- velocityTracker = VelocityTracker.obtain();
- } else {
- velocityTracker.clear();
- }
-
- velocityTracker.addMovement(event);
- onDown(event);
- }
-
- /**
- * Returns the tab switcher, the event handler belongs to.
- *
- * @return The tab switcher, the event handler belongs to, as an instance of the class {@link
- * TabSwitcher}. The tab switcher may not be null
- */
- @NonNull
- protected final TabSwitcher getTabSwitcher() {
- return tabSwitcher;
- }
-
- /**
- * The velocity tracker, which is used by the touch handler to measure the velocity of drag
- * gestures.
- *
- * @return The velocity tracker, which is used by the touch handler to measure the velocity of
- * drag gestures as an instance of the class {@link VelocityTracker} or null, if the velocity
- * tracker has not be initialized yet
- */
- @Nullable
- protected final VelocityTracker getVelocityTracker() {
- return velocityTracker;
- }
-
- /**
- * Resets the event handler once a drag gesture has been ended.
- */
- protected void reset() {
- if (this.velocityTracker != null) {
- this.velocityTracker.recycle();
- this.velocityTracker = null;
- }
-
- this.pointerId = -1;
- this.dragHelper.reset(dragThreshold);
- }
-
- /**
- * Returns, whether performing a drag gesture is currently allowed, or not.
- *
- * @return True, if performing a drag gesture is currently allowed, false otherwise
- */
- protected abstract boolean isDraggingAllowed();
-
- /**
- * The method, which is invoked on implementing subclasses, when a touch event is about to be
- * handled.
- */
- protected abstract void onTouchEvent();
-
- /**
- * The method, which is invoked on implementing subclasses in order to handle, when a drag
- * gesture has been started.
- *
- * @param event
- * The touch event, which started the drag gesture, as an instance of the class {@link
- * MotionEvent}. The touch event may not be null
- */
- protected abstract void onDown(@NonNull final MotionEvent event);
-
- /**
- * The method, which is invoked on implementing subclasses in order to handle, when a drag
- * gesture is performed.
- *
- * @param event
- * The last touch event of the drag gesture as an instance of the class {@link
- * MotionEvent}. The touch event may not be null
- */
- protected abstract void onDrag(@NonNull final MotionEvent event);
-
- /**
- * Handles, when a drag gesture has been ended.
- *
- * @param event
- * The touch event, which ended the drag gesture, as an instance of the class {@link
- * MotionEvent} or null, if no fling animation should be triggered
- */
- protected abstract void onUp(@Nullable final MotionEvent event);
-
- /**
- * Creates a new handler, which can be managed by a {@link TouchEventDispatcher} in order to
- * dispatch touch events to it.
- *
- * @param priority
- * The priority of the handler as an {@link Integer} value. The priority must be at
- * least {@link AbstractTouchEventHandler#MIN_PRIORITY} and at maximum {@link
- * AbstractTouchEventHandler#MAX_PRIORITY}
- * @param tabSwitcher
- * The tab switcher, the event handler belongs to, as an instance of the class {@link
- * TabSwitcher}. The tab switcher may not be null
- * @param dragThreshold
- * The threshold of the drag helper, which is used to recognize drag gestures, in pixels
- * as an {@link Integer} value The threshold must be at least 0
- */
- public AbstractTouchEventHandler(final int priority, @NonNull final TabSwitcher tabSwitcher,
- final int dragThreshold) {
- Condition.INSTANCE.ensureAtLeast(priority, MIN_PRIORITY,
- "The priority must be at least" + MIN_PRIORITY);
- Condition.INSTANCE.ensureAtMaximum(priority, MAX_PRIORITY,
- "The priority must be at maximum " + MAX_PRIORITY);
- Condition.INSTANCE.ensureNotNull(tabSwitcher, "The tab switcher may not be null");
- Condition.INSTANCE.ensureAtLeast(dragThreshold, 0, "The drag threshold must be at least 0");
- this.priority = priority;
- this.tabSwitcher = tabSwitcher;
- this.dragHelper = new DragHelper(0);
- this.dragThreshold = dragThreshold;
- reset();
- }
-
- /**
- * Returns, whether the event handler is reset, or not.
- *
- * @return True, if the event handler is reset, false otherwise
- */
- public final boolean isReset() {
- return pointerId == -1;
- }
-
- /**
- * Returns, whether a drag gesture is currently handled by the event handler, or not. This
- * method may be overridden by subclasses, if multiple drag helpers are used.
- *
- * @return True, if a drag gesture is currently handled by the event handler, false otherwise
- */
- @CallSuper
- public boolean isDragging() {
- return dragHelper.hasThresholdBeenReached();
- }
-
- /**
- * Returns the priority of the event handler. Events are first dispatched to handlers with a
- * higher priority.
- *
- * @return The priority of the event handler as an {@link Integer} value
- */
- public final int getPriority() {
- return priority;
- }
-
- /**
- * Returns the bounds of the onscreen area, the handler takes into consideration for handling
- * touch events. Touch events that occur outside of the area are clipped. By default, the area
- * is not restricted. Subclasses may override this method in order to restrict the area.
- *
- * @return The bounds of the onscreen area, the handler takes into consideration for handling
- * touch events, as an instance of the class {@link RectF} or null, if the area is not
- * restricted
- */
- @Nullable
- public RectF getTouchableArea() {
- return null;
- }
-
- /**
- * Returns, whether a specific touch event occurred inside the touchable area of the event
- * handler.
- *
- * @param event
- * The touch event, which should be checked, as an instance of the class {@link
- * MotionEvent}. The touch event may not be null
- * @return True, if the given touch event occurred inside the touchable area, false otherwise
- */
- public final boolean isInsideTouchableArea(@NonNull final MotionEvent event) {
- return getTouchableArea() == null || (event.getX() >= getTouchableArea().left &&
- event.getX() <= getTouchableArea().right &&
- event.getY() >= getTouchableArea().top &&
- event.getY() <= getTouchableArea().bottom);
- }
-
- /**
- * Returns the drag helper, which is used by the event handler to recognize drag gestures.
- *
- * @return The drag helper, which is used by the event handler to recognize drag gestures, as an
- * instance of the class DragHelper. The drag helper may not be null
- */
- @NonNull
- public final DragHelper getDragHelper() {
- return dragHelper;
- }
-
- /**
- * Sets the id of the pointer, which has been used to start the current drag gesture.
- *
- * @param pointerId
- * The id, which should be set, as an {@link Integer} value or -1, if no drag gesture is
- * currently started
- */
- public final void setPointerId(final int pointerId) {
- this.pointerId = pointerId;
- }
-
- /**
- * Handles a specific touch event. The event is only handled, if it occurred inside the
- * touchable area.
- *
- * @param event
- * The event, which should be handled, as an instance of the class {@link MotionEvent}.
- * The event may not be null
- * @return True, if the event has been handled, false otherwise
- */
- public final boolean handleTouchEvent(@NonNull final MotionEvent event) {
- Condition.INSTANCE.ensureNotNull(event, "The event may not be null");
-
- if (!tabSwitcher.isAnimationRunning() && isDraggingAllowed()) {
- onTouchEvent();
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- handleDown(event);
- return true;
- case MotionEvent.ACTION_MOVE:
- if (event.getPointerId(0) == pointerId) {
- if (velocityTracker == null) {
- velocityTracker = VelocityTracker.obtain();
- }
-
- velocityTracker.addMovement(event);
- onDrag(event);
- } else {
- onUp(null);
- handleDown(event);
- }
-
- return true;
- case MotionEvent.ACTION_UP:
- if (event.getPointerId(0) == pointerId) {
- onUp(event);
- }
-
- return true;
- default:
- break;
- }
- }
-
- return false;
- }
-
- @Override
- public final int compare(final AbstractTouchEventHandler o1,
- final AbstractTouchEventHandler o2) {
- int priority1 = o1.getPriority();
- int priority2 = o2.getPriority();
- return priority1 > priority2 ? 1 : (priority1 < priority2 ? -1 : 0);
- }
-
- @Override
- public final int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + getClass().hashCode();
- return result;
- }
-
- @Override
- public final boolean equals(final Object obj) {
- return obj != null && obj.getClass() == getClass();
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/DragGestureEventHandlerFactory.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/DragGestureEventHandlerFactory.java
deleted file mode 100644
index f6c81ab0..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/DragGestureEventHandlerFactory.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.gesture;
-
-import androidx.annotation.NonNull;
-import de.mrapp.android.tabswitcher.DragGesture;
-import de.mrapp.android.tabswitcher.PullDownGesture;
-import de.mrapp.android.tabswitcher.R;
-import de.mrapp.android.tabswitcher.SwipeGesture;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.util.Condition;
-
-/**
- * A factory, which allows to create instances of the class {@link AbstractDragGestureEventHandler}.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public class DragGestureEventHandlerFactory {
-
- /**
- * The tab switcher, the event handler are created for.
- */
- private final TabSwitcher tabSwitcher;
-
- /**
- * Creates a new factory, which allows to create instances of the class {@link
- * AbstractDragGestureEventHandler}.
- *
- * @param tabSwitcher
- * The tab switcher, the event handler should be created for, as an instance of the
- * class {@link TabSwitcher}. The tab switcher may not be null
- */
- public DragGestureEventHandlerFactory(@NonNull final TabSwitcher tabSwitcher) {
- Condition.INSTANCE.ensureNotNull(tabSwitcher, "The tab switcher may not be null");
- this.tabSwitcher = tabSwitcher;
- }
-
- /**
- * Creates and returns the event handler, which corresponds to a specific drag gesture.
- *
- * @param dragGesture
- * The drag gesture, the event handler should be created from, as an instance of the
- * class {@link DragGesture}. The drag gesture may not be null
- * @return The event handler, which has been created, as an instance of the class {@link
- * AbstractTouchEventHandler}. The event handler may not be null
- */
- @NonNull
- public final AbstractTouchEventHandler fromGesture(@NonNull final DragGesture dragGesture) {
- Condition.INSTANCE.ensureNotNull(dragGesture, "The drag gesture may not be null");
-
- if (dragGesture instanceof SwipeGesture) {
- int dragThreshold = dragGesture.getThreshold() != -1 ? dragGesture.getThreshold() :
- tabSwitcher.getResources()
- .getDimensionPixelSize(R.dimen.swipe_gesture_threshold);
- return new SwipeGestureEventHandler(tabSwitcher, dragThreshold,
- dragGesture.getTouchableArea(),
- ((SwipeGesture) dragGesture).getAnimationDuration());
- } else if (dragGesture instanceof PullDownGesture) {
- int dragThreshold = dragGesture.getThreshold() != -1 ? dragGesture.getThreshold() :
- tabSwitcher.getResources()
- .getDimensionPixelSize(R.dimen.pull_down_gesture_threshold);
- return new PullDownGestureEventHandler(tabSwitcher, dragThreshold,
- dragGesture.getTouchableArea());
- }
-
- throw new IllegalArgumentException(
- "Unsupported drag gesture: " + dragGesture.getClass().getSimpleName());
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/PullDownGestureEventHandler.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/PullDownGestureEventHandler.java
deleted file mode 100644
index daa363d0..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/PullDownGestureEventHandler.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.gesture;
-
-import android.graphics.RectF;
-import android.view.MotionEvent;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.android.tabswitcher.Layout;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-
-/**
- * An event handler, which allows to handle pull down gestures, which can be used to show the tab
- * switcher by pulling down the currently selected tab, when using the smartphone layout.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public class PullDownGestureEventHandler extends AbstractDragGestureEventHandler {
-
- /**
- * Defines the interface, a class, which should be notified about the events of a {@link
- * PullDownGestureEventHandler} , must implement.
- */
- public interface Callback {
-
- /**
- * The method, which is notified, when the currently selected tab has been pulled down.
- */
- void onPulledDown();
-
- }
-
- /**
- * The previous drag position.
- */
- private float previousDragPosition;
-
- /**
- * The callback, which is notified about the event handler's events.
- */
- private Callback callback;
-
- /**
- * Notifies the callback, that the currently selected tab has been pulled down.
- */
- private void notifyOnPulledDown() {
- if (callback != null) {
- callback.onPulledDown();
- }
- }
-
- /**
- * Creates a new event handler, which allows to handle pull down gestures, which can be used to
- * show the tab switcher by pulling down the currently selected tab, when using the smartphone
- * layout.
- *
- * @param tabSwitcher
- * The tab switcher, the event handler belongs to, as an instance of the class {@link
- * TabSwitcher}. The tab switcher may not be null
- * @param dragThreshold
- * The threshold of the drag helper, which is used to recognize drag gestures, in pixels
- * as an {@link Integer} value The threshold must be at least 0
- * @param touchableArea
- * The bounds of the onscreen area, the handler should take into consideration for
- * handling touch events, as an instance of the class {@link RectF} or null, if the are
- */
- public PullDownGestureEventHandler(@NonNull final TabSwitcher tabSwitcher,
- final int dragThreshold,
- @Nullable final RectF touchableArea) {
- super(tabSwitcher, dragThreshold, touchableArea);
- this.previousDragPosition = -1;
- this.callback = null;
- }
-
- /**
- * Sets the callback, which should be notified about the event handler's events.
- *
- * @param callback
- * The callback, which should be set, as an instance of the type {@link Callback} or
- * null, if no callback should be notified
- */
- public final void setCallback(@Nullable final Callback callback) {
- this.callback = callback;
- }
-
- @Override
- protected final boolean isDraggingAllowed() {
- return getTabSwitcher().getLayout() != Layout.TABLET &&
- !getTabSwitcher().isSwitcherShown() && getTabSwitcher().getSelectedTab() != null;
- }
-
- @Override
- protected final void onTouchEvent() {
-
- }
-
- @Override
- protected final void onDown(@NonNull final MotionEvent event) {
-
- }
-
- @Override
- protected final void onDrag(@NonNull final MotionEvent event) {
- float dragPosition = event.getY();
-
- if (dragPosition > previousDragPosition) {
- previousDragPosition = dragPosition;
- getDragHelper().update(dragPosition);
-
- if (getDragHelper().hasThresholdBeenReached()) {
- onUp(null);
- notifyOnPulledDown();
- }
- } else {
- getDragHelper().reset();
- previousDragPosition = -1;
- }
- }
-
- @Override
- protected final void onUp(@Nullable final MotionEvent event) {
- previousDragPosition = -1;
- reset();
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/SwipeGestureEventHandler.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/SwipeGestureEventHandler.java
deleted file mode 100644
index cb5f2edf..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/SwipeGestureEventHandler.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.gesture;
-
-import android.content.res.Resources;
-import android.graphics.RectF;
-import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.android.tabswitcher.Layout;
-import de.mrapp.android.tabswitcher.R;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-
-/**
- * An event handler, which allows to handle swipe gestures, which can be used to switch between
- * tabs.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public class SwipeGestureEventHandler extends AbstractDragGestureEventHandler {
-
- /**
- * Defines the interface, a class, which should be notified about the events of a {@link
- * SwipeGestureEventHandler}, must implement.
- */
- public interface Callback {
-
- /**
- * The method, which is invoked, when switching between neighboring tabs.
- *
- * @param selectedTabIndex
- * The index of the currently selected tab as an {@link Integer} value
- * @param distance
- * The distance, the currently selected tab is swiped by, in pixels as a {@link
- * Float} value
- */
- void onSwitchingBetweenTabs(int selectedTabIndex, float distance);
-
- /**
- * The method, which is invoked, when switching between neighboring tabs ended.
- *
- * @param selectedTabIndex
- * The index of the tab, which should become selected, as an {@link Integer} value
- * @param previousSelectedTabIndex
- * The index of the previously selected tab as an {@link Integer} value
- * @param selectionChanged
- * True, if the selection has changed, false otherwise
- * @param velocity
- * The velocity of the swipe gesture in pixels per second as a {@link Float} value
- * @param animationDuration
- * The duration of the swipe animation in milliseconds as a {@link Long} value
- */
- void onSwitchingBetweenTabsEnded(int selectedTabIndex, int previousSelectedTabIndex,
- boolean selectionChanged, float velocity,
- long animationDuration);
-
- }
-
- /**
- * The velocity, which may be reached by a drag gesture at maximum to start a fling animation.
- */
- private final float maxFlingVelocity;
-
- /**
- * The velocity, which must be reached by a drag gesture in order to start a swipe animation.
- */
- private final float minSwipeVelocity;
-
- /**
- * The duration of the swipe animation in milliseconds.
- */
- private final long swipeAnimationDuration;
-
- /**
- * The distance between two neighboring tabs when being swiped in pixels.
- */
- private final int swipedTabDistance;
-
- /**
- * The index of the currently selected tab.
- */
- private int selectedTabIndex;
-
- /**
- * The callback, which is notified about the event handler's events.
- */
- private Callback callback;
-
- /**
- * Returns, whether the threshold of a swiped tab item, which causes the previous or next tab to
- * be selected, has been reached, or not.
- *
- * @return True, if the threshold has been reached, false otherwise
- */
- private boolean isSwipeThresholdReached() {
- return Math.abs(getDragHelper().getDragDistance()) > 4 * swipedTabDistance;
- }
-
- /**
- * Notifies the callback about a swipe gesture, which is used to switch between neighboring
- * tabs.
- *
- * @param selectedTabIndex
- * The index of the currently selected tab as an {@link Integer} value
- * @param distance
- * The distance, the currently selected tab is swiped by, in pixels as a {@link Float}
- * value
- */
- private void notifyOnSwitchingBetweenTabs(final int selectedTabIndex, final float distance) {
- if (callback != null) {
- callback.onSwitchingBetweenTabs(selectedTabIndex, distance);
- }
- }
-
- /**
- * Notifies the callback, that a swipe gesture, which was used to switch between neighboring
- * tabs, has ended.
- *
- * @param selectedTabIndex
- * The index of the tab, which should become selected, as an {@link Integer} value
- * @param previousSelectedTabIndex
- * The index of the previously selected tab as an {@link Integer} value
- * @param selectionChanged
- * True, if the selection has changed, false otherwise
- * @param velocity
- * The velocity of the swipe gesture in pixels per second as a {@link Float} value
- */
- private void notifyOnSwitchingBetweenTabsEnded(final int selectedTabIndex,
- final int previousSelectedTabIndex,
- final boolean selectionChanged,
- final float velocity) {
- if (callback != null) {
- callback.onSwitchingBetweenTabsEnded(selectedTabIndex, previousSelectedTabIndex,
- selectionChanged, velocity, swipeAnimationDuration);
- }
- }
-
- /**
- * Creates a new event handler, which allows to handle swipe gestures, which can be used to
- * switch between tabs.
- *
- * @param tabSwitcher
- * The tab switcher, the event handler belongs to, as an instance of the class {@link
- * TabSwitcher}. The tab switcher may not be null
- * @param dragThreshold
- * The drag threshold in pixels as an {@link Integer} value. The drag threshold must be
- * at least 0
- * @param touchableArea
- * The bounds of the onscreen area, the handler should take into consideration for
- * handling touch events, as an instance of the class {@link RectF} or null, if the are
- * should not be restricted
- * @param animationDuration
- * The duration of the swipe animation in milliseconds as a {@link Long} value or -1, if
- * the default duration should be used
- */
- public SwipeGestureEventHandler(@NonNull final TabSwitcher tabSwitcher, final int dragThreshold,
- @Nullable final RectF touchableArea,
- final long animationDuration) {
- super(tabSwitcher, dragThreshold, touchableArea);
- ViewConfiguration configuration = ViewConfiguration.get(tabSwitcher.getContext());
- this.maxFlingVelocity = configuration.getScaledMaximumFlingVelocity();
- Resources resources = tabSwitcher.getResources();
- this.minSwipeVelocity = resources.getDimensionPixelSize(R.dimen.min_swipe_velocity);
- this.swipeAnimationDuration = animationDuration != -1 ? animationDuration :
- resources.getInteger(R.integer.swipe_animation_duration);
- this.swipedTabDistance = resources.getDimensionPixelSize(R.dimen.swiped_tab_distance);
- this.callback = null;
- this.selectedTabIndex = -1;
- }
-
- /**
- * Sets the callback, which should be notified about the event handler's events.
- *
- * @param callback
- * The callback, which should be set, as an instance of the type {@link Callback} or
- * null, if no callback should be notified
- */
- public final void setCallback(@Nullable final Callback callback) {
- this.callback = callback;
- }
-
- @Override
- protected final boolean isDraggingAllowed() {
- return (getTabSwitcher().getLayout() == Layout.TABLET ||
- !getTabSwitcher().isSwitcherShown()) && getTabSwitcher().getSelectedTab() != null;
- }
-
- @Override
- protected final void onTouchEvent() {
-
- }
-
- @Override
- protected final void onDown(@NonNull final MotionEvent event) {
-
- }
-
- @Override
- protected final void onDrag(@NonNull final MotionEvent event) {
- getDragHelper().update(event.getX());
-
- if (getDragHelper().hasThresholdBeenReached()) {
- if (selectedTabIndex == -1) {
- selectedTabIndex = getTabSwitcher().getSelectedTabIndex();
- }
-
- notifyOnSwitchingBetweenTabs(selectedTabIndex, getDragHelper().getDragDistance());
- }
- }
-
- @Override
- protected final void onUp(@Nullable final MotionEvent event) {
- if (selectedTabIndex != -1) {
- float swipeVelocity = 0;
-
- if (event != null && getVelocityTracker() != null) {
- int pointerId = event.getPointerId(0);
- getVelocityTracker().computeCurrentVelocity(1000, maxFlingVelocity);
- swipeVelocity = Math.abs(getVelocityTracker().getXVelocity(pointerId));
- }
-
- int index = selectedTabIndex;
- boolean selectionChanged = false;
-
- if (swipeVelocity >= minSwipeVelocity || isSwipeThresholdReached()) {
- index = getDragHelper().getDragDistance() > 0 ? selectedTabIndex + 1 :
- selectedTabIndex - 1;
- selectionChanged = true;
- index = Math.max(Math.min(index, getTabSwitcher().getCount() - 1), 0);
- }
-
- notifyOnSwitchingBetweenTabsEnded(index, selectedTabIndex, selectionChanged,
- swipeVelocity >= minSwipeVelocity ? swipeVelocity : 0);
- }
-
- selectedTabIndex = -1;
- reset();
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/TouchEventDispatcher.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/TouchEventDispatcher.java
deleted file mode 100644
index 0923cde3..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/gesture/TouchEventDispatcher.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.gesture;
-
-import android.view.MotionEvent;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.util.Condition;
-import de.mrapp.util.datastructure.ListenerList;
-
-/**
- * A dispatcher, which allows to dispatch touch events to multiple event handlers in the order of
- * their priority. Only the first event handler, which is suited to handle an event, is invoked.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public class TouchEventDispatcher implements Iterable {
-
- /**
- * Defines the interface, a class, which should be notified, when event handlers are added to or
- * removed from a {@link TouchEventDispatcher}, must implement.
- */
- public interface Callback {
-
- /**
- * The method, which is invoked, when an event handler has been added.
- *
- * @param dispatcher
- * The dispatcher, the event handler has been added to, as an instance of the class
- * {@link TouchEventDispatcher}. The dispatcher may not be null
- * @param eventHandler
- * The event handler, which has been added, as an instance of the class {@link
- * AbstractTouchEventHandler}. The event handler may not be null
- */
- void onAddedEventHandler(@NonNull TouchEventDispatcher dispatcher,
- @NonNull AbstractTouchEventHandler eventHandler);
-
- /**
- * The method, which is invoked, when an event handler has been removed.
- *
- * @param dispatcher
- * The dispatcher, the event handler has been removed from, as an instance of the
- * class {@link TouchEventDispatcher}. The dispatcher may not be null
- * @param eventHandler
- * The event handler, which has been removed, as an instance of the class {@link
- * AbstractTouchEventHandler}. The event handler may not be null
- */
- void onRemovedEventHandler(@NonNull TouchEventDispatcher dispatcher,
- @NonNull AbstractTouchEventHandler eventHandler);
-
- }
-
- /**
- * An iterator, which allows to iterate the event handlers of a {@link TouchEventDispatcher}.
- */
- private class EventHandlerIterator implements Iterator {
-
- /**
- * The iterator, which allows to iterate the priorities of the event handlers.
- */
- private Iterator priorityIterator;
-
- /**
- * The iterator, which allows to iterate the event handlers with the current priority.
- */
- private Iterator eventHandlerIterator;
-
- /**
- * Creates a new iterator, which allows to iterate the event handlers of a {@link
- * TouchEventDispatcher}.
- */
- EventHandlerIterator() {
- priorityIterator = eventHandlers.keySet().iterator();
-
- if (priorityIterator.hasNext()) {
- int key = priorityIterator.next();
- ListenerList handlers = eventHandlers.get(key);
- eventHandlerIterator = handlers.iterator();
- } else {
- eventHandlerIterator = null;
- }
- }
-
- @Override
- public boolean hasNext() {
- return (eventHandlerIterator != null && eventHandlerIterator.hasNext()) ||
- priorityIterator.hasNext();
- }
-
- @Override
- public AbstractTouchEventHandler next() {
- if (eventHandlerIterator.hasNext()) {
- return eventHandlerIterator.next();
- } else if (priorityIterator.hasNext()) {
- int key = priorityIterator.next();
- ListenerList handlers = eventHandlers.get(key);
- eventHandlerIterator = handlers.iterator();
- return next();
- }
-
- return null;
- }
-
- }
-
- /**
- * A sorted map, which contains the event handlers, touch events can be dispatched to. The
- * handlers are sorted by decreasing priority.
- */
- private final SortedMap> eventHandlers;
-
- /**
- * A list, which contains the event handlers, which are currently active.
- */
- private final List activeEventHandlers;
-
- /**
- * The event handler, which currently handles a drag gesture.
- */
- private AbstractTouchEventHandler draggingEventHandler;
-
- /**
- * The callback, which is notified, when event handlers are added or removed.
- */
- private Callback callback;
-
- /**
- * Notifies the callback, that an event handler has been added to the dispatcher.
- *
- * @param eventHandler
- * The event handler, which has been added, as an instance of the class {@link
- * AbstractTouchEventHandler}. The event handler may not be null
- */
- private void notifyOnAddedEventHandler(@NonNull final AbstractTouchEventHandler eventHandler) {
- if (callback != null) {
- callback.onAddedEventHandler(this, eventHandler);
- }
- }
-
- /**
- * Notifies the callback, that an event handler has been removed from the dispatcher.
- *
- * @param eventHandler
- * The event handler, which has been removed, as an instance of the class {@link
- * AbstractTouchEventHandler}. The event handler may not be null
- */
- private void notifyOnRemovedEventHandler(
- @NonNull final AbstractTouchEventHandler eventHandler) {
- if (callback != null) {
- callback.onRemovedEventHandler(this, eventHandler);
- }
- }
-
- /**
- * Creates a new dispatcher, which allows to dispatch touch events to multiple event handlers in
- * the order of their priority.
- */
- public TouchEventDispatcher() {
- this.eventHandlers = new TreeMap<>(Collections.reverseOrder());
- this.activeEventHandlers = new ArrayList<>();
- this.draggingEventHandler = null;
- this.callback = null;
- }
-
- /**
- * Sets the callback, which should be notified, when event handlers are added or removed.
- *
- * @param callback
- * The callback, which should be set, as an instance of the type {@link Callback} or
- * null, if no callback should be notified
- */
- public final void setCallback(@Nullable final Callback callback) {
- this.callback = callback;
- }
-
- /**
- * Adds a specific event handler to the dispatcher.
- *
- * @param handler
- * The event handler, which should be added, as an instance of hte class {@link
- * AbstractTouchEventHandler}. The event handler may not be null
- */
- public final void addEventHandler(@NonNull final AbstractTouchEventHandler handler) {
- Condition.INSTANCE.ensureNotNull(handler, "The handler may not be null");
- int key = handler.getPriority();
- ListenerList handlers = eventHandlers.get(key);
-
- if (handlers == null) {
- handlers = new ListenerList<>();
- eventHandlers.put(key, handlers);
- }
-
- handlers.add(handler);
- notifyOnAddedEventHandler(handler);
- }
-
- /**
- * Removes a specific event handler from the dispatcher.
- *
- * @param handler
- * The event handler, which should be removed, as an instance of the class {@link
- * AbstractTouchEventHandler}. The event handler may not be null
- */
- public final void removeEventHandler(@NonNull final AbstractTouchEventHandler handler) {
- Condition.INSTANCE.ensureNotNull(handler, "The handler may not be null");
- ListenerList handlers = eventHandlers.get(handler.getPriority());
-
- if (handlers != null) {
- Iterator iterator = handlers.iterator();
-
- while (iterator.hasNext()) {
- AbstractTouchEventHandler eventHandler = iterator.next();
-
- if (handler.equals(eventHandler)) {
- iterator.remove();
- notifyOnRemovedEventHandler(eventHandler);
- }
- }
- }
-
- for (int i = activeEventHandlers.size() - 1; i >= 0; i--) {
- AbstractTouchEventHandler eventHandler = activeEventHandlers.get(i);
-
- if (handler.equals(eventHandler)) {
- eventHandler.onUp(null);
- activeEventHandlers.remove(i);
- break;
- }
-
- }
-
- if (handler.equals(draggingEventHandler)) {
- draggingEventHandler.onUp(null);
- draggingEventHandler = null;
- }
- }
-
- /**
- * Handles a specific touch event by dispatching it to the first suited event handler.
- *
- * @param event
- * The event, which should be handled, as an instance of the class {@link MotionEvent}.
- * The event may not be null
- * @return True, if the event has been handled, false otherwise
- */
- public final boolean handleTouchEvent(@NonNull final MotionEvent event) {
- Condition.INSTANCE.ensureNotNull(event, "The event may not be null");
- boolean result = false;
-
- if (draggingEventHandler != null) {
- result = draggingEventHandler.handleTouchEvent(event);
-
- if (!result || draggingEventHandler.isReset() || !draggingEventHandler.isDragging()) {
- draggingEventHandler = null;
- }
- }
-
- if (!result) {
- for (int i = activeEventHandlers.size() - 1; i >= 0; i--) {
- AbstractTouchEventHandler handler = activeEventHandlers.get(i);
- boolean handled = handler.handleTouchEvent(event);
-
- if (!handled || handler.isReset()) {
- activeEventHandlers.remove(i);
- } else if (handled && handler.isDragging()) {
- draggingEventHandler = handler;
- activeEventHandlers.remove(i);
-
- for (AbstractTouchEventHandler activeHandler : activeEventHandlers) {
- activeHandler.onUp(null);
- }
-
- activeEventHandlers.clear();
- result = true;
- break;
- }
-
- result |= handled;
- }
- }
-
- if (!result) {
- Iterator iterator = iterator();
- AbstractTouchEventHandler handler;
- int handledPriority = Integer.MIN_VALUE;
-
- while ((handler = iterator.next()) != null &&
- handler.getPriority() >= handledPriority) {
- if (handler.isInsideTouchableArea(event)) {
- boolean handled = handler.handleTouchEvent(event);
-
- if (handled && !handler.isReset()) {
- result = true;
-
- if (handler.isDragging()) {
- draggingEventHandler = handler;
-
- for (AbstractTouchEventHandler activeHandler : activeEventHandlers) {
- activeHandler.onUp(null);
- }
-
- activeEventHandlers.clear();
- break;
- } else {
- activeEventHandlers.add(handler);
- handledPriority = handler.getPriority();
- }
- }
- }
- }
- }
-
- return result;
- }
-
- @Override
- public final Iterator iterator() {
- return new EventHandlerIterator();
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/iterator/AbstractItemIterator.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/iterator/AbstractItemIterator.java
deleted file mode 100644
index 330ee0a4..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/iterator/AbstractItemIterator.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.iterator;
-
-import java.util.Iterator;
-
-import androidx.annotation.NonNull;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.util.Condition;
-
-/**
- * An abstract base class for all iterators, which allow to iterate items of the type {@link
- * AbstractItem}.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public abstract class AbstractItemIterator implements Iterator {
-
- /**
- * An abstract base class of all builders, which allows to configure and create instances of the
- * class {@link AbstractItemIterator}.
- */
- public static abstract class AbstractBuilder, ProductType extends AbstractItemIterator> {
-
- /**
- * True, if the items should be iterated in reverse order, false otherwise.
- */
- protected boolean reverse;
-
- /**
- * The index of the first item, which should be iterated.
- */
- protected int start;
-
- /**
- * Returns a reference to the builder itself. It is implicitly cast to the generic type
- * BuilderType.
- *
- * @return The builder as an instance of the generic type BuilderType
- */
- @SuppressWarnings("unchecked")
- private BuilderType self() {
- return (BuilderType) this;
- }
-
- /**
- * Creates a new builder, which allows to configure and create instances of the class {@link
- * AbstractItemIterator}.
- */
- protected AbstractBuilder() {
- reverse(false);
- start(-1);
- }
-
- /**
- * Creates the iterator, which has been configured by using the builder.
- *
- * @return The iterator, which has been created, as an instance of the class {@link
- * ItemIterator}. The iterator may not be null
- */
- @NonNull
- public abstract ProductType create();
-
- /**
- * Sets, whether the items should be iterated in reverse order, or not.
- *
- * @param reverse
- * True, if the items should be iterated in reverse order, false otherwise
- * @return The builder, this method has been called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public BuilderType reverse(final boolean reverse) {
- this.reverse = reverse;
- return self();
- }
-
- /**
- * Sets the index of the first item, which should be iterated.
- *
- * @param start
- * The index, which should be set, as an {@link Integer} value or -1, if all items
- * should be iterated
- * @return The builder, this method has been called upon, as an instance of the generic type
- * BuilderType. The builder may not be null
- */
- @NonNull
- public BuilderType start(final int start) {
- Condition.INSTANCE.ensureAtLeast(start, -1, "The start must be at least -1");
- this.start = start;
- return self();
- }
-
- }
-
- /**
- * True, if the items should be iterated in reverse order, false otherwise.
- */
- private boolean reverse;
-
- /**
- * The index of the next item.
- */
- private int index;
-
- /**
- * The current item.
- */
- private AbstractItem current;
-
- /**
- * The previous item.
- */
- private AbstractItem previous;
-
- /**
- * The first item.
- */
- private AbstractItem first;
-
- /**
- * The method, which is invoked on subclasses in order to retrieve the total number of available
- * items.
- *
- * @return The total number of available items as an {@link Integer} value
- */
- public abstract int getCount();
-
- /**
- * The method, which is invoked on subclasses in order to retrieve the item, which corresponds
- * to a specific index.
- *
- * @param index
- * The index of the item, which should be returned, as an {@link Integer} value
- * @return The item, which corresponds to the given index, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- */
- @NonNull
- public abstract AbstractItem getItem(final int index);
-
- /**
- * Initializes the iterator.
- *
- * @param reverse
- * True, if the items should be iterated in reverse order, false otherwise
- * @param start
- * The index of the first item, which should be iterated, as an {@link Integer} value or
- * -1, if all items should be iterated
- */
- protected final void initialize(final boolean reverse, final int start) {
- Condition.INSTANCE.ensureAtLeast(start, -1, "The start must be at least -1");
- this.reverse = reverse;
- this.previous = null;
- this.index = start != -1 ? start : (reverse ? getCount() - 1 : 0);
- int previousIndex = reverse ? this.index + 1 : this.index - 1;
-
- if (previousIndex >= 0 && previousIndex < getCount()) {
- this.current = getItem(previousIndex);
- } else {
- this.current = null;
- }
- }
-
- /**
- * Returns the first item. Calling this method does not alter the current position of the
- * iterator.
- *
- * @return The first item as an instance of the class {@link AbstractItem} or null, if no items
- * are available
- */
- public final AbstractItem first() {
- return first;
- }
-
- /**
- * Returns the previous item. Calling this method does not alter the current position of the
- * iterator.
- *
- * @return The previous item as an instance of the class {@link AbstractItem} or null, if no
- * previous item is available
- */
- public final AbstractItem previous() {
- return previous;
- }
-
- /**
- * Returns the next item. Calling this method does not alter the current position of the
- * iterator.
- *
- * @return The next item as an instance of the class {@link AbstractItem} or null, if no next
- * item is available
- */
- public final AbstractItem peek() {
- return index >= 0 && index < getCount() ? getItem(index) : null;
- }
-
- @Override
- public final boolean hasNext() {
- if (reverse) {
- return index >= 0;
- } else {
- return getCount() - index >= 1;
- }
- }
-
- @Override
- public final AbstractItem next() {
- if (hasNext()) {
- previous = current;
-
- if (first == null) {
- first = current;
- }
-
- current = getItem(index);
- index += reverse ? -1 : 1;
- return current;
- }
-
- return null;
- }
-
-}
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/iterator/ArrayItemIterator.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/iterator/ArrayItemIterator.java
deleted file mode 100644
index 70d57aac..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/iterator/ArrayItemIterator.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.iterator;
-
-import androidx.annotation.NonNull;
-import de.mrapp.android.tabswitcher.Tab;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.android.tabswitcher.model.Model;
-import de.mrapp.android.tabswitcher.model.TabItem;
-import de.mrapp.android.util.view.AttachedViewRecycler;
-import de.mrapp.util.Condition;
-
-/**
- * An iterator, which allows to iterate the items, which correspond to the tabs, which are contained
- * by an array.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class ArrayItemIterator extends AbstractItemIterator {
-
- /**
- * A builder, which allows to configure an create instances of the class {@link
- * ArrayItemIterator}.
- */
- public static class Builder extends AbstractBuilder {
-
- /**
- * The model, which belongs to the tab switcher, whose items should be iterated by the
- * iterator, which is created by the builder.
- */
- private final Model model;
-
- /**
- * The view recycler, which allows to inflate the views, which are used to visualize the
- * tabs, which are iterated by the iterator, which is created by the builder.
- */
- private final AttachedViewRecycler viewRecycler;
-
- /**
- * The array, which contains the tabs, which are iterated by the iterator, which is created
- * by the builder.
- */
- private final Tab[] array;
-
- /**
- * The index of the first tab, which is iterated by the iterator, which is created by the
- * builder.
- */
- private final int firstIndex;
-
- /**
- * Creates a new builder, which allows to configure and create instances of the class {@link
- * ArrayItemIterator}.
- *
- * @param model
- * The model, which belongs to the tab switcher, whose items should be iterated by
- * the iterator, which is created by the builder, as an instance of the type {@link
- * Model}. The model may not be null
- * @param viewRecycler
- * The view recycler, which allows to inflate the views, which are used to visualize
- * the tabs, which should be iterated by the iterator, as an instance of the class
- * AttachedViewRecycler. The view recycler may not be null
- * @param array
- * The array, which contains the tabs, which should be iterated by the iterator, as
- * an array of the type {@link Tab}. The array may not be null
- * @param firstIndex
- * The index of the first tab, which should be iterated by the iterator, as an
- * {@link Integer} value. The index must be at least 0
- */
- public Builder(@NonNull final Model model,
- @NonNull final AttachedViewRecycler viewRecycler,
- @NonNull final Tab[] array, final int firstIndex) {
- Condition.INSTANCE.ensureNotNull(model, "The model may not be null");
- Condition.INSTANCE.ensureNotNull(viewRecycler, "The view recycler may not be null");
- Condition.INSTANCE.ensureNotNull(array, "The array may not be null");
- Condition.INSTANCE.ensureAtLeast(firstIndex, 0, "The first index must be at least 0");
- this.model = model;
- this.viewRecycler = viewRecycler;
- this.array = array;
- this.firstIndex = firstIndex;
- }
-
- @NonNull
- @Override
- public ArrayItemIterator create() {
- return new ArrayItemIterator(model, viewRecycler, array, firstIndex, reverse, start);
- }
-
- }
-
- /**
- * The model, which belongs to the tab switcher, whose tabs are iterated.
- */
- private final Model model;
-
- /**
- * The view recycler, which allows to inflate the views, which are used to visualize the
- * iterated tabs.
- */
- private final AttachedViewRecycler viewRecycler;
-
- /**
- * The array, which contains the tabs, which are iterated by the iterator.
- */
- private final Tab[] array;
-
- /**
- * The index of the first tab, which is iterated by the iterator.
- */
- private final int firstIndex;
-
- /**
- * Creates a new iterator, which allows to iterate the items, which correspond to the tabs,
- * which are contained by an array.
- *
- * @param model
- * The model, which belongs to the tab switcher, whose items should be iterated, as an
- * instance of the type {@link Model}. The model may not be null
- * @param viewRecycler
- * The view recycler, which allows to inflate the views, which are used to visualize the
- * iterated tabs, as an instance of the class AttachedViewRecycler. The view recycler
- * may not be null
- * @param array
- * The array, which contains the tabs, which should be iterated by the iterator, as an
- * array of the type {@link Tab}. The array may not be null
- * @param firstIndex
- * The index of the first tab, which should be iterated by the iterator, as an {@link
- * Integer} value. The index must be at least 0
- * @param reverse
- * True, if the items should be iterated in reverse order, false otherwise
- * @param start
- * The index of the first item, which should be iterated, as an {@link Integer} value or
- * -1, if all items should be iterated
- */
- private ArrayItemIterator(@NonNull final Model model,
- @NonNull final AttachedViewRecycler viewRecycler,
- @NonNull final Tab[] array, final int firstIndex,
- final boolean reverse, final int start) {
- Condition.INSTANCE.ensureNotNull(model, "The model may not be null");
- Condition.INSTANCE.ensureNotNull(viewRecycler, "The view recycler may not be null");
- Condition.INSTANCE.ensureNotNull(array, "The array may not be null");
- Condition.INSTANCE.ensureAtLeast(firstIndex, 0, "The first index must be at least 0");
- this.model = model;
- this.viewRecycler = viewRecycler;
- this.array = array;
- this.firstIndex = firstIndex;
- initialize(reverse, start);
- }
-
- @Override
- public final int getCount() {
- return array.length;
- }
-
- @NonNull
- @Override
- public final AbstractItem getItem(final int index) {
- return TabItem.create(model, viewRecycler, firstIndex + index, array[index]);
- }
-
-}
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/iterator/ItemIterator.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/iterator/ItemIterator.java
deleted file mode 100644
index 094d9a16..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/iterator/ItemIterator.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.iterator;
-
-import androidx.annotation.NonNull;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.android.tabswitcher.model.AddTabItem;
-import de.mrapp.android.tabswitcher.model.Model;
-import de.mrapp.android.tabswitcher.model.TabItem;
-import de.mrapp.android.util.view.AttachedViewRecycler;
-import de.mrapp.util.Condition;
-
-/**
- * An iterator, which allows to iterate the items, which correspond to the child views of a {@link
- * TabSwitcher}.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class ItemIterator extends AbstractItemIterator {
-
- /**
- * A builder, which allows to configure and create instances of the class {@link ItemIterator}.
- */
- public static class Builder extends AbstractBuilder {
-
- /**
- * The model, which belongs to the tab switcher, whose items should be iterated by the
- * iterator, which is created by the builder.
- */
- private final Model model;
-
- /**
- * The view recycler, which allows to inflate the views, which are used to visualize the
- * items, which are iterated by the iterator, which is created by the builder.
- */
- private final AttachedViewRecycler viewRecycler;
-
- /**
- * Creates a new builder, which allows to configure and create instances of the class {@link
- * ItemIterator}.
- *
- * @param model
- * The model, which belongs to the tab switcher, whose items should be iterated by
- * the iterator, which is created by the builder, as an instance of the type {@link
- * Model}. The model may not be null
- * @param viewRecycler
- * The view recycler, which allows to inflate the views, which are used to visualize
- * the items, which are iterated by the iterator, which is created by the builder,
- * as an instance of the class AttachedViewRecycler. The view recycler may not be
- * null
- */
- public Builder(@NonNull final Model model,
- @NonNull final AttachedViewRecycler viewRecycler) {
- Condition.INSTANCE.ensureNotNull(model, "The model may not be null");
- Condition.INSTANCE.ensureNotNull(viewRecycler, "The view recycler may not be null");
- this.model = model;
- this.viewRecycler = viewRecycler;
- }
-
- @NonNull
- @Override
- public ItemIterator create() {
- return new ItemIterator(model, viewRecycler, reverse, start);
- }
-
- }
-
- /**
- * The model, which belongs to the tab switcher, whose tabs are iterated.
- */
- private final Model model;
-
- /**
- * The view recycler, which allows to inflated the views, which are used to visualize the
- * iterated items.
- */
- private final AttachedViewRecycler viewRecycler;
-
- /**
- * Creates a new iterator, which allows to iterate the items, which correspond to the child
- * views of a {@link TabSwitcher}.
- *
- * @param model
- * The model, which belongs to the tab switcher, whose items should be iterated, as an
- * instance of the type {@link Model}. The model may not be null
- * @param viewRecycler
- * The view recycler, which allows to inflate the views, which are used to visualize the
- * iterated items, as an instance of the class AttachedViewRecycler. The view recycler
- * may not be null
- * @param reverse
- * True, if the items should be iterated in reverse order, false otherwise
- * @param start
- * The index of the first item, which should be iterated, as an {@link Integer} value or
- * -1, if all items should be iterated
- */
- private ItemIterator(@NonNull final Model model,
- @NonNull final AttachedViewRecycler viewRecycler,
- final boolean reverse, final int start) {
- Condition.INSTANCE.ensureNotNull(model, "The model may not be null");
- Condition.INSTANCE.ensureNotNull(viewRecycler, "The view recycler may not be null");
- this.model = model;
- this.viewRecycler = viewRecycler;
- initialize(reverse, start);
- }
-
- @Override
- public final int getCount() {
- return model.getCount() + (model.isAddTabButtonShown() ? 1 : 0);
- }
-
- @NonNull
- @Override
- public final AbstractItem getItem(final int index) {
- if (index == 0 && model.isAddTabButtonShown()) {
- return AddTabItem.create(viewRecycler);
- } else {
- return TabItem
- .create(model, viewRecycler, index - (model.isAddTabButtonShown() ? 1 : 0));
- }
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractArithmetics.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractArithmetics.java
deleted file mode 100644
index 34f3a4cf..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractArithmetics.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout;
-
-import android.view.ViewPropertyAnimator;
-
-import androidx.annotation.NonNull;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.util.Condition;
-
-/**
- * An abstract base class for all classes, which provide methods, which allow to calculate the
- * position, size and rotation of a {@link TabSwitcher}'s tabs.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public abstract class AbstractArithmetics implements Arithmetics {
-
- /**
- * The tab switcher, the arithmetics are calculated for.
- */
- private final TabSwitcher tabSwitcher;
-
- /**
- * Returns the tab switcher, the arithmetics are calculated for.
- *
- * @return The tab switcher, the arithmetics are calculated for, as an instance of the class
- * {@link TabSwitcher}. The tab switcher may not be null
- */
- @NonNull
- protected final TabSwitcher getTabSwitcher() {
- return tabSwitcher;
- }
-
- /**
- * Creates a new class, which provides methods, which allow to calculate the position, size and
- * rotation of a {@link TabSwitcher}'s tabs.
- *
- * @param tabSwitcher
- * The tab switcher, the arithmetics should be calculated for, as an instance of the
- * class {@link TabSwitcher}. The tab switcher may not be null
- */
- public AbstractArithmetics(@NonNull final TabSwitcher tabSwitcher) {
- Condition.INSTANCE.ensureNotNull(tabSwitcher, "The tab switcher may not be null");
- this.tabSwitcher = tabSwitcher;
- }
-
- @Override
- public final float getTabContainerSize(@NonNull final Axis axis) {
- return getTabContainerSize(axis, true);
- }
-
- @Override
- public final void animatePosition(@NonNull final Axis axis,
- @NonNull final ViewPropertyAnimator animator,
- @NonNull final AbstractItem item, final float position) {
- animatePosition(axis, animator, item, position, false);
- }
-
- @Override
- public final float getScale(@NonNull final AbstractItem item) {
- return getScale(item, false);
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractDragTabsEventHandler.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractDragTabsEventHandler.java
deleted file mode 100644
index 4d292208..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractDragTabsEventHandler.java
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout;
-
-import android.content.res.Resources;
-import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.android.tabswitcher.R;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.gesture.AbstractTouchEventHandler;
-import de.mrapp.android.tabswitcher.layout.Arithmetics.Axis;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.android.tabswitcher.model.TabItem;
-import de.mrapp.android.util.gesture.DragHelper;
-import de.mrapp.util.Condition;
-
-/**
- * An abstract base class for all drag handlers, which allow to calculate the position and state of
- * tabs on touch events.
- *
- * @param
- * The type of the drag handler's callback
- * @author Michael Rapp
- * @since 0.1.0
- */
-public abstract class AbstractDragTabsEventHandler
- extends AbstractTouchEventHandler {
-
- /**
- * Contains all possible states of dragging gestures, which can be performed on a {@link
- * TabSwitcher}.
- */
- public enum DragState {
-
- /**
- * When no dragging gesture is being performed.
- */
- NONE,
-
- /**
- * When the tabs are dragged towards the start.
- */
- DRAG_TO_START,
-
- /**
- * When the tabs are dragged towards the end.
- */
- DRAG_TO_END,
-
- /**
- * When an overshoot at the start is being performed.
- */
- OVERSHOOT_START,
-
- /**
- * When an overshoot at the end is being performed.
- */
- OVERSHOOT_END,
-
- /**
- * When a tab is swiped.
- */
- SWIPE,
-
- /**
- * When the currently selected tab is pulled down.
- */
- PULLING_DOWN
-
- }
-
- /**
- * Defines the interface, a class, which should be notified about the events of a drag handler,
- * must implement.
- */
- public interface Callback {
-
- /**
- * The method, which is invoked in order to calculate the positions of all tabs, depending
- * on the current drag distance.
- *
- * @param dragState
- * The current drag state as a value of the enum {@link DragState}. The drag state
- * must either be {@link DragState#DRAG_TO_END} or {@link DragState#DRAG_TO_START}
- * @param dragDistance
- * The current drag distance in pixels as a {@link Float} value
- * @return A drag state, which specifies whether the tabs are overshooting, or not. If the
- * tabs are overshooting, the drag state must be {@link DragState#OVERSHOOT_START} or {@link
- * DragState#OVERSHOOT_END}, null otherwise
- */
- @Nullable
- DragState onDrag(@NonNull DragState dragState, float dragDistance);
-
- /**
- * The method, which is invoked, when pressing a view has been started.
- *
- * @param item
- * The item, which corresponds to the view, which has been pressed, as an instance
- * of the class {@link AbstractItem}. The item may not be null
- */
- void onPressStarted(@NonNull AbstractItem item);
-
- /**
- * The method, which is invoked, when pressing a view has been ended.
- *
- * @param item
- * Tge item, which corresponds to the view, which was previously pressed, as an
- * instance of the class {@link AbstractItem}. The item may not be null
- */
- void onPressEnded(@NonNull AbstractItem item);
-
- /**
- * The method, which is invoked, when a view has been clicked.
- *
- * @param item
- * The item, which corresponds to the view, which has been clicked, as an instance
- * of the class {@link AbstractItem}. The item may not be null
- */
- void onClick(@NonNull AbstractItem item);
-
- /**
- * The method, which is invoked, when a fling has been triggered.
- *
- * @param distance
- * The distance of the fling in pixels as a {@link Float} value
- * @param duration
- * The duration of the fling in milliseconds as a {@link Long} value
- */
- void onFling(float distance, long duration);
-
- /**
- * The method, which is invoked, when a fling has been cancelled.
- */
- void onCancelFling();
-
- /**
- * The method, which is invoked, when an overshoot at the start should be reverted.
- */
- void onRevertStartOvershoot();
-
- /**
- * The method, which is invoked, when an overshoot at the end should be reverted.
- */
- void onRevertEndOvershoot();
-
- /**
- * The method, which is invoked, when a tab is swiped.
- *
- * @param tabItem
- * The tab item, which corresponds to the swiped tab, as an instance of the class
- * {@link TabItem}. The tab item may not be null
- * @param distance
- * The distance, the tab is swiped by, in pixels as a {@link Float} value
- */
- void onSwipe(@NonNull TabItem tabItem, float distance);
-
- /**
- * The method, which is invoked, when swiping a tab ended.
- *
- * @param tabItem
- * The tab item, which corresponds to the swiped tab, as an instance of the class
- * {@link TabItem}. The tab item may not be null
- * @param remove
- * True, if the tab should be removed, false otherwise
- * @param velocity
- * The velocity of the swipe gesture in pixels per second as a {@link Float} value
- */
- void onSwipeEnded(@NonNull TabItem tabItem, boolean remove, float velocity);
-
- }
-
- /**
- * The arithmetics, which are used to calculate the positions, size and rotation of tabs.
- */
- private final Arithmetics arithmetics;
-
- /**
- * True, if tabs can be swiped on the orthogonal axis, false otherwise.
- */
- private final boolean swipeEnabled;
-
- /**
- * The drag helper, which is used to recognize swipe gestures on the orthogonal axis.
- */
- private final DragHelper swipeDragHelper;
-
- /**
- * The minimum velocity, which must be reached by a drag gesture to start a fling animation.
- */
- private final float minFlingVelocity;
-
- /**
- * The velocity, which may be reached by a drag gesture at maximum to start a fling animation.
- */
- private final float maxFlingVelocity;
-
- /**
- * The velocity, which must be reached by a drag gesture in order to start a swipe animation.
- */
- private final float minSwipeVelocity;
-
- /**
- * The currently swiped tab item.
- */
- private TabItem swipedTabItem;
-
- /**
- * The currently pressed item.
- */
- private AbstractItem pressedItem;
-
- /**
- * The state of the currently performed drag gesture.
- */
- private DragState dragState;
-
- /**
- * The distance of the current drag gesture in pixels.
- */
- private float dragDistance;
-
- /**
- * The drag distance at which the start overshoot begins.
- */
- private float startOvershootThreshold;
-
- /**
- * The drag distance at which the end overshoot begins.
- */
- private float endOvershootThreshold;
-
- /**
- * The callback, which is notified about the drag handler's events.
- */
- private CallbackType callback;
-
- /**
- * Resets the drag handler to its previous state, when a drag gesture has ended.
- */
- private void resetDragging() {
- super.reset();
- this.dragState = DragState.NONE;
- this.swipedTabItem = null;
- this.dragDistance = 0;
- this.startOvershootThreshold = -Float.MAX_VALUE;
- this.endOvershootThreshold = Float.MAX_VALUE;
-
- if (this.swipeDragHelper != null) {
- this.swipeDragHelper.reset();
- }
-
- if (pressedItem != null) {
- notifyOnPressEnded(pressedItem);
- pressedItem = null;
- }
- }
-
- /**
- * Handles a click.
- *
- * @param event
- * The motion event, which triggered the click, as an instance of the class {@link
- * MotionEvent}. The motion event may not be null
- */
- private void handleClick(@NonNull final MotionEvent event) {
- AbstractItem item = getFocusedItem(arithmetics.getTouchPosition(Axis.DRAGGING_AXIS, event));
-
- if (item != null) {
- notifyOnClick(item);
- }
- }
-
- /**
- * Handles a fling gesture.
- *
- * @param event
- * The motion event, which triggered the fling gesture, as an instance of the class
- * {@link MotionEvent}. The motion event may not be null
- * @param dragState
- * The current drag state, which determines the fling direction, as a value of the enum
- * {@link DragState}. The drag state may not be null
- */
- private void handleFling(@NonNull final MotionEvent event, @NonNull final DragState dragState) {
- if (getVelocityTracker() != null) {
- int pointerId = event.getPointerId(0);
- getVelocityTracker().computeCurrentVelocity(1000, maxFlingVelocity);
- float flingVelocity = Math.abs(getVelocityTracker().getYVelocity(pointerId));
-
- if (flingVelocity > minFlingVelocity) {
- float flingDistance = 0.25f * flingVelocity;
-
- if (dragState == DragState.DRAG_TO_START) {
- flingDistance = -1 * flingDistance;
- }
-
- long duration = Math.round(Math.abs(flingDistance) / flingVelocity * 1000);
- notifyOnFling(flingDistance, duration);
- }
- }
- }
-
- /**
- * Handles, when the tabs are overshooting.
- */
- private void handleOvershoot() {
- if (!getDragHelper().isReset()) {
- getDragHelper().reset(0);
- dragDistance = 0;
- }
- }
-
- /**
- * Notifies the callback in order to calculate the positions of all tabs, depending on the
- * current drag distance.
- *
- * @param dragState
- * The current drag state as a value of the enum {@link DragState}. The drag state must
- * either be {@link DragState#DRAG_TO_END} or {@link DragState#DRAG_TO_START}
- * @param dragDistance
- * The current drag distance in pixels as a {@link Float} value
- * @return A drag state, which specifies whether the tabs are overshooting, or not. If the tabs
- * are overshooting, the drag state must be {@link DragState#OVERSHOOT_START} or {@link
- * DragState#OVERSHOOT_END}, null otherwise
- */
- private DragState notifyOnDrag(@NonNull final DragState dragState, final float dragDistance) {
- if (callback != null) {
- return callback.onDrag(dragState, dragDistance);
- }
-
- return null;
- }
-
- /**
- * Notifies the callback, that pressing a view has been started.
- *
- * @param item
- * The item, which corresponds to the view, which has been pressed, as an instance of
- * the class {@link AbstractItem}. The item may not be null
- */
- private void notifyOnPressStarted(@NonNull final AbstractItem item) {
- if (callback != null) {
- callback.onPressStarted(item);
- }
- }
-
- /**
- * Notifies the callback, that pressing a view has been ended.
- *
- * @param item
- * The item, which corresponds to the view, which was previously pressed, as an instance
- * of the class {@link AbstractItem}. The item may not be null
- */
- private void notifyOnPressEnded(@NonNull final AbstractItem item) {
- if (callback != null) {
- callback.onPressEnded(item);
- }
- }
-
- /**
- * Notifies the callback, that a view has been clicked.
- *
- * @param item
- * The item, which corresponds to the view, which has been clicked, as an instance of
- * the class {@link AbstractItem}. The item may not be null
- */
- private void notifyOnClick(@NonNull final AbstractItem item) {
- if (callback != null) {
- callback.onClick(item);
- }
- }
-
- /**
- * Notifies the callback, that a fling has been triggered.
- *
- * @param distance
- * The distance of the fling in pixels as a {@link Float} value
- * @param duration
- * The duration of the fling in milliseconds as a {@link Long} value
- */
- private void notifyOnFling(final float distance, final long duration) {
- if (callback != null) {
- callback.onFling(distance, duration);
- }
- }
-
- /**
- * Notifies the callback, that a fling has been cancelled.
- */
- private void notifyOnCancelFling() {
- if (callback != null) {
- callback.onCancelFling();
- }
- }
-
- /**
- * Notifies the callback, that an overshoot at the start should be reverted.
- */
- private void notifyOnRevertStartOvershoot() {
- if (callback != null) {
- callback.onRevertStartOvershoot();
- }
- }
-
- /**
- * Notifies the callback, that an overshoot at the end should be reverted.
- */
- private void notifyOnRevertEndOvershoot() {
- if (callback != null) {
- callback.onRevertEndOvershoot();
- }
- }
-
- /**
- * Notifies the callback, that a tab is swiped.
- *
- * @param tabItem
- * The tab item, which corresponds to the swiped tab, as an instance of the class {@link
- * TabItem}. The tab item may not be null
- * @param distance
- * The distance, the tab is swiped by, in pixels as a {@link Float} value
- */
- private void notifyOnSwipe(@NonNull final TabItem tabItem, final float distance) {
- if (callback != null) {
- callback.onSwipe(tabItem, distance);
- }
- }
-
- /**
- * Notifies the callback, that swiping a tab ended.
- *
- * @param tabItem
- * The tab item, which corresponds to the swiped tab, as an instance of the class {@link
- * TabItem}. The tab item may not be null
- * @param remove
- * True, if the tab should be removed, false otherwise
- * @param velocity
- * The velocity of the swipe gesture in pixels per second as a {@link Float} value
- */
- private void notifyOnSwipeEnded(@NonNull final TabItem tabItem, final boolean remove,
- final float velocity) {
- if (callback != null) {
- callback.onSwipeEnded(tabItem, remove, velocity);
- }
- }
-
- /**
- * Returns the arithmetics, which are used to calculate the positions, size and rotation of
- * tabs.
- *
- * @return The arithmetics, which are used to calculate the positions, size and rotation of
- * tabs, as an instance of the type {@link Arithmetics}. The arithmetics may not be null
- */
- @NonNull
- protected Arithmetics getArithmetics() {
- return arithmetics;
- }
-
- /**
- * Returns the callback, which should be notified about the drag handler's events.
- *
- * @return The callback, which should be notified about the drag handler's events, as an
- * instance of the generic type CallbackType or null, if no callback should be notified
- */
- @Nullable
- protected CallbackType getCallback() {
- return callback;
- }
-
- /**
- * Creates a new drag handler, which allows to calculate the position and state of tabs on touch
- * events.
- *
- * @param tabSwitcher
- * The tab switcher, whose tabs' positions and states should be calculated by the drag
- * handler, as an instance of the class {@link TabSwitcher}. The tab switcher may not be
- * null
- * @param arithmetics
- * The arithmetics, which should be used to calculate the position, size and rotation of
- * tabs, as an instance of the type {@link Arithmetics}. The arithmetics may not be
- * null
- * @param swipeEnabled
- * True, if tabs can be swiped on the orthogonal axis, false otherwise
- */
- public AbstractDragTabsEventHandler(@NonNull final TabSwitcher tabSwitcher,
- @NonNull final Arithmetics arithmetics,
- final boolean swipeEnabled) {
- super(MIN_PRIORITY, tabSwitcher,
- tabSwitcher.getResources().getDimensionPixelSize(R.dimen.drag_threshold));
- Condition.INSTANCE.ensureNotNull(arithmetics, "The arithmetics may not be null");
- this.arithmetics = arithmetics;
- this.swipeEnabled = swipeEnabled;
- Resources resources = tabSwitcher.getResources();
- this.swipeDragHelper =
- new DragHelper(resources.getDimensionPixelSize(R.dimen.swipe_threshold));
- this.callback = null;
- ViewConfiguration configuration = ViewConfiguration.get(tabSwitcher.getContext());
- this.minFlingVelocity = configuration.getScaledMinimumFlingVelocity();
- this.maxFlingVelocity = configuration.getScaledMaximumFlingVelocity();
- this.minSwipeVelocity = resources.getDimensionPixelSize(R.dimen.min_swipe_velocity);
- resetDragging();
- }
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the item, which
- * corresponds to the view, which is focused when clicking/dragging at a specific position.
- *
- * @param position
- * The position on the dragging axis in pixels as a {@link Float} value
- * @return The item, which corresponds to the focused view, as an instance of the class {@link
- * AbstractItem} or null, if no view is focused
- */
- protected abstract AbstractItem getFocusedItem(final float position);
-
- /**
- * The method, which is invoked on implementing subclasses, when the tabs are overshooting at
- * the start.
- *
- * @param dragPosition
- * The position of the pointer on the dragging axis in pixels as a {@link Float} value
- * @param overshootThreshold
- * The position on the dragging axis, an overshoot at the start currently starts at, in
- * pixels as a {@link Float} value
- * @return The updated position on the dragging axis, an overshoot at the start starts at, in
- * pixels as a {@link Float} value
- */
- protected float onOvershootStart(final float dragPosition, final float overshootThreshold) {
- return overshootThreshold;
- }
-
- /**
- * The method, which is invoked on implementing subclasses, when the tabs are overshooting at
- * the end.
- *
- * @param dragPosition
- * The position of the pointer on the dragging axis in pixels as a {@link Float} value
- * @param overshootThreshold
- * The position on the dragging axis, an overshoot at the end currently starts at, in
- * pixels as a {@link Float} value
- * @return The updated position on the dragging axis, an overshoot at the end starts at, in
- * pixels as a {@link Float} value
- */
- protected float onOvershootEnd(final float dragPosition, final float overshootThreshold) {
- return overshootThreshold;
- }
-
- /**
- * The method, which is invoked on implementing subclasses, when an overshoot has been
- * reverted.
- */
- protected void onOvershootReverted() {
-
- }
-
- /**
- * The method, which invoked on implementing subclasses, when the drag handler has been reset.
- */
- protected void onReset() {
-
- }
-
- /**
- * Returns, whether the threshold of a swiped tab item, which causes the corresponding tab to be
- * removed, has been reached, or not.
- *
- * @param swipedTabItem
- * The swiped tab item as an instance of the class {@link TabItem}. The tab item may not
- * be null
- * @return True, if the threshold has been reached, false otherwise
- */
- protected boolean isSwipeThresholdReached(@NonNull final TabItem swipedTabItem) {
- return false;
- }
-
- /**
- * Sets the callback, which should be notified about the drag handler's events.
- *
- * @param callback
- * The callback, which should be set, as an instance of the generic type CallbackType or
- * null, if no callback should be notified
- */
- public final void setCallback(@Nullable final CallbackType callback) {
- this.callback = callback;
- }
-
- /**
- * Sets the state of the currently performed drag gesture.
- *
- * @param dragState
- * The state, which should be set, as a value of the enum {@link DragState}. The state
- * may not be null
- */
- public final void setDragState(@NonNull final DragState dragState) {
- Condition.INSTANCE.ensureNotNull(dragState, "The drag state may not be null");
- this.dragState = dragState;
- }
-
- /**
- * Handles drag gestures.
- *
- * @param dragPosition
- * The position of the pointer on the dragging axis in pixels as a {@link Float} value
- * @param orthogonalPosition
- * The position of the pointer of the orthogonal axis in pixels as a {@link Float}
- * value
- * @return True, if any tabs have been moved, false otherwise
- */
- public final boolean handleDrag(final float dragPosition, final float orthogonalPosition) {
- if (dragPosition <= startOvershootThreshold) {
- handleOvershoot();
- dragState = DragState.OVERSHOOT_START;
- startOvershootThreshold = onOvershootStart(dragPosition, startOvershootThreshold);
- } else if (dragPosition >= endOvershootThreshold) {
- handleOvershoot();
- dragState = DragState.OVERSHOOT_END;
- endOvershootThreshold = onOvershootEnd(dragPosition, endOvershootThreshold);
- } else {
- onOvershootReverted();
- float previousDistance =
- getDragHelper().isReset() ? 0 : getDragHelper().getDragDistance();
- getDragHelper().update(dragPosition);
-
- if (swipeEnabled) {
- swipeDragHelper.update(orthogonalPosition);
-
- if (dragState == DragState.NONE && swipeDragHelper.hasThresholdBeenReached()) {
- AbstractItem focusedItem =
- getFocusedItem(getDragHelper().getDragStartPosition());
-
- if (focusedItem != null && focusedItem instanceof TabItem) {
- dragState = DragState.SWIPE;
- swipedTabItem = (TabItem) focusedItem;
- }
- }
- }
-
- if (dragState != DragState.SWIPE && getDragHelper().hasThresholdBeenReached()) {
- if (dragState == DragState.OVERSHOOT_START) {
- dragState = DragState.DRAG_TO_END;
- } else if (dragState == DragState.OVERSHOOT_END) {
- dragState = DragState.DRAG_TO_START;
- } else {
- float dragDistance = getDragHelper().getDragDistance();
-
- if (dragDistance == 0) {
- if (dragState != DragState.PULLING_DOWN) {
- dragState = DragState.NONE;
- }
- } else {
- dragState = previousDistance - dragDistance < 0 ? DragState.DRAG_TO_END :
- DragState.DRAG_TO_START;
- }
- }
- }
-
- if (dragState == DragState.SWIPE) {
- notifyOnSwipe(swipedTabItem, swipeDragHelper.getDragDistance());
- } else if (dragState != DragState.NONE) {
- float currentDragDistance = getDragHelper().getDragDistance();
- float distance = currentDragDistance - dragDistance;
- dragDistance = currentDragDistance;
- DragState overshoot = notifyOnDrag(dragState, distance);
-
- if (overshoot == DragState.OVERSHOOT_END && (dragState == DragState.DRAG_TO_END ||
- dragState == DragState.OVERSHOOT_END)) {
- endOvershootThreshold = dragPosition;
- dragState = DragState.OVERSHOOT_END;
- } else if (overshoot == DragState.OVERSHOOT_START &&
- (dragState == DragState.DRAG_TO_START ||
- dragState == DragState.OVERSHOOT_START)) {
- startOvershootThreshold = dragPosition;
- dragState = DragState.OVERSHOOT_START;
- }
-
- return true;
- }
- }
-
- return false;
- }
-
- @Override
- public final boolean isDragging() {
- return super.isDragging() || swipeDragHelper.hasThresholdBeenReached();
- }
-
- @Override
- public final void reset() {
- resetDragging();
- onReset();
- }
-
- @Override
- protected final boolean isDraggingAllowed() {
- return getTabSwitcher().isSwitcherShown() && !getTabSwitcher().isEmpty();
- }
-
- @Override
- protected final void onTouchEvent() {
- notifyOnCancelFling();
- }
-
- @Override
- protected final void onDown(@NonNull final MotionEvent event) {
- pressedItem = getFocusedItem(getArithmetics().getTouchPosition(Axis.DRAGGING_AXIS, event));
-
- if (pressedItem != null) {
- notifyOnPressStarted(pressedItem);
- }
- }
-
- @Override
- protected final void onDrag(@NonNull final MotionEvent event) {
- float dragPosition = arithmetics.getTouchPosition(Axis.DRAGGING_AXIS, event);
- float orthogonalPosition = arithmetics.getTouchPosition(Axis.ORTHOGONAL_AXIS, event);
-
- if (pressedItem != null && !isInsideTouchableArea(event)) {
- notifyOnPressEnded(pressedItem);
- pressedItem = null;
- }
-
- handleDrag(dragPosition, orthogonalPosition);
- }
-
- @Override
- public final void onUp(@Nullable final MotionEvent event) {
- if (dragState == DragState.SWIPE) {
- float swipeVelocity = 0;
-
- if (event != null && getVelocityTracker() != null) {
- int pointerId = event.getPointerId(0);
- getVelocityTracker().computeCurrentVelocity(1000, maxFlingVelocity);
- swipeVelocity = Math.abs(getVelocityTracker().getXVelocity(pointerId));
- }
-
- boolean remove = swipedTabItem.getTab().isCloseable() &&
- (swipeVelocity >= minSwipeVelocity || isSwipeThresholdReached(swipedTabItem));
- notifyOnSwipeEnded(swipedTabItem, remove,
- swipeVelocity >= minSwipeVelocity ? swipeVelocity : 0);
- } else if (dragState == DragState.DRAG_TO_START || dragState == DragState.DRAG_TO_END) {
- if (event != null && getDragHelper().hasThresholdBeenReached()) {
- handleFling(event, dragState);
- }
- } else if (dragState == DragState.OVERSHOOT_END) {
- notifyOnRevertEndOvershoot();
- } else if (dragState == DragState.OVERSHOOT_START) {
- notifyOnRevertStartOvershoot();
- } else if (event != null && dragState != DragState.PULLING_DOWN) {
- handleClick(event);
- }
-
- resetDragging();
- }
-
-}
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractTabRecyclerAdapter.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractTabRecyclerAdapter.java
deleted file mode 100644
index 1e35fadc..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractTabRecyclerAdapter.java
+++ /dev/null
@@ -1,820 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageButton;
-
-import androidx.annotation.CallSuper;
-import androidx.annotation.ColorInt;
-import androidx.annotation.MenuRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.widget.Toolbar;
-import de.mrapp.android.tabswitcher.Animation;
-import de.mrapp.android.tabswitcher.Layout;
-import de.mrapp.android.tabswitcher.R;
-import de.mrapp.android.tabswitcher.Tab;
-import de.mrapp.android.tabswitcher.TabCloseListener;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.TabSwitcherDecorator;
-import de.mrapp.android.tabswitcher.iterator.AbstractItemIterator;
-import de.mrapp.android.tabswitcher.iterator.ItemIterator;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.android.tabswitcher.model.Model;
-import de.mrapp.android.tabswitcher.model.State;
-import de.mrapp.android.tabswitcher.model.TabItem;
-import de.mrapp.android.tabswitcher.model.TabSwitcherModel;
-import de.mrapp.android.tabswitcher.model.TabSwitcherStyle;
-import de.mrapp.android.util.logging.LogLevel;
-import de.mrapp.android.util.view.AbstractViewRecycler;
-import de.mrapp.android.util.view.AttachedViewRecycler;
-import de.mrapp.util.Condition;
-
-/**
- * An abstract base class for all view recycler adapters, which allow to inflate the views, which
- * are used to visualize the tabs of a {@link TabSwitcher}.
- *
- * @author Michael Rapp
- * @since 1.0.0
- */
-public abstract class AbstractTabRecyclerAdapter
- extends AbstractViewRecycler.Adapter
- implements Tab.Callback, Model.Listener {
-
- /**
- * The view type of a tab.
- */
- private static final int TAB_VIEW_TYPE = 0;
-
- /**
- * The tab switcher, the tabs belong to.
- */
- private final TabSwitcher tabSwitcher;
-
- /**
- * The model, which belongs to the tab switcher.
- */
- private final TabSwitcherModel model;
-
- /*
- * The style, which allows to retrieve style attributes of the tab switcher.
- */
- private final TabSwitcherStyle style;
-
- /**
- * The view recycler, the adapter is bound to.
- */
- private AttachedViewRecycler viewRecycler;
-
- /**
- * Adapts the title of a tab.
- *
- * @param tabItem
- * The tab item, which corresponds to the tab, whose title should be adapted, as an
- * instance of the class {@link TabItem}. The tab item may not be null
- */
- private void adaptTitle(@NonNull final TabItem tabItem) {
- Tab tab = tabItem.getTab();
- AbstractTabViewHolder viewHolder = tabItem.getViewHolder();
- viewHolder.titleTextView.setText(tab.getTitle());
- }
-
- /**
- * Adapts the icon of a tab.
- *
- * @param tabItem
- * The tab item, which corresponds to the tab, whose icon should be adapted, as an
- * instance of the class {@link TabItem}. The tab item may not be null
- */
- private void adaptIcon(@NonNull final TabItem tabItem) {
- Tab tab = tabItem.getTab();
- AbstractTabViewHolder viewHolder = tabItem.getViewHolder();
- Drawable icon = style.getTabIcon(tab);
- viewHolder.iconImageView.setImageDrawable(icon);
- }
-
- /**
- * Adapts the visibility of a tab's close button.
- *
- * @param tabItem
- * The tab item, which corresponds to the tab, whose close button should be adapted, as
- * an instance of the class {@link TabItem}. The tab item may not be null
- */
- private void adaptCloseButtonVisibility(@NonNull final TabItem tabItem) {
- Tab tab = tabItem.getTab();
- AbstractTabViewHolder viewHolder = tabItem.getViewHolder();
- viewHolder.closeButton.setVisibility(tab.isCloseable() ? View.VISIBLE : View.GONE);
- viewHolder.closeButton.setTag(R.id.tag_visibility, tab.isCloseable());
- viewHolder.closeButton.setOnClickListener(
- tab.isCloseable() ? createCloseButtonClickListener(viewHolder.closeButton, tab) :
- null);
- }
-
- /**
- * Adapts the icon of a tab's close button.
- *
- * @param tabItem
- * The tab item, which corresponds to the tab, whose close button icon should be
- * adapted, as an instance of the class {@link TabItem}. The tab item may not be null
- */
- private void adaptCloseButtonIcon(@NonNull final TabItem tabItem) {
- Tab tab = tabItem.getTab();
- Drawable icon = style.getTabCloseButtonIcon(tab);
- AbstractTabViewHolder viewHolder = tabItem.getViewHolder();
- viewHolder.closeButton.setImageDrawable(icon);
- }
-
- /**
- * Adapts the background color of a tab.
- *
- * @param tabItem
- * The tab item, which corresponds to the tab, whose background should be adapted, as an
- * instance of the class {@link TabItem}. The tab item may not be null
- */
- private void adaptBackgroundColor(@NonNull final TabItem tabItem) {
- Tab tab = tabItem.getTab();
- ColorStateList colorStateList = style.getTabBackgroundColor(tab);
- int[] stateSet = model.getSelectedTab() == tab ? new int[]{android.R.attr.state_selected} :
- new int[]{};
- int color = colorStateList.getColorForState(stateSet, colorStateList.getDefaultColor());
- View view = tabItem.getView();
- Drawable background = view.getBackground();
- background.setColorFilter(color, PorterDuff.Mode.MULTIPLY);
- onAdaptBackgroundColor(color, tabItem);
- }
-
- /**
- * Adapts the text color of a tab's title.
- *
- * @param tabItem
- * The tab item, which corresponds to the tab, whose title should be adapted, as an
- * instance of the class {@link TabItem}. The tab item may not be null
- */
- private void adaptTitleTextColor(@NonNull final TabItem tabItem) {
- Tab tab = tabItem.getTab();
- ColorStateList colorStateList = style.getTabTitleTextColor(tab);
- AbstractTabViewHolder viewHolder = tabItem.getViewHolder();
- viewHolder.titleTextView.setTextColor(colorStateList);
- }
-
- /**
- * Adapts the visibility of a tab's progress bar.
- *
- * @param tabItem
- * The tab item, which corresponds to the tab, whose progress bar should be adapted, as
- * an instance of the class {@link TabItem}. The tab item may not be null
- */
- private void adaptProgressBarVisibility(@NonNull final TabItem tabItem) {
- Tab tab = tabItem.getTab();
- AbstractTabViewHolder viewHolder = tabItem.getViewHolder();
- viewHolder.progressBar.setVisibility(tab.isProgressBarShown() ? View.VISIBLE : View.GONE);
- viewHolder.iconImageView.setVisibility(tab.isProgressBarShown() ? View.GONE : View.VISIBLE);
- }
-
- /**
- * Adapts the color of a tab's progress bar.
- *
- * @param tabItem
- * The tab item, which corresponds to the tab, whose progress bar should be adapted, as
- * an instance of the class {@link TabItem}. The tab item may not be null
- */
- private void adaptProgressBarColor(@NonNull final TabItem tabItem) {
- Tab tab = tabItem.getTab();
- AbstractTabViewHolder viewHolder = tabItem.getViewHolder();
- int color = style.getTabProgressBarColor(tab);
- viewHolder.progressBar.setColor(color);
- }
-
- /**
- * Adapts the selection state of a tab's views.
- *
- * @param tabItem
- * The tab item, which corresponds to the tab, whose selection state should be adapted,
- * as an instance of the class {@link TabItem}. The tab item may not be null
- */
- private void adaptSelectionState(@NonNull final TabItem tabItem) {
- boolean selected = model.getSelectedTab() == tabItem.getTab();
- tabItem.getView().setSelected(selected);
- AbstractTabViewHolder viewHolder = tabItem.getViewHolder();
- viewHolder.titleTextView.setSelected(selected);
- viewHolder.closeButton.setSelected(selected);
- }
-
- /**
- * Adapts the appearance of all currently inflated tabs, depending on whether they are currently
- * selected, or not.
- */
- private void adaptAllSelectionStates() {
- AbstractItemIterator iterator =
- new ItemIterator.Builder(model, getViewRecyclerOrThrowException()).create();
- AbstractItem item;
-
- while ((item = iterator.next()) != null) {
- if (item.isInflated() && item instanceof TabItem) {
- TabItem tabItem = (TabItem) item;
- adaptSelectionState(tabItem);
- adaptBackgroundColor(tabItem);
- }
- }
- }
-
- /**
- * Creates and returns a listener, which allows to close a specific tab, when its close button
- * is clicked.
- *
- * @param closeButton
- * The tab's close button as an instance of the class {@link ImageButton}. The button
- * may not be null
- * @param tab
- * The tab, which should be closed, as an instance of the class {@link Tab}. The tab may
- * not be null
- * @return The listener, which has been created, as an instance of the class {@link
- * View.OnClickListener}. The listener may not be null
- */
- @NonNull
- private View.OnClickListener createCloseButtonClickListener(
- @NonNull final ImageButton closeButton, @NonNull final Tab tab) {
- return new View.OnClickListener() {
-
- @Override
- public void onClick(final View v) {
- TabItem tabItem = getTabItem(tab);
-
- if (tabItem != null) {
- State state = tabItem.getTag().getState();
-
- if (state == State.FLOATING || state == State.STACKED_START_ATOP) {
- if (notifyOnCloseTab(tab)) {
- closeButton.setOnClickListener(null);
- tabSwitcher.removeTab(tab);
- }
- }
- }
- }
-
- };
- }
-
- /**
- * Notifies all listeners, that a tab is about to be closed by clicking its close button.
- *
- * @param tab
- * The tab, which is about to be closed, as an instance of the class {@link Tab}. The
- * tab may not be null
- * @return True, if the tab should be closed, false otherwise
- */
- private boolean notifyOnCloseTab(@NonNull final Tab tab) {
- boolean result = true;
-
- for (TabCloseListener listener : model.getTabCloseListeners()) {
- result &= listener.onCloseTab(tabSwitcher, tab);
- }
-
- return result;
- }
-
- /**
- * Returns the tab switcher, which contains the tabs.
- *
- * @return The tab switcher, which contains the tabs, as an instance of the class {@link
- * TabSwitcher}. The tab switcher may not be null
- */
- @NonNull
- protected final TabSwitcher getTabSwitcher() {
- return tabSwitcher;
- }
-
- /**
- * Returns the model of the tab switcher.
- *
- * @return The model of the tab switcher as an instance of the class {@link TabSwitcherModel}.
- * The model may not be null
- */
- @NonNull
- protected final TabSwitcherModel getModel() {
- return model;
- }
-
- /**
- * Returns the style, which allow to retrieve style attributes of the tab switcher.
- *
- * @return The style, which allows to retrieve style attributes of the tab switcher, as an
- * instance of the class {@link TabSwitcherStyle}. The style may not be null
- */
- @NonNull
- protected final TabSwitcherStyle getStyle() {
- return style;
- }
-
- /**
- * Returns the tab item, which corresponds to a specific tab.
- *
- * @param tab
- * The tab, whose tab item should be returned, as an instance of the class {@link Tab}.
- * The tab may not be null
- * @return The tab item, which corresponds to the given tab, as an instance of the class {@link
- * TabItem} or null, if no view, which visualizes the tab, is currently inflated
- */
- @Nullable
- protected final TabItem getTabItem(@NonNull final Tab tab) {
- int index = model.indexOf(tab);
-
- if (index != -1) {
- TabItem tabItem = TabItem.create(model, getViewRecyclerOrThrowException(), index);
-
- if (tabItem.isInflated()) {
- return tabItem;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the view recycler, the adapter is bound to, or throws an {@link
- * IllegalStateException}, if no view recycler has been set.
- *
- * @return The view recycler, the adapter is bound to, as an instance of the class
- * AttachedViewRecycler. The view recycler may not be null
- */
- @NonNull
- protected final AttachedViewRecycler getViewRecyclerOrThrowException() {
- Condition.INSTANCE.ensureNotNull(viewRecycler, "No view recycler has been set",
- IllegalStateException.class);
- return viewRecycler;
- }
-
- /**
- * The method, which is invoked on implementing subclasses, when the background color of a tab
- * has been changed.
- *
- * @param color
- * The color, which has been set, as an {@link Integer} value
- * @param tabItem
- * The tab item, which corresponds to the tab, whose background color has been changed,
- * as an instance of the class {@link TabItem}. The tab item may not be null
- */
- protected void onAdaptBackgroundColor(@ColorInt final int color,
- @NonNull final TabItem tabItem) {
-
- }
-
- /**
- * The method, which is invoked on implementing subclasses in order to inflate the view, which
- * is used to visualize tabs.
- *
- * @param inflater
- * The layout inflater, which should be used, as an instance of the class {@link
- * LayoutInflater}. The layout inflater may not be null
- * @param parent
- * The parent of the view, which should be inflated, as an instance of the class {@link
- * ViewGroup} or null, if no parent is available
- * @param viewHolder
- * The view holder, which should hold references to the child views of the view, which
- * should be inflated, as an instance of the class {@link AbstractTabViewHolder}. The
- * view holder may not be null
- * @return The view, which has been inflated, as an instance of the class {@link View}. The view
- * may not be null
- */
- @NonNull
- protected abstract View onInflateTabView(@NonNull final LayoutInflater inflater,
- @Nullable final ViewGroup parent,
- @NonNull final AbstractTabViewHolder viewHolder);
-
- /**
- * The method, which is invoked on implementing subclasses in order to adapt the appearance of a
- * view, which is used to visualize a tab.
- *
- * @param view
- * The view, which is used to visualize the tab, as an instance of the class {@link
- * View}. The view may not be null
- * @param tabItem
- * The tab item, which corresponds to the tab, which is visualized by the given view, as
- * an instance of the class {@link TabItem}. The tab item may not be null
- * @param params
- * An array, which may contain optional parameters, as an array of the generic type
- * ParamType or an empty array, if no optional parameters are available
- */
- @SuppressWarnings("unchecked")
- protected abstract void onShowTabView(@NonNull final View view, @NonNull final TabItem tabItem,
- @NonNull final Integer... params);
-
- /**
- * The method, which is invoked on implementing subclasses in order to create the view holder,
- * which should be associated with an inflated view.
- *
- * @return The view holder, which has been created, as an instance of the class {@link
- * AbstractTabViewHolder}. The view holder may not be null
- */
- @NonNull
- protected abstract AbstractTabViewHolder onCreateTabViewHolder();
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the layout,
- * which is used by the tab switcher.
- *
- * @return The layout, which is used by the tab switcher, as a value of the enum {@link Layout}.
- * The layout may not be null
- */
- @NonNull
- protected abstract Layout getLayout();
-
- /**
- * Creates a new view recycler adapter, which allows to inflate the views, which are used to
- * visualize the tabs of a {@link TabSwitcher}.
- *
- * @param tabSwitcher
- * The tab switcher as an instance of the class {@link TabSwitcher}. The tab switcher
- * may not be null
- * @param model
- * The model, which belongs to the tab switcher, as an instance of the class {@link
- * TabSwitcherModel}. The model may not be null
- * @param style
- * The style, which allows to retrieve style attributes of the tab switcher switcher, as
- * an instance of the class {@link TabSwitcherStyle}. The style may not be null
- */
- public AbstractTabRecyclerAdapter(@NonNull final TabSwitcher tabSwitcher,
- @NonNull final TabSwitcherModel model,
- @NonNull final TabSwitcherStyle style) {
- Condition.INSTANCE.ensureNotNull(tabSwitcher, "The tab switcher may not be null");
- Condition.INSTANCE.ensureNotNull(model, "The model may not be null");
- Condition.INSTANCE.ensureNotNull(style, "The style may not be null");
- this.tabSwitcher = tabSwitcher;
- this.model = model;
- this.style = style;
- this.viewRecycler = null;
- }
-
- /**
- * Sets the view recycler, which allows to inflate the views, which are used to visualize tabs.
- *
- * @param viewRecycler
- * The view recycler, which should be set, as an instance of the class
- * AttachedViewRecycler. The view recycler may not be null
- */
- public final void setViewRecycler(
- @NonNull final AttachedViewRecycler viewRecycler) {
- Condition.INSTANCE.ensureNotNull(viewRecycler, "The view recycler may not be null");
- this.viewRecycler = viewRecycler;
- }
-
- @Override
- public void onLogLevelChanged(@NonNull final LogLevel logLevel) {
-
- }
-
- @Override
- public final void onDecoratorChanged(@NonNull final TabSwitcherDecorator decorator) {
-
- }
-
- @Override
- public final void onSwitcherShown() {
-
- }
-
- @Override
- public final void onSwitcherHidden() {
-
- }
-
- @Override
- public final void onSelectionChanged(final int previousIndex, final int index,
- @Nullable final Tab selectedTab,
- final boolean switcherHidden) {
- adaptAllSelectionStates();
- }
-
- @Override
- public final void onTabAdded(final int index, @NonNull final Tab tab,
- final int previousSelectedTabIndex, final int selectedTabIndex,
- final boolean selectionChanged,
- final boolean switcherVisibilityChanged,
- @NonNull final Animation animation) {
- if (selectionChanged) {
- adaptAllSelectionStates();
- }
- }
-
- @Override
- public final void onAllTabsAdded(final int index, @NonNull final Tab[] tabs,
- final int previousSelectedTabIndex, final int selectedTabIndex,
- final boolean selectionChanged,
- @NonNull final Animation animation) {
- if (selectionChanged) {
- adaptAllSelectionStates();
- }
- }
-
- @Override
- public final void onTabRemoved(final int index, @NonNull final Tab tab,
- final int previousSelectedTabIndex, final int selectedTabIndex,
- final boolean selectionChanged,
- @NonNull final Animation animation) {
- if (selectionChanged) {
- adaptAllSelectionStates();
- }
- }
-
- @Override
- public final void onAllTabsRemoved(@NonNull final Tab[] tabs,
- @NonNull final Animation animation) {
-
- }
-
- @Override
- public void onPaddingChanged(final int left, final int top, final int right, final int bottom) {
-
- }
-
- @Override
- public void onApplyPaddingToTabsChanged(final boolean applyPaddingToTabs) {
-
- }
-
- @Override
- public final void onTabIconChanged(@Nullable final Drawable icon) {
- ItemIterator iterator =
- new ItemIterator.Builder(model, getViewRecyclerOrThrowException()).create();
- AbstractItem item;
-
- while ((item = iterator.next()) != null) {
- if (item.isInflated() && item instanceof TabItem) {
- adaptIcon((TabItem) item);
- }
- }
- }
-
- @CallSuper
- @Override
- public void onTabBackgroundColorChanged(@Nullable final ColorStateList colorStateList) {
- ItemIterator iterator =
- new ItemIterator.Builder(model, getViewRecyclerOrThrowException()).create();
- AbstractItem item;
-
- while ((item = iterator.next()) != null) {
- if (item.isInflated() && item instanceof TabItem) {
- adaptBackgroundColor((TabItem) item);
- }
- }
- }
-
- @Override
- public void onTabContentBackgroundColorChanged(@ColorInt final int color) {
-
- }
-
- @Override
- public final void onTabTitleColorChanged(@Nullable final ColorStateList colorStateList) {
- ItemIterator iterator =
- new ItemIterator.Builder(model, getViewRecyclerOrThrowException()).create();
- AbstractItem item;
-
- while ((item = iterator.next()) != null) {
- if (item.isInflated() && item instanceof TabItem) {
- adaptTitleTextColor((TabItem) item);
- }
- }
- }
-
- @Override
- public final void onTabCloseButtonIconChanged(@Nullable final Drawable icon) {
- ItemIterator iterator =
- new ItemIterator.Builder(model, getViewRecyclerOrThrowException()).create();
- AbstractItem item;
-
- while ((item = iterator.next()) != null) {
- if (item.isInflated() && item instanceof TabItem) {
- adaptCloseButtonIcon((TabItem) item);
- }
- }
- }
-
- @Override
- public final void onTabProgressBarColorChanged(@ColorInt final int color) {
- ItemIterator iterator =
- new ItemIterator.Builder(model, getViewRecyclerOrThrowException()).create();
- AbstractItem item;
-
- while ((item = iterator.next()) != null) {
- if (item.isInflated() && item instanceof TabItem) {
- adaptProgressBarColor((TabItem) item);
- }
- }
- }
-
- @Override
- public final void onAddTabButtonVisibilityChanged(final boolean visible) {
-
- }
-
- @Override
- public void onAddTabButtonColorChanged(@Nullable final ColorStateList colorStateList) {
-
- }
-
- @Override
- public final void onToolbarVisibilityChanged(final boolean visible) {
-
- }
-
- @Override
- public final void onToolbarTitleChanged(@Nullable final CharSequence title) {
-
- }
-
- @Override
- public final void onToolbarNavigationIconChanged(@Nullable final Drawable icon,
- @Nullable final View.OnClickListener listener) {
-
- }
-
- @Override
- public final void onToolbarMenuInflated(@MenuRes final int resourceId,
- @Nullable final Toolbar.OnMenuItemClickListener listener) {
-
- }
-
- @Override
- public final void onEmptyViewChanged(@Nullable final View view, final long animationDuration) {
-
- }
-
- @Override
- public final void onTitleChanged(@NonNull final Tab tab) {
- TabItem tabItem = getTabItem(tab);
-
- if (tabItem != null) {
- adaptTitle(tabItem);
- }
- }
-
- @Override
- public final void onIconChanged(@NonNull final Tab tab) {
- TabItem tabItem = getTabItem(tab);
-
- if (tabItem != null) {
- adaptIcon(tabItem);
- }
- }
-
- @Override
- public final void onCloseableChanged(@NonNull final Tab tab) {
- TabItem tabItem = getTabItem(tab);
-
- if (tabItem != null) {
- adaptCloseButtonVisibility(tabItem);
- }
- }
-
- @Override
- public final void onCloseButtonIconChanged(@NonNull final Tab tab) {
- TabItem tabItem = getTabItem(tab);
-
- if (tabItem != null) {
- adaptCloseButtonIcon(tabItem);
- }
- }
-
- @Override
- public final void onBackgroundColorChanged(@NonNull final Tab tab) {
- TabItem tabItem = getTabItem(tab);
-
- if (tabItem != null) {
- adaptBackgroundColor(tabItem);
- }
- }
-
- @Override
- public void onContentBackgroundColorChanged(@NonNull final Tab tab) {
-
- }
-
- @Override
- public final void onTitleTextColorChanged(@NonNull final Tab tab) {
- TabItem tabItem = getTabItem(tab);
-
- if (tabItem != null) {
- adaptTitleTextColor(tabItem);
- }
- }
-
- @Override
- public final void onProgressBarVisibilityChanged(@NonNull final Tab tab) {
- TabItem tabItem = getTabItem(tab);
-
- if (tabItem != null) {
- adaptProgressBarVisibility(tabItem);
- }
- }
-
- @Override
- public final void onProgressBarColorChanged(@NonNull final Tab tab) {
- TabItem tabItem = getTabItem(tab);
-
- if (tabItem != null) {
- adaptProgressBarColor(tabItem);
- }
- }
-
- @CallSuper
- @Override
- public int getViewType(@NonNull final AbstractItem item) {
- if (item instanceof TabItem) {
- return TAB_VIEW_TYPE;
- } else {
- throw new IllegalArgumentException("Unknown item type");
- }
- }
-
- @SuppressWarnings("unchecked")
- @CallSuper
- @NonNull
- @Override
- public View onInflateView(@NonNull final LayoutInflater inflater,
- @Nullable final ViewGroup parent, @NonNull final AbstractItem item,
- final int viewType, @NonNull final Integer... params) {
- if (viewType == TAB_VIEW_TYPE) {
- TabItem tabItem = (TabItem) item;
- AbstractTabViewHolder viewHolder = onCreateTabViewHolder();
- View view = onInflateTabView(inflater, parent, viewHolder);
- viewHolder.titleContainer = view.findViewById(R.id.tab_title_container);
- viewHolder.titleTextView = view.findViewById(R.id.tab_title_text_view);
- viewHolder.iconImageView = view.findViewById(R.id.tab_icon_image_view);
- viewHolder.progressBar = view.findViewById(R.id.tab_progress_bar);
- viewHolder.closeButton = view.findViewById(R.id.close_tab_button);
- view.setTag(R.id.tag_view_holder, viewHolder);
- tabItem.setViewHolder(viewHolder);
- item.setView(view);
- view.setTag(R.id.tag_properties, item.getTag());
- return view;
- } else {
- throw new IllegalArgumentException("Unknown view type");
- }
- }
-
- @SuppressWarnings("unchecked")
- @CallSuper
- @Override
- public void onShowView(@NonNull final Context context, @NonNull final View view,
- @NonNull final AbstractItem item, final boolean inflated,
- @NonNull final Integer... params) {
- if (item instanceof TabItem) {
- TabItem tabItem = (TabItem) item;
- AbstractTabViewHolder viewHolder =
- (AbstractTabViewHolder) view.getTag(R.id.tag_view_holder);
-
- if (!tabItem.isInflated()) {
- tabItem.setView(view);
- tabItem.setViewHolder(viewHolder);
- view.setTag(R.id.tag_properties, tabItem.getTag());
- }
-
- Tab tab = tabItem.getTab();
- tab.addCallback(this);
- adaptTitle(tabItem);
- adaptIcon(tabItem);
- adaptProgressBarVisibility(tabItem);
- adaptCloseButtonVisibility(tabItem);
- adaptCloseButtonIcon(tabItem);
- adaptBackgroundColor(tabItem);
- adaptTitleTextColor(tabItem);
- adaptSelectionState(tabItem);
- onShowTabView(view, tabItem, params);
- } else {
- throw new IllegalArgumentException("Unknown item type");
- }
- }
-
- @CallSuper
- @Override
- public void onRemoveView(@NonNull final View view, @NonNull final AbstractItem item) {
- if (item instanceof TabItem) {
- TabItem tabItem = (TabItem) item;
- Tab tab = tabItem.getTab();
- tab.removeCallback(this);
- view.setTag(R.id.tag_properties, null);
- } else {
- throw new IllegalArgumentException("Unknown item type");
- }
- }
-
-}
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractTabSwitcherLayout.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractTabSwitcherLayout.java
deleted file mode 100644
index 79d3e2b1..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractTabSwitcherLayout.java
+++ /dev/null
@@ -1,1690 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout;
-
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.animation.Animation;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Transformation;
-
-import androidx.annotation.CallSuper;
-import androidx.annotation.ColorInt;
-import androidx.annotation.MenuRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.widget.Toolbar;
-import androidx.appcompat.widget.Toolbar.OnMenuItemClickListener;
-import androidx.core.util.Pair;
-import de.mrapp.android.tabswitcher.AddTabButtonListener;
-import de.mrapp.android.tabswitcher.R;
-import de.mrapp.android.tabswitcher.Tab;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.TabSwitcherDecorator;
-import de.mrapp.android.tabswitcher.gesture.AbstractTouchEventHandler;
-import de.mrapp.android.tabswitcher.gesture.PullDownGestureEventHandler;
-import de.mrapp.android.tabswitcher.gesture.SwipeGestureEventHandler;
-import de.mrapp.android.tabswitcher.gesture.TouchEventDispatcher;
-import de.mrapp.android.tabswitcher.iterator.AbstractItemIterator;
-import de.mrapp.android.tabswitcher.iterator.ItemIterator;
-import de.mrapp.android.tabswitcher.layout.AbstractDragTabsEventHandler.DragState;
-import de.mrapp.android.tabswitcher.layout.Arithmetics.Axis;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.android.tabswitcher.model.AddTabItem;
-import de.mrapp.android.tabswitcher.model.Model;
-import de.mrapp.android.tabswitcher.model.State;
-import de.mrapp.android.tabswitcher.model.TabItem;
-import de.mrapp.android.tabswitcher.model.TabSwitcherModel;
-import de.mrapp.android.tabswitcher.model.TabSwitcherStyle;
-import de.mrapp.android.util.ViewUtil;
-import de.mrapp.android.util.logging.LogLevel;
-import de.mrapp.android.util.logging.Logger;
-import de.mrapp.android.util.view.AbstractViewRecycler;
-import de.mrapp.android.util.view.AttachedViewRecycler;
-import de.mrapp.util.Condition;
-
-/**
- * An abstract base class for all layouts, which implement the functionality of a {@link
- * TabSwitcher}.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public abstract class AbstractTabSwitcherLayout
- implements TabSwitcherLayout, OnGlobalLayoutListener, Model.Listener,
- TouchEventDispatcher.Callback, AbstractDragTabsEventHandler.Callback,
- SwipeGestureEventHandler.Callback, PullDownGestureEventHandler.Callback {
-
- /**
- * Defines the interface, a class, which should be notified about the events of a tab switcher
- * layout, must implement.
- */
- public interface Callback {
-
- /*
- * The method, which is invoked, when all animations have been ended.
- */
- void onAnimationsEnded();
-
- }
-
- /**
- * A layout listener, which unregisters itself from the observed view, when invoked. The
- * listener allows to encapsulate another listener, which is notified, when the listener is
- * invoked.
- */
- public static class LayoutListenerWrapper implements OnGlobalLayoutListener {
-
- /**
- * The observed view.
- */
- private final View view;
-
- /**
- * The encapsulated listener.
- */
- private final OnGlobalLayoutListener listener;
-
- /**
- * Creates a new layout listener, which unregisters itself from the observed view, when
- * invoked.
- *
- * @param view
- * The observed view as an instance of the class {@link View}. The view may not be
- * null
- * @param listener
- * The listener, which should be encapsulated, as an instance of the type {@link
- * OnGlobalLayoutListener} or null, if no listener should be encapsulated
- */
- public LayoutListenerWrapper(@NonNull final View view,
- @Nullable final OnGlobalLayoutListener listener) {
- Condition.INSTANCE.ensureNotNull(view, "The view may not be null");
- this.view = view;
- this.listener = listener;
- }
-
- @Override
- public void onGlobalLayout() {
- ViewUtil.removeOnGlobalLayoutListener(view.getViewTreeObserver(), this);
-
- if (listener != null) {
- listener.onGlobalLayout();
- }
- }
-
- }
-
- /**
- * A animation listener, which increases the number of running animations, when the observed
- * animation is started, and decreases the number of accordingly, when the animation is
- * finished. The listener allows to encapsulate another animation listener, which is notified
- * when the animation has been started, canceled or ended.
- */
- protected class AnimationListenerWrapper extends AnimatorListenerAdapter {
-
- /**
- * The encapsulated listener.
- */
- private final AnimatorListener listener;
-
- /**
- * Decreases the number of running animations and executes the next pending action, if no
- * running animations remain.
- */
- private void endAnimation() {
- if (--runningAnimations == 0) {
- notifyOnAnimationsEnded();
- }
- }
-
- /**
- * Creates a new animation listener, which increases the number of running animations, when
- * the observed animation is started, and decreases the number of accordingly, when the
- * animation is finished.
- *
- * @param listener
- * The listener, which should be encapsulated, as an instance of the type {@link
- * AnimatorListener} or null, if no listener should be encapsulated
- */
- public AnimationListenerWrapper(@Nullable final AnimatorListener listener) {
- this.listener = listener;
- runningAnimations++;
- }
-
- @Override
- public void onAnimationStart(final Animator animation) {
- super.onAnimationStart(animation);
-
- if (listener != null) {
- listener.onAnimationStart(animation);
- }
- }
-
- @Override
- public void onAnimationEnd(final Animator animation) {
- super.onAnimationEnd(animation);
-
- if (listener != null) {
- listener.onAnimationEnd(animation);
- }
-
- endAnimation();
- }
-
- @Override
- public void onAnimationCancel(final Animator animation) {
- super.onAnimationCancel(animation);
-
- if (listener != null) {
- listener.onAnimationCancel(animation);
- }
-
- endAnimation();
- }
-
- }
-
- /**
- * A builder, which allows to configure and create instances of the class {@link
- * InitialItemIterator}.
- */
- protected class InitialItemIteratorBuilder extends
- AbstractItemIterator.AbstractBuilder {
-
- /**
- * The backing array, which is used to store items, once their initial position and state
- * has been calculated.
- */
- private final AbstractItem[] backingArray;
-
- /**
- * Creates a new builder, which allows to configure and create instances of the class {@link
- * InitialItemIterator}.
- *
- * @param backingArray
- * The backing array, which should be used to store items, once their initial
- * position and state has been calculated. The backing array may not be null
- */
- public InitialItemIteratorBuilder(@NonNull final AbstractItem[] backingArray) {
- Condition.INSTANCE.ensureNotNull(backingArray, "The backing array may not be null");
- this.backingArray = backingArray;
- }
-
- @NonNull
- @Override
- public InitialItemIterator create() {
- return new InitialItemIterator(backingArray, reverse, start);
- }
-
- }
-
- /**
- * An iterator, which allows to iterate the items, which correspond to the child views of a
- * {@link TabSwitcher}. When an item is referenced for the first time, its initial position and
- * state is calculated and the item is stored in a backing array. When the item is iterated
- * again, it is retrieved from the backing array.
- */
- protected class InitialItemIterator extends AbstractItemIterator {
-
- /**
- * The backing array, which is used to store items, once their initial position and state
- * has been calculated.
- */
- private final AbstractItem[] backingArray;
-
- /**
- * Calculates the initial position and state of a specific item.
- *
- * @param item
- * The item, whose position and state should be calculated, as an instance of the
- * class {@link AbstractItem}. The item may not be null
- * @param predecessor
- * The predecessor of the given item as an instance of the class {@link
- * AbstractItem} or null, if the item does not have a predecessor
- */
- private void calculateAndClipStartPosition(@NonNull final AbstractItem item,
- @Nullable final AbstractItem predecessor) {
- float position = calculateStartPosition(item);
- Pair pair = clipPosition(item.getIndex(), position, predecessor);
- item.getTag().setPosition(pair.first);
- item.getTag().setState(pair.second);
- }
-
- /**
- * Calculates and returns the initial position of a specific item.
- *
- * @param item
- * The item, whose position should be calculated, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @return The position, which has been calculated, as a {@link Float} value
- */
- private float calculateStartPosition(@NonNull final AbstractItem item) {
- if (item.getIndex() == 0) {
- return getCount() > getStackedTabCount() ?
- getStackedTabCount() * stackedTabSpacing :
- (getCount() - 1) * stackedTabSpacing;
- } else {
- return -1;
- }
- }
-
- /**
- * Creates a new iterator, which allows to iterate the items, which corresponds to the child
- * views of a {@link TabSwitcher}. When an item is referenced for the first time, its
- * initial position and state is calculated and the item is stored in a backing array. When
- * the item is iterated again, it is retrieved from the backing array.
- *
- * @param backingArray
- * The backing array, which should be used to store items, once their initial
- * position and state has been calculated, as an array of the type {@link
- * AbstractItem}. The array may not be null
- * @param reverse
- * True, if the items should be iterated in reverse order, false otherwise
- * @param start
- * The index of the first item, which should be iterated, as an {@link Integer}
- * value or -1, if all items should be iterated
- */
- private InitialItemIterator(@NonNull final AbstractItem[] backingArray,
- final boolean reverse, final int start) {
- Condition.INSTANCE.ensureNotNull(backingArray, "The backing array may not be null");
- this.backingArray = backingArray;
- initialize(reverse, start);
- }
-
- @Override
- public final int getCount() {
- return backingArray.length;
- }
-
- @NonNull
- @Override
- public final AbstractItem getItem(final int index) {
- AbstractItem item = backingArray[index];
-
- if (item == null) {
- if (index == 0 && getModel().isAddTabButtonShown()) {
- item = AddTabItem.create(getTabViewRecycler());
- } else {
- item = TabItem.create(getModel(), getTabViewRecycler(),
- index - (getModel().isAddTabButtonShown() ? 1 : 0));
- }
-
- calculateAndClipStartPosition(item, index > 0 ? getItem(index - 1) : null);
- backingArray[index] = item;
- }
-
- return item;
- }
-
- }
-
- /**
- * An animation, which allows to fling the tabs.
- */
- private class FlingAnimation extends android.view.animation.Animation {
-
- /**
- * The distance, the tabs should be moved.
- */
- private final float distance;
-
- /**
- * Creates a new fling animation.
- *
- * @param distance
- * The distance, the tabs should be moved, in pixels as a {@link Float} value
- */
- FlingAnimation(final float distance) {
- this.distance = distance;
- }
-
- @Override
- protected void applyTransformation(final float interpolatedTime, final Transformation t) {
- if (flingAnimation != null) {
- getDragHandler().handleDrag(distance * interpolatedTime, 0);
- }
- }
-
- }
-
- /**
- * The tab switcher, the layout belongs to.
- */
- private final TabSwitcher tabSwitcher;
-
- /**
- * The model of the tab switcher, the layout belongs to.
- */
- private final TabSwitcherModel model;
-
- /**
- * The arithmetics, which are used by the layout.
- */
- private final Arithmetics arithmetics;
-
- /**
- * The style, which allows to retrieve style attributes of the tab switcher.
- */
- private final TabSwitcherStyle style;
-
- /**
- * The dispatcher, which is used to dispatch touch events to event handlers.
- */
- private final TouchEventDispatcher touchEventDispatcher;
-
- /**
- * The space between tabs, which are part of a stack, in pixels.
- */
- private final int stackedTabSpacing;
-
- /**
- * The logger, which is used for logging.
- */
- private final Logger logger;
-
- /**
- * The callback, which is notified about the layout's events.
- */
- private Callback callback;
-
- /**
- * The number of animations, which are currently running.
- */
- private int runningAnimations;
-
- /**
- * The animation, which is used to fling the tabs.
- */
- private android.view.animation.Animation flingAnimation;
-
- /**
- * The index of the first visible tab.
- */
- private int firstVisibleIndex;
-
- /**
- * Registers the layout as the callback of all touch event handlers.
- */
- private void registerEventHandlerCallbacks() {
- for (AbstractTouchEventHandler eventHandler : touchEventDispatcher) {
- registerEventHandlerCallback(eventHandler);
- }
-
- touchEventDispatcher.setCallback(this);
- }
-
- /**
- * Registers the layout as the callback of a specific event handler.
- *
- * @param eventHandler
- * The event handler as an instance of the class {@link AbstractTouchEventHandler}. The
- * event handler may not be null
- */
- private void registerEventHandlerCallback(
- @NonNull final AbstractTouchEventHandler eventHandler) {
- if (eventHandler instanceof SwipeGestureEventHandler) {
- ((SwipeGestureEventHandler) eventHandler).setCallback(this);
- } else if (eventHandler instanceof PullDownGestureEventHandler) {
- ((PullDownGestureEventHandler) eventHandler).setCallback(this);
- }
- }
-
- /**
- * Unregisters the layout as the callback of all touch event handlers.
- */
- private void unregisterEventHandlerCallbacks() {
- for (AbstractTouchEventHandler eventHandler : touchEventDispatcher) {
- unregisterEventHandlerCallback(eventHandler);
- }
-
- touchEventDispatcher.setCallback(null);
- }
-
- /**
- * Unregisters the layout as the callback of a specific event handler.
- *
- * @param eventHandler
- * The event handler as an instance of the class {@link AbstractTouchEventHandler}. The
- * event handler may not be null
- */
- private void unregisterEventHandlerCallback(
- @NonNull final AbstractTouchEventHandler eventHandler) {
- if (eventHandler instanceof SwipeGestureEventHandler) {
- ((SwipeGestureEventHandler) eventHandler).setCallback(null);
- } else if (eventHandler instanceof PullDownGestureEventHandler) {
- ((PullDownGestureEventHandler) eventHandler).setCallback(null);
- }
- }
-
- /**
- * Adapts the visibility of the toolbars, which are shown, when the tab switcher is shown.
- */
- private void adaptToolbarVisibility() {
- Toolbar[] toolbars = getToolbars();
-
- if (toolbars != null) {
- for (Toolbar toolbar : toolbars) {
- toolbar.setVisibility(
- getTabSwitcher().isSwitcherShown() && getModel().areToolbarsShown() ?
- View.VISIBLE : View.INVISIBLE);
- }
- }
-
- // TODO: Detach and re-inflate layout
- }
-
- /**
- * Adapts the title of the toolbar, which is shown, when the tab switcher is shown.
- */
- private void adaptToolbarTitle() {
- Toolbar[] toolbars = getToolbars();
-
- if (toolbars != null) {
- CharSequence title = style.getToolbarTitle();
- toolbars[TabSwitcher.PRIMARY_TOOLBAR_INDEX].setTitle(title);
- }
- }
-
- /**
- * Adapts the navigation icon of the toolbar, which is shown, when the tab switcher is shown.
- */
- private void adaptToolbarNavigationIcon() {
- Toolbar[] toolbars = getToolbars();
-
- if (toolbars != null) {
- Toolbar toolbar = toolbars[TabSwitcher.PRIMARY_TOOLBAR_INDEX];
- Drawable icon = style.getToolbarNavigationIcon();
- toolbar.setNavigationIcon(icon);
- toolbar.setNavigationOnClickListener(getModel().getToolbarNavigationIconListener());
- }
- }
-
- /**
- * Adapts the decorator.
- */
- private void adaptDecorator() {
- getContentViewRecycler().setAdapter(onCreateContentRecyclerAdapter());
- }
-
- /**
- * Adapts the log level.
- */
- private void adaptLogLevel() {
- getTabViewRecycler().setLogLevel(getModel().getLogLevel());
- getContentViewRecycler().setLogLevel(getModel().getLogLevel());
- }
-
- /**
- * Inflates the menu of the toolbar, which is shown, when the tab switcher is shown.
- */
- private void inflateToolbarMenu() {
- Toolbar[] toolbars = getToolbars();
- int menuId = getModel().getToolbarMenuId();
-
- if (toolbars != null && menuId != -1) {
- Toolbar toolbar = toolbars.length > 1 ? toolbars[TabSwitcher.SECONDARY_TOOLBAR_INDEX] :
- toolbars[TabSwitcher.PRIMARY_TOOLBAR_INDEX];
- Menu previousMenu = toolbar.getMenu();
-
- if (previousMenu != null) {
- previousMenu.clear();
- }
-
- toolbar.inflateMenu(menuId);
- toolbar.setOnMenuItemClickListener(getModel().getToolbarMenuItemListener());
- }
- }
-
- /**
- * Creates and returns an animation listener, which allows to handle, when a fling animation
- * ended.
- *
- * @return The listener, which has been created, as an instance of the class {@link
- * Animation.AnimationListener}. The listener may not be null
- */
- @NonNull
- private Animation.AnimationListener createFlingAnimationListener() {
- return new Animation.AnimationListener() {
-
- @Override
- public void onAnimationStart(final android.view.animation.Animation animation) {
-
- }
-
- @Override
- public void onAnimationEnd(final android.view.animation.Animation animation) {
- getDragHandler().onUp(null);
- flingAnimation = null;
- notifyOnAnimationsEnded();
- }
-
- @Override
- public void onAnimationRepeat(final android.view.animation.Animation animation) {
-
- }
-
- };
- }
-
- /**
- * Calculates the positions of all items, when dragging towards the start.
- *
- * @param dragDistance
- * The current drag distance in pixels as a {@link Float} value
- */
- private void calculatePositionsWhenDraggingToEnd(final float dragDistance) {
- firstVisibleIndex = -1;
- AbstractItemIterator iterator =
- new ItemIterator.Builder(getTabSwitcher(), getTabViewRecycler()).create();
- AbstractItem item;
- boolean abort = false;
-
- while ((item = iterator.next()) != null && !abort) {
- if (getItemCount() - item.getIndex() > 1) {
- abort = calculatePositionWhenDraggingToEnd(dragDistance, item, iterator.previous());
-
- if (firstVisibleIndex == -1 && item.getTag().getState() == State.FLOATING) {
- firstVisibleIndex = item.getIndex();
- }
- } else {
- Pair pair = clipPosition(item.getIndex(), item.getTag().getPosition(),
- iterator.previous());
- item.getTag().setPosition(pair.first);
- item.getTag().setState(pair.second);
- }
-
- inflateOrRemoveView(item, true);
- }
- }
-
- /**
- * The method, which is invoked on implementing subclasses in order to calculate the position of
- * a specific item, when dragging towards the end.
- *
- * @param dragDistance
- * The current drag distance in pixels as a {@link Float} value
- * @param item
- * The item whose position should be calculated, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param predecessor
- * The predecessor of the given item as an instance of the class {@link AbstractItem} or
- * null, if the item does not have a predecessor
- * @return True, if calculating the position of subsequent items can be omitted, false otherwise
- */
- private boolean calculatePositionWhenDraggingToEnd(final float dragDistance,
- @NonNull final AbstractItem item,
- @Nullable final AbstractItem predecessor) {
- if (predecessor == null || predecessor.getTag().getState() != State.FLOATING) {
- if ((item.getTag().getState() == State.STACKED_START_ATOP && item.getIndex() == 0) ||
- item.getTag().getState() == State.FLOATING) {
- float currentPosition = item.getTag().getPosition();
- float newPosition = currentPosition + dragDistance;
- float maxEndPosition = calculateMaxEndPosition(item.getIndex());
-
- if (maxEndPosition != -1) {
- newPosition = Math.min(newPosition, maxEndPosition);
- }
-
- Pair pair = clipPosition(item.getIndex(), newPosition, predecessor);
- item.getTag().setPosition(pair.first);
- item.getTag().setState(pair.second);
- } else if (item.getTag().getState() == State.STACKED_START_ATOP) {
- return true;
- }
- } else {
- float newPosition = calculateSuccessorPosition(item, predecessor);
- float maxEndPosition = calculateMaxEndPosition(item.getIndex());
-
- if (maxEndPosition != -1) {
- newPosition = Math.min(newPosition, maxEndPosition);
- }
- Pair pair = clipPosition(item.getIndex(), newPosition, predecessor);
- item.getTag().setPosition(pair.first);
- item.getTag().setState(pair.second);
- }
-
- return false;
- }
-
- /**
- * Calculates the positions of all items, when dragging towards the end.
- *
- * @param dragDistance
- * The current drag distance in pixels as a {@link Float} value
- */
- private void calculatePositionsWhenDraggingToStart(final float dragDistance) {
- AbstractItemIterator iterator =
- new ItemIterator.Builder(getTabSwitcher(), getTabViewRecycler())
- .start(Math.max(0, firstVisibleIndex)).create();
- AbstractItem item;
- boolean abort = false;
-
- while ((item = iterator.next()) != null && !abort) {
- if (getItemCount() - item.getIndex() > 1) {
- abort = calculatePositionWhenDraggingToStart(dragDistance, item,
- iterator.previous());
- } else {
- Pair pair = clipPosition(item.getIndex(), item.getTag().getPosition(),
- iterator.previous());
- item.getTag().setPosition(pair.first);
- item.getTag().setState(pair.second);
- }
-
- inflateOrRemoveView(item, true);
- }
-
- if (firstVisibleIndex > 0) {
- int start = firstVisibleIndex - 1;
- iterator =
- new ItemIterator.Builder(getTabSwitcher(), getTabViewRecycler()).reverse(true)
- .start(start).create();
-
- while ((item = iterator.next()) != null) {
- AbstractItem successor = iterator.previous();
-
- if (item.getIndex() < start) {
- float successorPosition = successor.getTag().getPosition();
- Pair pair =
- clipPosition(successor.getIndex(), successorPosition, item);
- successor.getTag().setPosition(pair.first);
- successor.getTag().setState(pair.second);
- inflateOrRemoveView(successor, true);
-
- if (successor.getTag().getState() == State.FLOATING) {
- firstVisibleIndex = successor.getIndex();
- } else {
- break;
- }
- }
-
- float newPosition = calculatePredecessorPosition(item, successor);
- item.getTag().setPosition(newPosition);
-
- if (!iterator.hasNext()) {
- Pair pair =
- clipPosition(item.getIndex(), newPosition, (AbstractItem) null);
- item.getTag().setPosition(pair.first);
- item.getTag().setState(pair.second);
- inflateOrRemoveView(item, true);
-
- if (item.getTag().getState() == State.FLOATING) {
- firstVisibleIndex = item.getIndex();
- }
- }
- }
- }
- }
-
- /**
- * Calculates the position of a specific item, when dragging towards the start.
- *
- * @param dragDistance
- * The current drag distance in pixels as a {@link Float} value
- * @param item
- * The item, whose position should be calculated, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param predecessor
- * The predecessor of the given item as an instance of the class {@link AbstractItem} or
- * null, if the item does not have a predecessor
- * @return True, if calculating the position of subsequent items can be omitted, false otherwise
- */
- private boolean calculatePositionWhenDraggingToStart(final float dragDistance,
- @NonNull final AbstractItem item,
- @Nullable final AbstractItem predecessor) {
- float attachedPosition = calculateAttachedPosition(getTabSwitcher().getCount());
-
- if (predecessor == null || predecessor.getTag().getState() != State.FLOATING ||
- (attachedPosition != -1 && predecessor.getTag().getPosition() > attachedPosition)) {
- if (item.getTag().getState() == State.FLOATING) {
- float currentPosition = item.getTag().getPosition();
- float newPosition = currentPosition + dragDistance;
- float minStartPosition = calculateMinStartPosition(item.getIndex());
-
- if (minStartPosition != -1) {
- newPosition = Math.max(newPosition, minStartPosition);
- }
-
- Pair pair = clipPosition(item.getIndex(), newPosition, predecessor);
- item.getTag().setPosition(pair.first);
- item.getTag().setState(pair.second);
- } else if (item.getTag().getState() == State.STACKED_START_ATOP) {
- float currentPosition = item.getTag().getPosition();
- Pair pair =
- clipPosition(item.getIndex(), currentPosition, predecessor);
- item.getTag().setPosition(pair.first);
- item.getTag().setState(pair.second);
- return true;
- } else if (item.getTag().getState() == State.HIDDEN ||
- item.getTag().getState() == State.STACKED_START) {
- return true;
- }
- } else {
- float newPosition = calculateSuccessorPosition(item, predecessor);
- float minStartPosition = calculateMinStartPosition(item.getIndex());
-
- if (minStartPosition != -1) {
- newPosition = Math.max(newPosition, minStartPosition);
- }
-
- Pair pair = clipPosition(item.getIndex(), newPosition, predecessor);
- item.getTag().setPosition(pair.first);
- item.getTag().setState(pair.second);
- }
-
- return false;
- }
-
- /**
- * Notifies the callback, that all animations have been ended.
- */
- private void notifyOnAnimationsEnded() {
- if (callback != null) {
- callback.onAnimationsEnded();
- }
- }
-
- /**
- * Returns the tab switcher, the layout belongs to.
- *
- * @return The tab switcher, the layout belongs to, as an instance of the class {@link
- * TabSwitcher}. The tab switcher may not be null
- */
- @NonNull
- protected final TabSwitcher getTabSwitcher() {
- return tabSwitcher;
- }
-
- /**
- * Returns the model of the tab switcher, the layout belongs to.
- *
- * @return The model of the tab switcher, the layout belongs to, as an instance of the class
- * {@link TabSwitcherModel}. The model may not be null
- */
- @NonNull
- protected final TabSwitcherModel getModel() {
- return model;
- }
-
- /**
- * Returns the arithmetics, which are used by the layout.
- *
- * @return The arithmetics, which are used by the layout, as an instance of the type {@link
- * Arithmetics}. The arithmetics may not be null
- */
- @NonNull
- protected final Arithmetics getArithmetics() {
- return arithmetics;
- }
-
- /**
- * Returns the style, which allows to retrieve style attributes of the tab switcher.
- *
- * @return The style, which allows to retrieve style attributes of the tab switcher, as an
- * instance of the class {@link TabSwitcherStyle}. The style may not be null
- */
- @NonNull
- protected final TabSwitcherStyle getStyle() {
- return style;
- }
-
- /**
- * Returns the space between tabs, which are part of a stack.
- *
- * @return The space between tabs, which are part of a stack, in pixels as an {@link Integer}
- * value
- */
- protected final int getStackedTabSpacing() {
- return stackedTabSpacing;
- }
-
- /**
- * Returns the logger, which is used for logging.
- *
- * @return The logger, which is used for logging, as an instance of the class Logger. The logger
- * may not be null
- */
- @NonNull
- protected final Logger getLogger() {
- return logger;
- }
-
- /**
- * Returns the context, which is used by the layout.
- *
- * @return The context, which is used by the layout, as an instance of the class {@link
- * Context}. The context may not be null
- */
- @NonNull
- protected final Context getContext() {
- return tabSwitcher.getContext();
- }
-
- /**
- * Returns the index of the first visible tab.
- *
- * @return The index of the first visible tab as an {@link Integer} value or -1, if no tabs is
- * visible
- */
- protected final int getFirstVisibleIndex() {
- return firstVisibleIndex;
- }
-
- /**
- * Sets the index of the first visible tab.
- *
- * @param firstVisibleIndex
- * The index, which should be set, as an {@link Integer} value or -1, if no tab is
- * visible
- */
- protected final void setFirstVisibleIndex(final int firstVisibleIndex) {
- this.firstVisibleIndex = firstVisibleIndex;
- }
-
- /**
- * Returns the number of child views, which are contained by the tab switcher.
- *
- * @return The number of child views, which are contained by the tab switcher, as an {@link
- * Integer} value
- */
- protected final int getItemCount() {
- return getModel().getCount() + (getModel().isAddTabButtonShown() ? 1 : 0);
- }
-
- /**
- * Returns, whether a hidden tab at a specific index, is part of the stack, which is located at
- * the start, or not.
- *
- * @param index
- * The index of the hidden tab, as an {@link Integer} value
- * @return True, if the hidden tab is part of the stack, which is located at the start, false
- * otherwise
- */
- protected final boolean isStackedAtStart(final int index) {
- boolean start = true;
- AbstractItemIterator iterator =
- new ItemIterator.Builder(getTabSwitcher(), getTabViewRecycler()).start(index + 1)
- .create();
- AbstractItem item;
-
- while ((item = iterator.next()) != null) {
- State state = item.getTag().getState();
-
- if (state == State.STACKED_START) {
- start = true;
- break;
- } else if (state == State.FLOATING) {
- start = false;
- break;
- }
- }
-
- return start;
- }
-
- /**
- * Clips the position of a specific item.
- *
- * @param index
- * The index of the item, whose position should be clipped, as an {@link Integer} value
- * @param position
- * The position, which should be clipped, in pixels as a {@link Float} value
- * @param predecessor
- * The predecessor of the given item as an instance of the class {@link AbstractItem} or
- * null, if the item does not have a predecessor
- * @return A pair, which contains the position and state of the item, as an instance of the
- * class Pair. The pair may not be null
- */
- @NonNull
- protected final Pair clipPosition(final int index, final float position,
- @Nullable final AbstractItem predecessor) {
- return clipPosition(index, position,
- predecessor != null ? predecessor.getTag().getState() : null);
- }
-
- /**
- * Clips the position of a specific item.
- *
- * @param index
- * The index of the item, whose position should be clipped, as an {@link Integer} value
- * @param position
- * The position, which should be clipped, in pixels as a {@link Float} value
- * @param predecessorState
- * The state of the predecessor of the given item as a value of the enum {@link State}
- * or null, if the item does not have a predecessor
- * @return A pair, which contains the position and state of the item, as an instance of the
- * class Pair. The pair may not be null
- */
- protected final Pair clipPosition(final int index, final float position,
- @Nullable final State predecessorState) {
- Pair startPair =
- calculatePositionAndStateWhenStackedAtStart(getItemCount(), index,
- predecessorState);
- float startPosition = startPair.first;
-
- if (position <= startPosition) {
- State state = startPair.second;
- return Pair.create(startPosition, state);
- } else {
- Pair endPair = calculatePositionAndStateWhenStackedAtEnd(index);
- float endPosition = endPair.first;
-
- if (position >= endPosition) {
- State state = endPair.second;
- return Pair.create(endPosition, state);
- } else {
- State state = State.FLOATING;
- return Pair.create(position, state);
- }
- }
- }
-
- /**
- * Calculates and returns the position and state of a specific item, when stacked at the start.
- *
- * @param count
- * The total number of items, which are currently contained by the tab switcher, as an
- * {@link Integer} value
- * @param index
- * The index of the item, whose position and state should be returned, as an {@link
- * Integer} value
- * @param predecessor
- * The predecessor of the given item as an instance of the class {@link AbstractItem} or
- * null, if the item does not have a predecessor
- * @return A pair, which contains the position and state of the given item, when stacked at the
- * start, as an instance of the class Pair. The pair may not be null
- */
- @NonNull
- protected final Pair calculatePositionAndStateWhenStackedAtStart(final int count,
- final int index,
- @Nullable final AbstractItem predecessor) {
- return calculatePositionAndStateWhenStackedAtStart(count, index,
- predecessor != null ? predecessor.getTag().getState() : null);
- }
-
- /**
- * Inflates or removes the view, which is used to visualize a specific item, depending on the
- * item's current state.
- *
- * @param item
- * The item, whose view should be inflated or removed, as an instance of the class
- * {@link AbstractItem}. The item may not be null
- * @param dragging
- * True, if the item is currently being dragged, false otherwise
- */
- protected final void inflateOrRemoveView(@NonNull final AbstractItem item,
- final boolean dragging) {
- if (item.isInflated() && !item.isVisible()) {
- getTabViewRecycler().remove(item);
- } else if (item.isVisible()) {
- if (!item.isInflated()) {
- inflateAndUpdateView(item, dragging, null);
- } else {
- updateView(item, dragging);
- }
- }
- }
-
- /**
- * Inflates the view, which is used to visualize a specific item.
- *
- * @param item
- * The item, whose view should be inflated, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param listener
- * The layout listener, which should be notified, when the view has been inflated, as an
- * instance of the type {@link OnGlobalLayoutListener} or null, if no listener should be
- * notified
- * @param params
- * An array, which contains optional parameters, which should be passed to the view
- * recycler, which is used to inflate the view, as an {@link Integer} array or null, if
- * no optional parameters should be used
- */
- protected final void inflateView(@NonNull final AbstractItem item,
- @Nullable final OnGlobalLayoutListener listener,
- @NonNull final Integer... params) {
- Pair pair = getTabViewRecycler().inflate(item, params);
-
- if (listener != null) {
- boolean inflated = pair.second;
-
- if (inflated) {
- View view = pair.first;
- view.getViewTreeObserver()
- .addOnGlobalLayoutListener(new LayoutListenerWrapper(view, listener));
- } else {
- listener.onGlobalLayout();
- }
- }
- }
-
- /**
- * Updates the view, which is used to visualize a specific item.
- *
- * @param item
- * The item, whose view should be updated, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param dragging
- * True, if the item is currently being dragged, false otherwise
- */
- @CallSuper
- protected void updateView(@NonNull final AbstractItem item, final boolean dragging) {
- float position = item.getTag().getPosition();
- getArithmetics().setPosition(Axis.DRAGGING_AXIS, item, position);
- getArithmetics().setPosition(Axis.ORTHOGONAL_AXIS, item, 0);
- }
-
- /**
- * Calculates and returns the position on the dragging axis, where the distance between an item
- * and its predecessor should have reached the maximum.
- *
- * @param count
- * The total number of items, which are contained by the tab switcher, as an {@link
- * Integer} value
- * @return The position, which has been calculated, in pixels as an {@link Float} value or -1,
- * if no attached position is used
- */
- protected float calculateAttachedPosition(final int count) {
- return -1;
- }
-
- /**
- * Creates a new layout, which implements the functionality of a {@link TabSwitcher}.
- *
- * @param tabSwitcher
- * The tab switcher, the layout belongs to, as an instance of the class {@link
- * TabSwitcher}. The tab switcher may not be null
- * @param model
- * The model of the tab switcher, the layout belongs to, as an instance of the class
- * {@link TabSwitcherModel}. The model may not be null
- * @param arithmetics
- * The arithmetics, which should be used by the layout, as an instance of the type
- * {@link Arithmetics}. The arithmetics may not be null
- * @param style
- * The style, which allows to retrieve style attributes of the tab switcher, as an
- * instance of the class {@link TabSwitcherStyle}. The style may not be null
- * @param touchEventDispatcher
- * The dispatcher, which is used to dispatch touch events to event handlers, as an
- * instance of the class {@link TouchEventDispatcher}. The dispatcher may not be null
- */
- public AbstractTabSwitcherLayout(@NonNull final TabSwitcher tabSwitcher,
- @NonNull final TabSwitcherModel model,
- @NonNull final Arithmetics arithmetics,
- @NonNull final TabSwitcherStyle style,
- @NonNull final TouchEventDispatcher touchEventDispatcher) {
- Condition.INSTANCE.ensureNotNull(tabSwitcher, "The tab switcher may not be null");
- Condition.INSTANCE.ensureNotNull(model, "The model may not be null");
- Condition.INSTANCE.ensureNotNull(arithmetics, "The arithmetics may not be null");
- Condition.INSTANCE.ensureNotNull(style, "The style may not be null");
- Condition.INSTANCE.ensureNotNull(touchEventDispatcher, "The dispatcher may not be null");
- this.tabSwitcher = tabSwitcher;
- this.model = model;
- this.arithmetics = arithmetics;
- this.style = style;
- this.touchEventDispatcher = touchEventDispatcher;
- Resources resources = tabSwitcher.getResources();
- this.stackedTabSpacing = resources.getDimensionPixelSize(R.dimen.stacked_tab_spacing);
- this.logger = new Logger(model.getLogLevel());
- this.callback = null;
- this.runningAnimations = 0;
- this.flingAnimation = null;
- this.firstVisibleIndex = -1;
- }
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the drag
- * handler, which is used by the layout.
- *
- * @return The drag handler, which is used by the layout, as an instance of the class {@link
- * AbstractDragTabsEventHandler} or null, if the drag handler has not been initialized yet
- */
- public abstract AbstractDragTabsEventHandler> getDragHandler();
-
- /**
- * The method, which is invoked on implementing subclasses in order to inflate the layout.
- *
- * @param inflater
- * The layout inflater, which should be used, as an instance of the class {@link
- * LayoutInflater}. The layout inflater may not be null
- * @param tabsOnly
- * True, if only the tabs should be inflated, false otherwise
- */
- protected abstract void onInflateLayout(@NonNull final LayoutInflater inflater,
- final boolean tabsOnly);
-
- /**
- * The method, which is invoked on implementing subclasses in order to detach the layout.
- *
- * @param tabsOnly
- * True, if only the tabs should be detached, false otherwise
- * @return A pair, which contains the index of the tab, which should be used as a reference,
- * when restoring the positions of tabs, as well as its current position in relation to the
- * available space, as an instance of the class Pair or null, if the positions of tabs should
- * not be restored
- */
- @Nullable
- protected abstract Pair onDetachLayout(final boolean tabsOnly);
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the view
- * recycler, which allows to recycle the views, which are associated with tabs.
- *
- * @return The view recycler, which allows to recycle the views, which are associated with tabs,
- * as an instance of the class ViewRecycler or null, if the view recycler has not been
- * initialized yet
- */
- public abstract AbstractViewRecycler getContentViewRecycler();
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the view
- * recycler, which allows to inflate the views, which are used to visualize the tabs.
- *
- * @return The view recycler, which allows to inflate the views, which are used to visualize the
- * tabs, as an instance of the class AttachedViewRecycler or null, if the view recycler has not
- * been initialized yet
- */
- protected abstract AttachedViewRecycler getTabViewRecycler();
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the adapter of
- * the view recycler, which allows to inflate the views, which are used to visualize the tabs.
- *
- * @return The adapter of the view recycler, which allows to inflated the views, which are used
- * to visualize the tabs, as an instance of the class {@link AbstractTabRecyclerAdapter} or
- * null, if the view recycler has not been initialized yet
- */
- protected abstract AbstractTabRecyclerAdapter getTabRecyclerAdapter();
-
- /**
- * The method, which is invoked on implementing subclasses in order to inflate and update the
- * view, which is used to visualize a specific item.
- *
- * @param item
- * The item, whose view should be inflated, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param dragging
- * True, if the view is currently being dragged, false otherwise
- * @param listener
- * The layout listener, which should be notified, when the view has been inflated, as an
- * instance of the type {@link OnGlobalLayoutListener} or null, if no listener should be
- * notified
- */
- protected abstract void inflateAndUpdateView(@NonNull final AbstractItem item,
- final boolean dragging,
- @Nullable final OnGlobalLayoutListener listener);
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the number of
- * tabs, which are contained by a stack.
- *
- * @return The number of tabs, which are contained by a stack, as an {@link Integer} value
- */
- protected abstract int getStackedTabCount();
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the position and
- * state of a specific item, when stacked at the start.
- *
- * @param count
- * The total number of items, which are currently contained by the tab switcher, as an
- * {@link Integer} value
- * @param index
- * The index of the item, whose position and state should be returned, as an {@link
- * Integer} value
- * @param predecessorState
- * The state of the predecessor of the given item as a value of the enum {@link State}
- * or null, if the item does not have a predecessor
- * @return A pair, which contains the position and state of the given item, when stacked at the
- * start, as an instance of the class Pair. The pair may not be null
- */
- @NonNull
- protected abstract Pair calculatePositionAndStateWhenStackedAtStart(
- final int count, final int index, @Nullable final State predecessorState);
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the position and
- * state of a specific item, when stacked at the end.
- *
- * @param index
- * The index of the item, whose position and state should be returned, as an {@link
- * Integer} value
- * @return A pair, which contains the position and state of the given item, when stacked at the
- * end, as an instance of the class Pair. The pair may not be null
- */
- @NonNull
- protected abstract Pair calculatePositionAndStateWhenStackedAtEnd(
- final int index);
-
- /**
- * Calculates the position of an item in relation to the position of its predecessor.
- *
- * @param item
- * The item, whose position should be calculated, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param predecessor
- * The predecessor as an instance of the class {@link AbstractItem}. The predecessor may
- * not be null
- * @return The position, which has been calculated, as a {@link Float} value
- */
- protected abstract float calculateSuccessorPosition(@NonNull final AbstractItem item,
- @NonNull final AbstractItem predecessor);
-
- /**
- * Calculates the position of an item in relation to the position of its successor.
- *
- * @param item
- * The item, whose position should be calculated, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param successor
- * The successor as an instance of the class {@link AbstractItem}. The successor may not
- * be null
- * @return The position, which has been calculated, as a {@link Float} value
- */
- protected abstract float calculatePredecessorPosition(@NonNull final AbstractItem item,
- @NonNull final AbstractItem successor);
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the minimum
- * position of a specific item, when dragging towards the start.
- *
- * @param index
- * The index of the item, whose position should be calculated, as an {@link Integer}
- * value
- * @return The position, which has been calculated, as a {@link Float} value or -1, if no
- * minimum position is available
- */
- protected float calculateMinStartPosition(final int index) {
- return -1;
- }
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve the maximum
- * position of a specific item, when dragging towards the end.
- *
- * @param index
- * The index of the item, whose position should be calculated, as an {@link Integer}
- * value
- * @return The position, which has been calculated, as a {@link Float} value or -1, if no
- * maximum position is available
- */
- protected float calculateMaxEndPosition(final int index) {
- return -1;
- }
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve, whether the
- * items are overshooting at the start.
- *
- * @return True, if the items are overshooting at the start, false otherwise
- */
- protected boolean isOvershootingAtStart() {
- return false;
- }
-
- /**
- * The method, which is invoked on implementing subclasses in order to retrieve, whether the
- * items are overshooting at the end.
- *
- * @param dragState
- * The current drag state as an instance of the enum {@link DragState}. The drag state
- * may not be null
- * @param iterator
- * An iterator, which allows to iterate the items, which are contained by the tab
- * switcher, as an instance of the class {@link AbstractItemIterator}. The iterator may
- * not be null
- * @return True, if the items are overshooting at the end, false otherwise
- */
- protected boolean isOvershootingAtEnd(@NonNull final DragState dragState,
- @NonNull final AbstractItemIterator iterator) {
- return false;
- }
-
- /**
- * The method, which is called when dragging after the positions and states of all tabs have
- * been calculated. It may be overridden by subclasses in order to implement a second layout
- * pass, which requires the information, which has been calculated in the first pass, and allows
- * to perform additional modifications of the tabs based on that information.
- *
- * @param builder
- * The builder, which allows to create the iterator, which should be used to iterate the
- * tabs, as an instance of the class {@link AbstractItemIterator.AbstractBuilder}. The
- * builder may not be null
- */
- protected void secondLayoutPass(@NonNull final AbstractItemIterator.AbstractBuilder builder) {
-
- }
-
- /**
- * The method, which is invoked on implementing subclasses in order to create the view recycler
- * adapter, which allows to inflate the views, which are associated with tabs.
- *
- * @return The view recycler adapter, which has been created, as an instance of the class
- * AttachedViewRecycler.Adapter. The recycler adapter may not be null }
- */
- @NonNull
- protected AttachedViewRecycler.Adapter onCreateContentRecyclerAdapter() {
- return getModel().getContentRecyclerAdapter();
- }
-
- /**
- * Inflates the layout.
- *
- * @param tabsOnly
- * True, if only the tabs should be inflated, false otherwise
- */
- public final void inflateLayout(final boolean tabsOnly) {
- int themeResourceId = style.getThemeHelper().getThemeResourceId(tabSwitcher.getLayout());
- LayoutInflater inflater =
- LayoutInflater.from(new ContextThemeWrapper(getContext(), themeResourceId));
- onInflateLayout(inflater, tabsOnly);
- registerEventHandlerCallbacks();
- adaptDecorator();
- adaptLogLevel();
-
- if (!tabsOnly) {
- adaptToolbarVisibility();
- adaptToolbarTitle();
- adaptToolbarNavigationIcon();
- inflateToolbarMenu();
- }
- }
-
- /**
- * Detaches the layout.
- *
- * @param tabsOnly
- * True, if only the tabs should be detached, false otherwise
- * @return A pair, which contains the index of the first visible tab, as well as its current
- * position in relation to the available space, as an instance of the class Pair or null, if the
- * tab switcher is not shown
- */
- @Nullable
- public final Pair detachLayout(final boolean tabsOnly) {
- Pair pair = onDetachLayout(tabsOnly);
- getTabViewRecycler().removeAll();
- getTabViewRecycler().clearCache();
- unregisterEventHandlerCallbacks();
- touchEventDispatcher.removeEventHandler(getDragHandler());
-
- if (!tabsOnly) {
- getTabSwitcher().removeAllViews();
- }
-
- return pair;
- }
-
- /**
- * Sets the callback, which should be notified about the layout's events.
- *
- * @param callback
- * The callback, which should be set, as an instance of the type {@link Callback} or
- * null, if no callback should be notified
- */
- public final void setCallback(@Nullable final Callback callback) {
- this.callback = callback;
- }
-
- @Override
- public final boolean isAnimationRunning() {
- return runningAnimations > 0 || flingAnimation != null;
- }
-
- @Nullable
- @Override
- public final Menu getToolbarMenu() {
- Toolbar[] toolbars = getToolbars();
-
- if (toolbars != null) {
- Toolbar toolbar = toolbars.length > 1 ? toolbars[TabSwitcher.SECONDARY_TOOLBAR_INDEX] :
- toolbars[TabSwitcher.PRIMARY_TOOLBAR_INDEX];
- return toolbar.getMenu();
- }
-
- return null;
- }
-
- @Override
- public final void onLogLevelChanged(@NonNull final LogLevel logLevel) {
- adaptLogLevel();
- }
-
- @CallSuper
- @Override
- public void onDecoratorChanged(@NonNull final TabSwitcherDecorator decorator) {
- adaptDecorator();
- detachLayout(true);
- onGlobalLayout();
- }
-
- @Override
- public void onAddTabButtonVisibilityChanged(final boolean visible) {
-
- }
-
- @Override
- public final void onAddTabButtonColorChanged(@Nullable final ColorStateList colorStateList) {
-
- }
-
- @Override
- public final void onToolbarVisibilityChanged(final boolean visible) {
- adaptToolbarVisibility();
- }
-
- @Override
- public final void onToolbarTitleChanged(@Nullable final CharSequence title) {
- adaptToolbarTitle();
- }
-
- @Override
- public final void onToolbarNavigationIconChanged(@Nullable final Drawable icon,
- @Nullable final OnClickListener listener) {
- adaptToolbarNavigationIcon();
- }
-
- @Override
- public final void onToolbarMenuInflated(@MenuRes final int resourceId,
- @Nullable final OnMenuItemClickListener listener) {
- inflateToolbarMenu();
- }
-
- @Override
- public final void onTabIconChanged(@Nullable final Drawable icon) {
-
- }
-
- @Override
- public void onTabBackgroundColorChanged(@Nullable final ColorStateList colorStateList) {
-
- }
-
- @Override
- public void onTabContentBackgroundColorChanged(@ColorInt final int color) {
-
- }
-
- @Override
- public final void onTabTitleColorChanged(@Nullable final ColorStateList colorStateList) {
-
- }
-
- @Override
- public final void onTabCloseButtonIconChanged(@Nullable final Drawable icon) {
-
- }
-
- @Override
- public final void onTabProgressBarColorChanged(@ColorInt final int color) {
-
- }
-
- @Override
- public void onSwitcherShown() {
-
- }
-
- @Override
- public void onSwitcherHidden() {
-
- }
-
- @Override
- public final void onAddedEventHandler(@NonNull final TouchEventDispatcher dispatcher,
- @NonNull final AbstractTouchEventHandler eventHandler) {
- registerEventHandlerCallback(eventHandler);
- }
-
- @Override
- public final void onRemovedEventHandler(@NonNull final TouchEventDispatcher dispatcher,
- @NonNull final AbstractTouchEventHandler eventHandler) {
- unregisterEventHandlerCallback(eventHandler);
- }
-
- @Nullable
- @Override
- public final DragState onDrag(@NonNull final DragState dragState, final float dragDistance) {
- if (dragDistance != 0) {
- if (dragState == DragState.DRAG_TO_END) {
- calculatePositionsWhenDraggingToEnd(dragDistance);
- } else {
- calculatePositionsWhenDraggingToStart(dragDistance);
- }
-
- secondLayoutPass(new ItemIterator.Builder(getTabSwitcher(), getTabViewRecycler()));
- }
-
- DragState overshoot = isOvershootingAtEnd(dragState,
- new ItemIterator.Builder(getTabSwitcher(), getTabViewRecycler()).create()) ?
- DragState.OVERSHOOT_END :
- (isOvershootingAtStart() ? DragState.OVERSHOOT_START : null);
- getLogger().logVerbose(getClass(),
- "Dragging using a distance of " + dragDistance + " pixels. Drag state is " +
- dragState + ", overshoot is " + overshoot);
- return overshoot;
- }
-
- @Override
- public final void onPressStarted(@NonNull final AbstractItem item) {
- ColorStateList colorStateList = null;
- boolean selected = false;
-
- if (item instanceof TabItem) {
- TabItem tabItem = (TabItem) item;
- Tab tab = tabItem.getTab();
- colorStateList = style.getTabBackgroundColor(tab);
- selected = getModel().getSelectedTab() == tab;
- } else if (item instanceof AddTabItem) {
- colorStateList = style.getAddTabButtonColor();
- }
-
- if (colorStateList != null) {
- int[] stateSet = selected ?
- new int[]{android.R.attr.state_pressed, android.R.attr.state_selected} :
- new int[]{android.R.attr.state_pressed};
- int color = colorStateList.getColorForState(stateSet, -1);
-
- if (color != -1) {
- View view = item.getView();
- Drawable background = view.getBackground();
- background.setColorFilter(color, PorterDuff.Mode.MULTIPLY);
- }
- }
- }
-
- @Override
- public final void onPressEnded(@NonNull final AbstractItem item) {
- getTabRecyclerAdapter().onTabBackgroundColorChanged(getModel().getTabBackgroundColor());
- }
-
- @Override
- public final void onClick(@NonNull final AbstractItem item) {
- if (item instanceof TabItem) {
- TabItem tabItem = (TabItem) item;
- getModel().selectTab(tabItem.getTab());
- getLogger().logVerbose(getClass(), "Clicked tab at index " +
- (tabItem.getIndex() - (getModel().isAddTabButtonShown() ? 1 : 0)));
- } else if (item instanceof AddTabItem) {
- AddTabButtonListener listener = getModel().getAddTabButtonListener();
-
- if (listener != null) {
- listener.onAddTab(getTabSwitcher());
- }
-
- getLogger().logVerbose(getClass(), "Clicked add tab button");
- }
- }
-
- @Override
- public final void onFling(final float distance, final long duration) {
- if (getDragHandler() != null) {
- flingAnimation = new FlingAnimation(distance);
- flingAnimation.setFillAfter(true);
- flingAnimation.setAnimationListener(createFlingAnimationListener());
- flingAnimation.setDuration(duration);
- flingAnimation.setInterpolator(new DecelerateInterpolator());
- getTabSwitcher().startAnimation(flingAnimation);
- logger.logVerbose(getClass(),
- "Started fling animation using a distance of " + distance +
- " pixels and a duration of " + duration + " milliseconds");
- }
- }
-
- @Override
- public final void onCancelFling() {
- if (flingAnimation != null) {
- flingAnimation.cancel();
- flingAnimation = null;
- getDragHandler().onUp(null);
- logger.logVerbose(getClass(), "Canceled fling animation");
- }
- }
-
- @Override
- public void onRevertStartOvershoot() {
-
- }
-
- @Override
- public void onRevertEndOvershoot() {
-
- }
-
- @Override
- public void onSwipe(@NonNull final TabItem tabItem, final float distance) {
-
- }
-
- @Override
- public void onSwipeEnded(@NonNull final TabItem tabItem, final boolean remove,
- final float velocity) {
-
- }
-
- @Override
- public void onPulledDown() {
-
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractTabViewHolder.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractTabViewHolder.java
deleted file mode 100644
index 60ca1588..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/AbstractTabViewHolder.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout;
-
-import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.view.CircularProgressBar;
-
-/**
- * An abstract base class for all view holders, which allow to store references to the views, a tab
- * of a {@link TabSwitcher} consists of.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public abstract class AbstractTabViewHolder {
-
- /**
- * The view group, which contains the title and close button of a tab.
- */
- public ViewGroup titleContainer;
-
- /**
- * The text view, which is used to display the title of a tab.
- */
- public TextView titleTextView;
-
- /**
- * The image view, which is used to display the icon of a tab.
- */
- public ImageView iconImageView;
-
- /**
- * The progress bar of a tab.
- */
- public CircularProgressBar progressBar;
-
- /**
- * The close button of a tab.
- */
- public ImageButton closeButton;
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/Arithmetics.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/Arithmetics.java
deleted file mode 100644
index 640172ce..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/Arithmetics.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package de.mrapp.android.tabswitcher.layout;
-
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewPropertyAnimator;
-
-import androidx.annotation.NonNull;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.layout.AbstractDragTabsEventHandler.DragState;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-
-/**
- * Defines the interface, a class, which provides methods, which allow to calculate the position,
- * size and rotation of a {@link TabSwitcher}'s children, must implement.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public interface Arithmetics {
-
- /**
- * Contains all axes on which the tabs of a {@link TabSwitcher} can be moved.
- */
- enum Axis {
-
- /**
- * The axis on which a tab is moved when dragging it.
- */
- DRAGGING_AXIS,
-
- /**
- * The axis on which a tab is moved, when it is added to or removed from the switcher.
- */
- ORTHOGONAL_AXIS,
-
- /**
- * The horizontal axis.
- */
- X_AXIS,
-
- /**
- * The vertical axis.
- */
- Y_AXIS
-
- }
-
- /**
- * Returns the padding of the tab switcher on a specific axis and using a specific gravity.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param gravity
- * The gravity as an {@link Integer} value. The gravity must be
- * Gravity.START
or Gravity.END
- * @return The padding of the tab switcher on the given axis and using the given gravity as an
- * {@link Integer} value
- */
- int getTabSwitcherPadding(@NonNull Axis axis, int gravity);
-
- /**
- * Returns the size of the container, which contains the tab switcher's tabs, on a specific
- * axis. By default, the padding and the size of the toolbars are included.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @return The size of the container, which contains the tab switcher's tabs, on the given axis
- * as a {@link Float} value
- */
- float getTabContainerSize(@NonNull Axis axis);
-
- /**
- * Returns the size of the container, which contains the tab switcher's tabs, on a specific
- * axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param includePadding
- * True, if the padding and the size of the toolbars should be included, false
- * otherwise
- * @return The size of the container, which contains the tab switcher's tabs, on the given axis
- * as a {@link Float} value
- */
- float getTabContainerSize(@NonNull Axis axis, boolean includePadding);
-
- /**
- * Returns the position of a touch event on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param event
- * The touch event, whose position should be returned, as an instance of the class
- * {@link MotionEvent}. The motion event may not be null
- * @return The position of the given touch event on the given axis as a {@link Float} value
- */
- float getTouchPosition(@NonNull Axis axis, @NonNull MotionEvent event);
-
- /**
- * Returns the position of a specific item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose position should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @return The position of the given item on the given axis as a {@link Float} value
- */
- float getPosition(@NonNull Axis axis, @NonNull AbstractItem item);
-
- /**
- * Sets the position of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose position should be set, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param position
- * The position, which should be set, as a {@link Float} value
- */
- void setPosition(@NonNull Axis axis, @NonNull AbstractItem item, float position);
-
- /**
- * Animates the position of an item on a specific axis. By default, the item's padding is not
- * taken into account.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param animator
- * The animator, which should be used to animate the position, as an instance of the
- * class {@link ViewPropertyAnimator}. The animator may not be null
- * @param item
- * The item, whose position should be animated, as an instance of the class {@link
- * View}. The view may not be null
- * @param position
- * The position, which should be set by the animation, as a {@link Float} value
- */
- void animatePosition(@NonNull Axis axis, @NonNull ViewPropertyAnimator animator,
- @NonNull AbstractItem item, float position);
-
- /**
- * Animates the position of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param animator
- * The animator, which should be used to animate the position, as an instance of the
- * class {@link ViewPropertyAnimator}. The animator may not be null
- * @param item
- * The item, whose position should be animated, as an instance of the class {@link
- * View}. The view may not be null
- * @param position
- * The position, which should be set by the animation, as a {@link Float} value
- * @param includePadding
- * True, if the item's padding should be taken into account, false otherwise
- */
- void animatePosition(@NonNull Axis axis, @NonNull ViewPropertyAnimator animator,
- @NonNull AbstractItem item, float position, boolean includePadding);
-
- /**
- * Returns the scale of an item, depending on its margin. By default, the item's padding is
- * not taken into account.
- *
- * @param item
- * The item, whose scale should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @return The scale of the given item as a {@link Float} value
- */
- float getScale(@NonNull final AbstractItem item);
-
- /**
- * Returns the scale of an item, depending on its margin.
- *
- * @param item
- * The item, whose scale should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param includePadding
- * True, if the item's padding should be taken into account as well, false otherwise
- * @return The scale of the given item as a {@link Float} value
- */
- float getScale(@NonNull final AbstractItem item, final boolean includePadding);
-
- /**
- * Sets the scale of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose scale should be set, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param scale
- * The scale, which should be set, as a {@link Float} value
- */
- void setScale(@NonNull Axis axis, @NonNull AbstractItem item, float scale);
-
- /**
- * Animates the scale of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param animator
- * The animator, which should be used to animate the scale, as an instance of the class
- * {@link ViewPropertyAnimator}. The animator may not be null
- * @param scale
- * The scale, which should be set by the animation, as a {@link Float} value
- */
- void animateScale(@NonNull Axis axis, @NonNull ViewPropertyAnimator animator, float scale);
-
- /**
- * Returns the size of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose size should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @return The size of the given item on the given axis as a {@link Float} value
- */
- float getSize(@NonNull Axis axis, @NonNull AbstractItem item);
-
- /**
- * Returns the pivot of an item on a specific axis, depending on the current drag state.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose pivot should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param dragState
- * The current drag state as a value of the enum {@link DragState}. The drag state may
- * not be null
- * @return The pivot of the given item on the given axis as a {@link Float} value
- */
- float getPivot(@NonNull Axis axis, @NonNull AbstractItem item, @NonNull DragState dragState);
-
- /**
- * Sets the pivot of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose pivot should be set, as an instance of the class {@link View}. The
- * item may not be null
- * @param pivot
- * The pivot, which should be set, as a {@link Float} value
- */
- void setPivot(@NonNull Axis axis, @NonNull AbstractItem item, float pivot);
-
- /**
- * Returns the rotation of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose rotation should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @return The rotation of the given item on the given axis as a {@link Float} value
- */
- float getRotation(@NonNull Axis axis, @NonNull AbstractItem item);
-
- /**
- * Sets the rotation of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose rotation should be set, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @param angle
- * The rotation, which should be set, as a {@link Float} value
- */
- void setRotation(@NonNull Axis axis, @NonNull AbstractItem item, float angle);
-
- /**
- * Animates the rotation of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param animator
- * The animator, should be used to animate the rotation, as an instance of the class
- * {@link ViewPropertyAnimator}. The animator may not be null
- * @param angle
- * The rotation, which should be set by the animation, as a {@link Float} value
- */
- void animateRotation(@NonNull Axis axis, @NonNull ViewPropertyAnimator animator, float angle);
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/ContentRecyclerAdapter.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/ContentRecyclerAdapter.java
deleted file mode 100644
index 1d45a790..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/ContentRecyclerAdapter.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import de.mrapp.android.tabswitcher.Animation;
-import de.mrapp.android.tabswitcher.StatefulTabSwitcherDecorator;
-import de.mrapp.android.tabswitcher.Tab;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.TabSwitcherDecorator;
-import de.mrapp.android.tabswitcher.TabSwitcherListener;
-import de.mrapp.android.tabswitcher.model.Restorable;
-import de.mrapp.android.util.view.AbstractViewRecycler;
-import de.mrapp.util.Condition;
-
-/**
- * A view recycler adapter, which allows to inflate the views, which are associated with the tabs of
- * a {@link TabSwitcher}, by encapsulating a {@link TabSwitcherDecorator}.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class ContentRecyclerAdapter extends AbstractViewRecycler.Adapter
- implements Restorable, TabSwitcherListener {
-
- /**
- * The name of the extra, which is used to store the saved instance states of previously removed
- * associated views within a bundle.
- */
- private static final String SAVED_INSTANCE_STATES_EXTRA =
- ContentRecyclerAdapter.class.getName() + "::SavedInstanceStates";
-
- /**
- * The tab switcher, which contains the tabs, the associated views, which are inflated by the
- * adapter, correspond to.
- */
- private final TabSwitcher tabSwitcher;
-
- /**
- * The decorator, which is used to inflate the associated views.
- */
- private final TabSwitcherDecorator decorator;
-
- /**
- * A sparse array, which manages the saved instance states of previously removed associated
- * views.
- */
- private SparseArray savedInstanceStates;
-
- /**
- * Puts the parameter {@link Tab#WAS_SHOWN_PARAMETER} into a specific bundle. If the bundle is
- * null, a new bundle is created.
- *
- * @param parameters
- * The bundle, the parameter should be put into, as an instance of the class {@link
- * Bundle} or null
- * @return The bundle, the parameter has been put into, as an instance of the clas {@link
- * Bundle}. The bundle may not be null
- */
- @NonNull
- private Bundle setWasShownParameter(@Nullable final Bundle parameters) {
- Bundle result = parameters;
-
- if (result == null) {
- result = new Bundle();
- }
-
- result.putBoolean(Tab.WAS_SHOWN_PARAMETER, true);
- return result;
- }
-
- /**
- * Creates a new view recycler adapter, which allows to inflate views, which are associated with
- * the tabs of a {@link TabSwitcher}, by encapsulating a {@link TabSwitcherDecorator}.
- *
- * @param tabSwitcher
- * The tab switcher, which contains the tabs, whose associated views are inflated by the
- * adapter, correspond to, as an instance of the class {@link TabSwitcher}. The tab
- * switcher may not be null
- * @param decorator
- * The decorator, which should be used to inflate the associated views, as an instance
- * of the class {@link TabSwitcherDecorator}. The decorator may not be null
- */
- public ContentRecyclerAdapter(@NonNull final TabSwitcher tabSwitcher,
- @NonNull final TabSwitcherDecorator decorator) {
- Condition.INSTANCE.ensureNotNull(tabSwitcher, "The tab switcher may not be null");
- Condition.INSTANCE.ensureNotNull(decorator, "The decorator may not be null");
- this.tabSwitcher = tabSwitcher;
- tabSwitcher.addListener(this);
- this.decorator = decorator;
- this.savedInstanceStates = new SparseArray<>();
- }
-
- /**
- * Clears the saved state of a specific tab.
- *
- * @param tab
- * The tab, whose saved state should be cleared, as an instance of the class {@link
- * Tab}. The tab may not be null
- */
- public void clearSavedState(@NonNull final Tab tab) {
- Condition.INSTANCE.ensureNotNull(tab, "The tab may not be null");
- savedInstanceStates.remove(tab.hashCode());
- }
-
- /**
- * Clears the saved states of all tabs.
- */
- public void clearAllSavedStates() {
- savedInstanceStates.clear();
- }
-
- @NonNull
- @Override
- public final View onInflateView(@NonNull final LayoutInflater inflater,
- @Nullable final ViewGroup parent, @NonNull final Tab item,
- final int viewType, @NonNull final Void... params) {
- int index = tabSwitcher.indexOf(item);
- View view = decorator.inflateView(inflater, parent, item, index);
- view.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT));
- return view;
- }
-
- @Override
- public final void onShowView(@NonNull final Context context, @NonNull final View view,
- @NonNull final Tab item, final boolean inflated,
- @NonNull final Void... params) {
- int index = tabSwitcher.indexOf(item);
- Bundle savedInstanceState = null;
- Bundle parameters = item.getParameters();
-
- if (parameters != null && parameters.getBoolean(Tab.WAS_SHOWN_PARAMETER, false)) {
- savedInstanceState = savedInstanceStates.get(item.hashCode());
- }
-
- item.setParameters(setWasShownParameter(parameters));
- decorator.applyDecorator(context, tabSwitcher, view, item, index, savedInstanceState,
- inflated);
- }
-
- @Override
- public final void onRemoveView(@NonNull final View view, @NonNull final Tab item) {
- int index = tabSwitcher.indexOf(item);
- Bundle outState = decorator.saveInstanceState(view, item, index);
- savedInstanceStates.put(item.hashCode(), outState);
- }
-
- @Override
- public final int getViewTypeCount() {
- return decorator.getViewTypeCount();
- }
-
- @Override
- public final int getViewType(@NonNull final Tab item) {
- int index = tabSwitcher.indexOf(item);
- return decorator.getViewType(item, index);
- }
-
- @Override
- public final void saveInstanceState(@NonNull final Bundle outState) {
- outState.putSparseParcelableArray(SAVED_INSTANCE_STATES_EXTRA, savedInstanceStates);
- }
-
- @Override
- public final void restoreInstanceState(@Nullable final Bundle savedInstanceState) {
- if (savedInstanceState != null) {
- savedInstanceStates =
- savedInstanceState.getSparseParcelableArray(SAVED_INSTANCE_STATES_EXTRA);
- }
- }
-
- @Override
- public final void onSwitcherShown(@NonNull final TabSwitcher tabSwitcher) {
-
- }
-
- @Override
- public final void onSwitcherHidden(@NonNull final TabSwitcher tabSwitcher) {
-
- }
-
- @Override
- public final void onSelectionChanged(@NonNull final TabSwitcher tabSwitcher,
- final int selectedTabIndex,
- @Nullable final Tab selectedTab) {
-
- }
-
- @Override
- public final void onTabAdded(@NonNull final TabSwitcher tabSwitcher, final int index,
- @NonNull final Tab tab, @NonNull final Animation animation) {
-
- }
-
- @Override
- public final void onTabRemoved(@NonNull final TabSwitcher tabSwitcher, final int index,
- @NonNull final Tab tab, @NonNull final Animation animation) {
- if (tabSwitcher.areSavedStatesClearedWhenRemovingTabs()) {
- clearSavedState(tab);
- TabSwitcherDecorator decorator = tabSwitcher.getDecorator();
-
- if (decorator instanceof StatefulTabSwitcherDecorator) {
- ((StatefulTabSwitcherDecorator) decorator).clearState(tab);
- }
- }
- }
-
- @Override
- public final void onAllTabsRemoved(@NonNull final TabSwitcher tabSwitcher,
- @NonNull final Tab[] tabs,
- @NonNull final Animation animation) {
- if (tabSwitcher.areSavedStatesClearedWhenRemovingTabs()) {
- clearAllSavedStates();
-
- TabSwitcherDecorator decorator = tabSwitcher.getDecorator();
-
- if (decorator instanceof StatefulTabSwitcherDecorator) {
- ((StatefulTabSwitcherDecorator) decorator).clearAllStates();
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/TabSwitcherLayout.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/TabSwitcherLayout.java
deleted file mode 100644
index 94287773..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/TabSwitcherLayout.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout;
-
-import android.view.Menu;
-import android.view.ViewGroup;
-
-import androidx.annotation.Nullable;
-import androidx.appcompat.widget.Toolbar;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-
-/**
- * Defines the interface, a layout, which implements the functionality of a {@link TabSwitcher},
- * must implement.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public interface TabSwitcherLayout {
-
- /**
- * Returns, whether an animation is currently running, or not.
- *
- * @return True, if an animation is currently running, false otherwise
- */
- boolean isAnimationRunning();
-
- /**
- * Returns the view group, which contains the tab switcher's tabs.
- *
- * @return The view group, which contains the tab switcher's tabs, as an instance of the class
- * {@link ViewGroup} or null, if the view has not been laid out yet
- */
- @Nullable
- ViewGroup getTabContainer();
-
- /**
- * Returns the toolbars, which are shown, when the tab switcher is shown. When using the
- * smartphone layout, only one toolbar is shown. When using the tablet layout, a primary and
- * secondary toolbar is shown. In such case, the index {@link TabSwitcher#PRIMARY_TOOLBAR_INDEX}
- * of the returned array corresponds to the primary toolbar and the index {@link
- * TabSwitcher#SECONDARY_TOOLBAR_INDEX} corresponds to the secondary toolbar.
- *
- * @return An array, which contains the toolbars, which are shown, when the tab switcher is
- * shown, as an array of the type Toolbar or null, if the view has not been laid out yet
- */
- @Nullable
- Toolbar[] getToolbars();
-
- /**
- * Returns the menu of the toolbar, which is shown, when the tab switcher is shown. When using
- * the tablet layout, the menu corresponds to the secondary toolbar.
- *
- * @return The menu of the toolbar as an instance of the type {@link Menu} or null, if the view
- * has not been laid out yet
- */
- @Nullable
- Menu getToolbarMenu();
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/phone/PhoneArithmetics.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/phone/PhoneArithmetics.java
deleted file mode 100644
index 7228f1b3..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/phone/PhoneArithmetics.java
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout.phone;
-
-import android.content.res.Resources;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
-import android.widget.FrameLayout;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.widget.Toolbar;
-import de.mrapp.android.tabswitcher.Layout;
-import de.mrapp.android.tabswitcher.R;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.layout.AbstractArithmetics;
-import de.mrapp.android.tabswitcher.layout.AbstractDragTabsEventHandler.DragState;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.util.Condition;
-
-/**
- * Provides methods, which allow to calculate the position, size and rotation of a {@link
- * TabSwitcher}'s tabs, when using the smartphone layout.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class PhoneArithmetics extends AbstractArithmetics {
-
- /**
- * The height of a tab's title container in pixels.
- */
- private final int tabTitleContainerHeight;
-
- /**
- * The inset of tabs in pixels.
- */
- private final int tabInset;
-
- /**
- * The number of tabs, which are contained by a stack.
- */
- private final int stackedTabCount;
-
- /**
- * The space between tabs, which are part of a stack, in pixels.
- */
- private final float stackedTabSpacing;
-
- /**
- * The pivot when overshooting at the end.
- */
- private final float endOvershootPivot;
-
- /**
- * Modifies a specific axis depending on the orientation of the tab switcher.
- *
- * @param axis
- * The original axis as a value of the enum {@link Axis}. The axis may not be null
- * @return The orientation invariant axis as a value of the enum {@link Axis}. The orientation
- * invariant axis may not be null
- */
- @NonNull
- private Axis getOrientationInvariantAxis(@NonNull final Axis axis) {
- if (axis == Axis.Y_AXIS) {
- return Axis.DRAGGING_AXIS;
- } else if (axis == Axis.X_AXIS) {
- return Axis.ORTHOGONAL_AXIS;
- } else if (getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE) {
- return axis == Axis.DRAGGING_AXIS ? Axis.ORTHOGONAL_AXIS : Axis.DRAGGING_AXIS;
- } else {
- return axis;
- }
- }
-
- /**
- * Returns the default pivot of an item on a specific axis.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose pivot should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @return The pivot of the given item on the given axis as a {@link Float} value
- */
- private float getDefaultPivot(@NonNull final Axis axis, @NonNull final AbstractItem item) {
- if (axis == Axis.DRAGGING_AXIS || axis == Axis.Y_AXIS) {
- return getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE ?
- getSize(axis, item) / 2f : 0;
- } else {
- return getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE ? 0 :
- getSize(axis, item) / 2f;
- }
- }
-
- /**
- * Returns the pivot of an item on a specific axis, when it is swiped.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose pivot should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @return The pivot of the given item on the given axis as a {@link Float} value
- */
- private float getPivotWhenSwiping(@NonNull final Axis axis, @NonNull final AbstractItem item) {
- if (axis == Axis.DRAGGING_AXIS || axis == Axis.Y_AXIS) {
- return endOvershootPivot;
- } else {
- return getDefaultPivot(axis, item);
- }
- }
-
- /**
- * Returns the pivot of an item on a specific axis, when overshooting at the start.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose pivot should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @return The pivot of the given item on the given axis as a {@link Float} value
- */
- private float getPivotWhenOvershootingAtStart(@NonNull final Axis axis,
- @NonNull final AbstractItem item) {
- return getSize(axis, item) / 2f;
- }
-
- /**
- * Returns the pivot of an item on a specific axis, when overshooting at the end.
- *
- * @param axis
- * The axis as a value of the enum {@link Axis}. The axis may not be null
- * @param item
- * The item, whose pivot should be returned, as an instance of the class {@link
- * AbstractItem}. The item may not be null
- * @return The pivot of the given item on the given axis as a {@link Float} value
- */
- private float getPivotWhenOvershootingAtEnd(@NonNull final Axis axis,
- @NonNull final AbstractItem item) {
- if (axis == Axis.DRAGGING_AXIS || axis == Axis.Y_AXIS) {
- return getTabSwitcher().getCount() > 1 ? endOvershootPivot : getSize(axis, item) / 2f;
- } else {
- return getSize(axis, item) / 2f;
- }
- }
-
- /**
- * Creates a new class, which provides methods, which allow to calculate the position, size and
- * rotation of a {@link TabSwitcher}'s tabs, when using the smartphone layout.
- *
- * @param tabSwitcher
- * The tab switcher, the arithmetics should be calculated for, as an instance of the
- * class {@link TabSwitcher}. The tab switcher may not be null
- */
- public PhoneArithmetics(@NonNull final TabSwitcher tabSwitcher) {
- super(tabSwitcher);
- Resources resources = tabSwitcher.getResources();
- tabTitleContainerHeight =
- resources.getDimensionPixelSize(R.dimen.tab_title_container_height);
- tabInset = resources.getDimensionPixelSize(R.dimen.tab_inset);
- stackedTabCount = resources.getInteger(R.integer.phone_stacked_tab_count);
- stackedTabSpacing = resources.getDimensionPixelSize(R.dimen.stacked_tab_spacing);
- endOvershootPivot = resources.getDimensionPixelSize(R.dimen.end_overshoot_pivot);
- }
-
- @Override
- public final int getTabSwitcherPadding(@NonNull final Axis axis, final int gravity) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE
- .ensureTrue(gravity == Gravity.START || gravity == Gravity.END, "Invalid gravity");
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- return gravity == Gravity.START ? getTabSwitcher().getPaddingTop() :
- getTabSwitcher().getPaddingBottom();
- } else {
- return gravity == Gravity.START ? getTabSwitcher().getPaddingLeft() :
- getTabSwitcher().getPaddingRight();
- }
- }
-
- @Override
- public final float getTabContainerSize(@NonNull final Axis axis, final boolean includePadding) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- ViewGroup tabContainer = getTabSwitcher().getTabContainer();
- assert tabContainer != null;
- FrameLayout.LayoutParams layoutParams =
- (FrameLayout.LayoutParams) tabContainer.getLayoutParams();
- int padding = !includePadding ? (getTabSwitcherPadding(axis, Gravity.START) +
- getTabSwitcherPadding(axis, Gravity.END)) : 0;
- Toolbar[] toolbars = getTabSwitcher().getToolbars();
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- int toolbarSize =
- !includePadding && getTabSwitcher().areToolbarsShown() && toolbars != null ?
- toolbars[0].getHeight() - tabInset : 0;
- return tabContainer.getHeight() - layoutParams.topMargin - layoutParams.bottomMargin -
- padding - toolbarSize;
- } else {
- return tabContainer.getWidth() - layoutParams.leftMargin - layoutParams.rightMargin -
- padding;
- }
- }
-
- @Override
- public final float getTouchPosition(@NonNull final Axis axis,
- @NonNull final MotionEvent event) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(event, "The motion event may not be null");
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- return event.getY();
- } else {
- return event.getX();
- }
- }
-
- @Override
- public final float getPosition(@NonNull final Axis axis, @NonNull final AbstractItem item) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
- View view = item.getView();
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- Toolbar[] toolbars = getTabSwitcher().getToolbars();
- return view.getY() -
- (getTabSwitcher().areToolbarsShown() && getTabSwitcher().isSwitcherShown() &&
- toolbars != null ?
- toolbars[TabSwitcher.PRIMARY_TOOLBAR_INDEX].getHeight() - tabInset :
- 0) - getTabSwitcherPadding(axis, Gravity.START);
- } else {
- FrameLayout.LayoutParams layoutParams =
- (FrameLayout.LayoutParams) view.getLayoutParams();
- return view.getX() - layoutParams.leftMargin - getTabSwitcher().getPaddingLeft() / 2f +
- getTabSwitcher().getPaddingRight() / 2f +
- (getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE &&
- getTabSwitcher().isSwitcherShown() ?
- stackedTabCount * stackedTabSpacing / 2f : 0);
- }
- }
-
- @Override
- public final void setPosition(@NonNull final Axis axis, @NonNull final AbstractItem item,
- final float position) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
- View view = item.getView();
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- Toolbar[] toolbars = getTabSwitcher().getToolbars();
- view.setY((getTabSwitcher().areToolbarsShown() && getTabSwitcher().isSwitcherShown() &&
- toolbars != null ?
- toolbars[TabSwitcher.PRIMARY_TOOLBAR_INDEX].getHeight() - tabInset : 0) +
- getTabSwitcherPadding(axis, Gravity.START) + position);
- } else {
- FrameLayout.LayoutParams layoutParams =
- (FrameLayout.LayoutParams) view.getLayoutParams();
- view.setX(position + layoutParams.leftMargin + getTabSwitcher().getPaddingLeft() / 2f -
- getTabSwitcher().getPaddingRight() / 2f -
- (getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE &&
- getTabSwitcher().isSwitcherShown() ?
- stackedTabCount * stackedTabSpacing / 2f : 0));
- }
- }
-
- @Override
- public final void animatePosition(@NonNull final Axis axis,
- @NonNull final ViewPropertyAnimator animator,
- @NonNull final AbstractItem item, final float position,
- final boolean includePadding) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(animator, "The animator may not be null");
- Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- Toolbar[] toolbars = getTabSwitcher().getToolbars();
- animator.y((getTabSwitcher().areToolbarsShown() && getTabSwitcher().isSwitcherShown() &&
- toolbars != null ?
- toolbars[TabSwitcher.PRIMARY_TOOLBAR_INDEX].getHeight() - tabInset : 0) +
- (includePadding ? getTabSwitcherPadding(axis, Gravity.START) : 0) + position);
- } else {
- View view = item.getView();
- FrameLayout.LayoutParams layoutParams =
- (FrameLayout.LayoutParams) view.getLayoutParams();
- animator.x(position + layoutParams.leftMargin + (includePadding ?
- getTabSwitcher().getPaddingLeft() / 2f -
- getTabSwitcher().getPaddingRight() / 2f : 0) -
- (getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE &&
- getTabSwitcher().isSwitcherShown() ?
- stackedTabCount * stackedTabSpacing / 2f : 0));
- }
- }
-
- @Override
- public final float getScale(@NonNull final AbstractItem item, final boolean includePadding) {
- Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
- View view = item.getView();
- FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
- float width = view.getWidth();
- float targetWidth = width + layoutParams.leftMargin + layoutParams.rightMargin -
- (includePadding ?
- getTabSwitcher().getPaddingLeft() + getTabSwitcher().getPaddingRight() :
- 0) - (getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE ?
- stackedTabCount * stackedTabSpacing : 0);
- return targetWidth / width;
- }
-
- @Override
- public final void setScale(@NonNull final Axis axis, @NonNull final AbstractItem item,
- final float scale) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
- View view = item.getView();
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- view.setScaleY(scale);
- } else {
- view.setScaleX(scale);
- }
- }
-
- @Override
- public final void animateScale(@NonNull final Axis axis,
- @NonNull final ViewPropertyAnimator animator,
- final float scale) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(animator, "The animator may not be null");
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- animator.scaleY(scale);
- } else {
- animator.scaleX(scale);
- }
- }
-
- @Override
- public final float getSize(@NonNull final Axis axis, @NonNull final AbstractItem item) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
- View view = item.getView();
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- return view.getHeight() * getScale(item);
- } else {
- return view.getWidth() * getScale(item);
- }
- }
-
- @Override
- public final float getPivot(@NonNull final Axis axis, @NonNull final AbstractItem item,
- @NonNull final DragState dragState) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
- Condition.INSTANCE.ensureNotNull(dragState, "The drag state may not be null");
-
- if (dragState == DragState.SWIPE) {
- return getPivotWhenSwiping(axis, item);
- } else if (dragState == DragState.OVERSHOOT_START) {
- return getPivotWhenOvershootingAtStart(axis, item);
- } else if (dragState == DragState.OVERSHOOT_END) {
- return getPivotWhenOvershootingAtEnd(axis, item);
- } else {
- return getDefaultPivot(axis, item);
- }
- }
-
- @Override
- public final void setPivot(@NonNull final Axis axis, @NonNull final AbstractItem item,
- final float pivot) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
- View view = item.getView();
- FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- float newPivot = pivot - layoutParams.topMargin - tabTitleContainerHeight;
- view.setTranslationY(view.getTranslationY() +
- (view.getPivotY() - newPivot) * (1 - view.getScaleY()));
- view.setPivotY(newPivot);
- } else {
- float newPivot = pivot - layoutParams.leftMargin;
- view.setTranslationX(view.getTranslationX() +
- (view.getPivotX() - newPivot) * (1 - view.getScaleX()));
- view.setPivotX(newPivot);
- }
- }
-
- @Override
- public final float getRotation(@NonNull final Axis axis, @NonNull final AbstractItem item) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(item, "The view may not be null");
- View view = item.getView();
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- return view.getRotationY();
- } else {
- return view.getRotationX();
- }
- }
-
- @Override
- public final void setRotation(@NonNull final Axis axis, @NonNull final AbstractItem item,
- final float angle) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(item, "The item may not be null");
- View view = item.getView();
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- view.setRotationY(
- getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE ? -1 * angle : angle);
- } else {
- view.setRotationX(
- getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE ? -1 * angle : angle);
- }
- }
-
- @Override
- public final void animateRotation(@NonNull final Axis axis,
- @NonNull final ViewPropertyAnimator animator,
- final float angle) {
- Condition.INSTANCE.ensureNotNull(axis, "The axis may not be null");
- Condition.INSTANCE.ensureNotNull(animator, "The animator may not be null");
-
- if (getOrientationInvariantAxis(axis) == Axis.DRAGGING_AXIS) {
- animator.rotationY(
- getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE ? -1 * angle : angle);
- } else {
- animator.rotationX(
- getTabSwitcher().getLayout() == Layout.PHONE_LANDSCAPE ? -1 * angle : angle);
- }
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/phone/PhoneDragTabsEventHandler.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/phone/PhoneDragTabsEventHandler.java
deleted file mode 100644
index 75c6b7fb..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/phone/PhoneDragTabsEventHandler.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout.phone;
-
-import android.content.res.Resources;
-import android.view.Gravity;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.widget.Toolbar;
-import de.mrapp.android.tabswitcher.Layout;
-import de.mrapp.android.tabswitcher.R;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.iterator.AbstractItemIterator;
-import de.mrapp.android.tabswitcher.iterator.ItemIterator;
-import de.mrapp.android.tabswitcher.layout.AbstractDragTabsEventHandler;
-import de.mrapp.android.tabswitcher.layout.Arithmetics;
-import de.mrapp.android.tabswitcher.layout.Arithmetics.Axis;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.android.tabswitcher.model.State;
-import de.mrapp.android.tabswitcher.model.TabItem;
-import de.mrapp.android.util.gesture.DragHelper;
-import de.mrapp.android.util.view.AttachedViewRecycler;
-import de.mrapp.util.Condition;
-
-/**
- * A drag handler, which allows to calculate the position and state of tabs on touch events, when
- * using the smartphone layout.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class PhoneDragTabsEventHandler
- extends AbstractDragTabsEventHandler {
-
- /**
- * Defines the interface, a class, which should be notified about the events of a drag handler,
- * must implement.
- */
- public interface Callback extends AbstractDragTabsEventHandler.Callback {
-
- /**
- * The method, which is invoked, when tabs are overshooting at the start.
- *
- * @param position
- * The position of the first tab in pixels as a {@link Float} value
- */
- void onStartOvershoot(float position);
-
- /**
- * The method, which is invoked, when the tabs should be tilted when overshooting at the
- * start.
- *
- * @param angle
- * The angle, the tabs should be tilted by, in degrees as a {@link Float} value
- */
- void onTiltOnStartOvershoot(float angle);
-
- /**
- * The method, which is invoked, when the tabs should be tilted when overshooting at the
- * end.
- *
- * @param angle
- * The angle, the tabs should be tilted by, in degrees as a {@link Float} value
- */
- void onTiltOnEndOvershoot(float angle);
-
- }
-
- /**
- * The view recycler, which allows to inflate the views, which are used to visualize the tabs,
- * whose positions and states are calculated by the drag handler.
- */
- private final AttachedViewRecycler viewRecycler;
-
- /**
- * The drag helper, which is used to recognize drag gestures when overshooting.
- */
- private final DragHelper overshootDragHelper;
-
- /**
- * The maximum overshoot distance in pixels.
- */
- private final int maxOvershootDistance;
-
- /**
- * The maximum angle, tabs can be rotated by, when overshooting at the start, in degrees.
- */
- private final float maxStartOvershootAngle;
-
- /**
- * The maximum angle, tabs can be rotated by, when overshooting at the end, in degrees.
- */
- private final float maxEndOvershootAngle;
-
- /**
- * The number of tabs, which are contained by a stack.
- */
- private final int stackedTabCount;
-
- /**
- * The inset of tabs in pixels.
- */
- private final int tabInset;
-
- /**
- * Notifies the callback, that tabs are overshooting at the start.
- *
- * @param position
- * The position of the first tab in pixels as a {@link Float} value
- */
- private void notifyOnStartOvershoot(final float position) {
- if (getCallback() != null) {
- getCallback().onStartOvershoot(position);
- }
- }
-
- /**
- * Notifies the callback, that the tabs should be tilted when overshooting at the start.
- *
- * @param angle
- * The angle, the tabs should be tilted by, in degrees as a {@link Float} value
- */
- private void notifyOnTiltOnStartOvershoot(final float angle) {
- if (getCallback() != null) {
- getCallback().onTiltOnStartOvershoot(angle);
- }
- }
-
- /**
- * Notifies the callback, that the tabs should be titled when overshooting at the end.
- *
- * @param angle
- * The angle, the tabs should be tilted by, in degrees as a {@link Float} value
- */
- private void notifyOnTiltOnEndOvershoot(final float angle) {
- if (getCallback() != null) {
- getCallback().onTiltOnEndOvershoot(angle);
- }
- }
-
- /**
- * Creates a new drag handler, which allows to calculate the position and state of tabs on touch
- * events, when using the smartphone layout.
- *
- * @param tabSwitcher
- * The tab switcher, whose tabs' positions and states should be calculated by the drag
- * handler, as an instance of the class {@link TabSwitcher}. The tab switcher may not be
- * null
- * @param arithmetics
- * The arithmetics, which should be used to calculate the position, size and rotation of
- * tabs, as an instance of the type {@link Arithmetics}. The arithmetics may not be
- * null
- * @param viewRecycler
- * The view recycler, which allows to inflate the views, which are used to visualize the
- * tabs, whose positions and states should be calculated by the tab switcher, as an
- * instance of the class AttachedViewRecycler. The view recycler may not be null
- */
- public PhoneDragTabsEventHandler(@NonNull final TabSwitcher tabSwitcher,
- @NonNull final Arithmetics arithmetics,
- @NonNull final AttachedViewRecycler viewRecycler) {
- super(tabSwitcher, arithmetics, true);
- Condition.INSTANCE.ensureNotNull(viewRecycler, "The view recycler may not be null");
- this.viewRecycler = viewRecycler;
- this.overshootDragHelper = new DragHelper(0);
- Resources resources = tabSwitcher.getResources();
- this.tabInset = resources.getDimensionPixelSize(R.dimen.tab_inset);
- this.stackedTabCount = resources.getInteger(R.integer.phone_stacked_tab_count);
- this.maxOvershootDistance = resources.getDimensionPixelSize(R.dimen.max_overshoot_distance);
- this.maxStartOvershootAngle = resources.getInteger(R.integer.max_start_overshoot_angle);
- this.maxEndOvershootAngle = resources.getInteger(R.integer.max_end_overshoot_angle);
- }
-
- @Override
- @Nullable
- protected final AbstractItem getFocusedItem(final float position) {
- AbstractItemIterator iterator =
- new ItemIterator.Builder(getTabSwitcher(), viewRecycler).create();
- AbstractItem tabItem;
-
- while ((tabItem = iterator.next()) != null) {
- if (tabItem.getTag().getState() == State.FLOATING ||
- tabItem.getTag().getState() == State.STACKED_START_ATOP) {
- Toolbar[] toolbars = getTabSwitcher().getToolbars();
- float toolbarHeight = getTabSwitcher().getLayout() != Layout.PHONE_LANDSCAPE &&
- getTabSwitcher().areToolbarsShown() && toolbars != null ?
- toolbars[TabSwitcher.PRIMARY_TOOLBAR_INDEX].getHeight() - tabInset : 0;
- float viewPosition =
- getArithmetics().getPosition(Axis.DRAGGING_AXIS, tabItem) + toolbarHeight +
- getArithmetics()
- .getTabSwitcherPadding(Axis.DRAGGING_AXIS, Gravity.START);
-
- if (viewPosition <= position) {
- return tabItem;
- }
- }
- }
-
- return null;
- }
-
- @Override
- protected final float onOvershootStart(final float dragPosition,
- final float overshootThreshold) {
- float result = overshootThreshold;
- overshootDragHelper.update(dragPosition);
- float overshootDistance = overshootDragHelper.getDragDistance();
-
- if (overshootDistance < 0) {
- float absOvershootDistance = Math.abs(overshootDistance);
- float startOvershootDistance =
- getTabSwitcher().getCount() >= stackedTabCount ? maxOvershootDistance :
- (getTabSwitcher().getCount() > 1 ? (float) maxOvershootDistance /
- (float) getTabSwitcher().getCount() : 0);
-
- if (absOvershootDistance <= startOvershootDistance) {
- float ratio =
- Math.max(0, Math.min(1, absOvershootDistance / startOvershootDistance));
- AbstractItemIterator iterator =
- new ItemIterator.Builder(getTabSwitcher(), viewRecycler).create();
- AbstractItem tabItem = iterator.getItem(0);
- float currentPosition = tabItem.getTag().getPosition();
- float position = currentPosition - (currentPosition * ratio);
- notifyOnStartOvershoot(position);
- } else {
- float ratio =
- (absOvershootDistance - startOvershootDistance) / maxOvershootDistance;
-
- if (ratio >= 1) {
- overshootDragHelper.setMinDragDistance(overshootDistance);
- result = dragPosition + maxOvershootDistance + startOvershootDistance;
- }
-
- notifyOnTiltOnStartOvershoot(
- Math.max(0, Math.min(1, ratio)) * maxStartOvershootAngle);
- }
- }
-
- return result;
- }
-
- @Override
- protected final float onOvershootEnd(final float dragPosition, final float overshootThreshold) {
- float result = overshootThreshold;
- overshootDragHelper.update(dragPosition);
- float overshootDistance = overshootDragHelper.getDragDistance();
- float ratio = overshootDistance / maxOvershootDistance;
-
- if (ratio >= 1) {
- overshootDragHelper.setMaxDragDistance(overshootDistance);
- result = dragPosition - maxOvershootDistance;
- }
-
- notifyOnTiltOnEndOvershoot(Math.max(0, Math.min(1, ratio)) *
- -(getTabSwitcher().getCount() > 1 ? maxEndOvershootAngle : maxStartOvershootAngle));
- return result;
- }
-
- @Override
- protected final void onOvershootReverted() {
- overshootDragHelper.reset();
- }
-
- @Override
- protected final void onReset() {
- if (overshootDragHelper != null) {
- overshootDragHelper.reset();
- }
- }
-
- @Override
- protected final boolean isSwipeThresholdReached(@NonNull final TabItem swipedTabItem) {
- return Math.abs(getArithmetics().getPosition(Axis.ORTHOGONAL_AXIS, swipedTabItem)) >
- getArithmetics().getTabContainerSize(Axis.ORTHOGONAL_AXIS) / 6f;
- }
-
-}
\ No newline at end of file
diff --git a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/phone/PhoneTabRecyclerAdapter.java b/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/phone/PhoneTabRecyclerAdapter.java
deleted file mode 100644
index e5339e77..00000000
--- a/chromiumTabs/src/main/java/de/mrapp/android/tabswitcher/layout/phone/PhoneTabRecyclerAdapter.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright 2016 - 2020 Michael Rapp
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package de.mrapp.android.tabswitcher.layout.phone;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout.LayoutParams;
-import android.widget.ImageView;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.content.ContextCompat;
-import androidx.core.util.Pair;
-import de.mrapp.android.tabswitcher.Layout;
-import de.mrapp.android.tabswitcher.R;
-import de.mrapp.android.tabswitcher.Tab;
-import de.mrapp.android.tabswitcher.TabPreviewListener;
-import de.mrapp.android.tabswitcher.TabSwitcher;
-import de.mrapp.android.tabswitcher.iterator.ItemIterator;
-import de.mrapp.android.tabswitcher.layout.AbstractTabRecyclerAdapter;
-import de.mrapp.android.tabswitcher.layout.AbstractTabViewHolder;
-import de.mrapp.android.tabswitcher.model.AbstractItem;
-import de.mrapp.android.tabswitcher.model.TabItem;
-import de.mrapp.android.tabswitcher.model.TabSwitcherModel;
-import de.mrapp.android.tabswitcher.model.TabSwitcherStyle;
-import de.mrapp.android.util.ViewUtil;
-import de.mrapp.android.util.logging.LogLevel;
-import de.mrapp.android.util.multithreading.AbstractDataBinder;
-import de.mrapp.android.util.view.ViewRecycler;
-import de.mrapp.util.Condition;
-
-/**
- * A view recycler adapter, which allows to inflate the views, which are used to visualize the tabs
- * of a {@link TabSwitcher}, when using the smartphone layout.
- *
- * @author Michael Rapp
- * @since 0.1.0
- */
-public class PhoneTabRecyclerAdapter extends AbstractTabRecyclerAdapter
- implements AbstractDataBinder.Listener