From 518651b99bb7d7b7b135944312eec34f9b034640 Mon Sep 17 00:00:00 2001 From: Alexander Dadukin Date: Sun, 28 Mar 2021 22:07:10 +0100 Subject: [PATCH 1/5] Refactored menu item to support show and hide. --- .../screens/JavaActivity.java | 8 +- .../screens/NotificationBadgeActivity.kt | 13 +-- .../ProgrammaticallyCreatedDemoActivity.kt | 6 +- .../parsers/ExpandableBottomBarParserTest.kt | 4 +- .../ExpandableBottomBar.kt | 105 ++++++++++-------- .../ExpandableBottomBarNotification.kt | 56 ---------- .../st235/lib_expandablebottombar/MenuItem.kt | 33 ++++++ ...omBarMenuItem.kt => MenuItemDescriptor.kt} | 36 +++--- ...eItemViewController.kt => MenuItemImpl.kt} | 97 +++++++++++----- .../lib_expandablebottombar/Notification.kt | 74 ++++++++++++ ...ificationBadge.kt => NotificationBadge.kt} | 12 +- ...ttomBarMenuItemView.kt => MenuItemView.kt} | 32 ++++-- .../ExpandableBottomBarNavigationUI.kt | 14 +-- .../parsers/ExpandableBottomBarParser.kt | 12 +- .../utils/AndroidUtils.kt | 15 +++ .../ExpandableItemViewControllerTest.kt | 37 ------ ...uItemTest.kt => MenuItemDescriptorTest.kt} | 24 ++-- .../expandablebottombar/MenuItemImplTest.kt | 37 ++++++ 18 files changed, 366 insertions(+), 249 deletions(-) delete mode 100644 lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarNotification.kt create mode 100644 lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItem.kt rename lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/{ExpandableBottomBarMenuItem.kt => MenuItemDescriptor.kt} (76%) rename lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/{ExpandableItemViewController.kt => MenuItemImpl.kt} (68%) create mode 100644 lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/Notification.kt rename lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/{ExpandableBottomBarNotificationBadge.kt => NotificationBadge.kt} (56%) rename lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/components/{ExpandableBottomBarMenuItemView.kt => MenuItemView.kt} (79%) delete mode 100644 lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/ExpandableItemViewControllerTest.kt rename lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/{ExpandableBottomBarMenuItemTest.kt => MenuItemDescriptorTest.kt} (55%) create mode 100644 lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemImplTest.kt diff --git a/app/src/main/java/github/com/st235/expandablebottombar/screens/JavaActivity.java b/app/src/main/java/github/com/st235/expandablebottombar/screens/JavaActivity.java index 8e0b861..e9587a0 100644 --- a/app/src/main/java/github/com/st235/expandablebottombar/screens/JavaActivity.java +++ b/app/src/main/java/github/com/st235/expandablebottombar/screens/JavaActivity.java @@ -8,23 +8,21 @@ import github.com.st235.expandablebottombar.R; import github.com.st235.lib_expandablebottombar.ExpandableBottomBar; -import github.com.st235.lib_expandablebottombar.ExpandableBottomBarMenuItem; +import github.com.st235.lib_expandablebottombar.MenuItemDescriptor; public class JavaActivity extends AppCompatActivity { private static final String TAG = JavaActivity.class.getSimpleName(); - private ExpandableBottomBar bottomBar; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_java); - bottomBar = findViewById(R.id.expandable_bottom_bar); + ExpandableBottomBar bottomBar = findViewById(R.id.expandable_bottom_bar); bottomBar.addItems( - new ExpandableBottomBarMenuItem.Builder(this) + new MenuItemDescriptor.Builder(this) .addItem(R.id.icon_home, R.drawable.ic_home, R.string.text, Color.GRAY) .addItem(R.id.icon_likes, R.drawable.ic_likes, R.string.text2, 0xffff77a9) .addItem(R.id.icon_bookmarks, R.drawable.ic_bookmarks, R.string.text3, 0xff58a5f0) diff --git a/app/src/main/java/github/com/st235/expandablebottombar/screens/NotificationBadgeActivity.kt b/app/src/main/java/github/com/st235/expandablebottombar/screens/NotificationBadgeActivity.kt index a8e5f10..a33870a 100644 --- a/app/src/main/java/github/com/st235/expandablebottombar/screens/NotificationBadgeActivity.kt +++ b/app/src/main/java/github/com/st235/expandablebottombar/screens/NotificationBadgeActivity.kt @@ -10,15 +10,13 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.graphics.ColorUtils import github.com.st235.expandablebottombar.R import github.com.st235.lib_expandablebottombar.ExpandableBottomBar -import github.com.st235.lib_expandablebottombar.ExpandableBottomBarNotification +import github.com.st235.lib_expandablebottombar.Notification import kotlinx.android.synthetic.main.activity_xml_declared.* class NotificationBadgeActivity : AppCompatActivity() { private lateinit var bottomBar: ExpandableBottomBar - private val notificationsLookup = mutableMapOf() - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_notification_badge) @@ -40,10 +38,7 @@ class NotificationBadgeActivity : AppCompatActivity() { } bottomBar.onItemReselectedListener = { v, i -> - if (!notificationsLookup.containsKey(i.itemId)) { - notificationsLookup[i.itemId] = bottomBar.getNotificationFor(i.itemId) - } - val notification = notificationsLookup.getValue(i.itemId) + val notification = i.notification() if (v.tag == null) { notification.show() @@ -64,8 +59,8 @@ class NotificationBadgeActivity : AppCompatActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.clear -> { - for (notification in notificationsLookup.values) { - notification.clear() + for (menuItem in bottomBar.getMenuItems()) { + menuItem.notification().clear() } } } diff --git a/app/src/main/java/github/com/st235/expandablebottombar/screens/ProgrammaticallyCreatedDemoActivity.kt b/app/src/main/java/github/com/st235/expandablebottombar/screens/ProgrammaticallyCreatedDemoActivity.kt index 3036e73..191f216 100644 --- a/app/src/main/java/github/com/st235/expandablebottombar/screens/ProgrammaticallyCreatedDemoActivity.kt +++ b/app/src/main/java/github/com/st235/expandablebottombar/screens/ProgrammaticallyCreatedDemoActivity.kt @@ -9,7 +9,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.graphics.ColorUtils import github.com.st235.expandablebottombar.R import github.com.st235.lib_expandablebottombar.ExpandableBottomBar -import github.com.st235.lib_expandablebottombar.ExpandableBottomBarMenuItem +import github.com.st235.lib_expandablebottombar.MenuItemDescriptor class ProgrammaticallyCreatedDemoActivity : AppCompatActivity() { @@ -24,7 +24,7 @@ class ProgrammaticallyCreatedDemoActivity : AppCompatActivity() { color.setBackgroundColor(ColorUtils.setAlphaComponent(Color.GRAY, 60)) bottomBar.addItems( - ExpandableBottomBarMenuItem.Builder(this) + MenuItemDescriptor.Builder(this) .addItem( R.id.icon_home, R.drawable.ic_home, @@ -57,7 +57,7 @@ class ProgrammaticallyCreatedDemoActivity : AppCompatActivity() { } bottomBar.onItemReselectedListener = { _, i -> - Log.d("ExpandableBottomBar", "OnReselected: ${i.itemId}") + Log.d("ExpandableBottomBar", "OnReselected: ${i.id}") } } } diff --git a/lib-expandablebottombar/src/androidTest/java/github/com/st235/expandablebottombar/parsers/ExpandableBottomBarParserTest.kt b/lib-expandablebottombar/src/androidTest/java/github/com/st235/expandablebottombar/parsers/ExpandableBottomBarParserTest.kt index 5357dcf..6006a8f 100644 --- a/lib-expandablebottombar/src/androidTest/java/github/com/st235/expandablebottombar/parsers/ExpandableBottomBarParserTest.kt +++ b/lib-expandablebottombar/src/androidTest/java/github/com/st235/expandablebottombar/parsers/ExpandableBottomBarParserTest.kt @@ -5,7 +5,7 @@ import android.graphics.Color import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import androidx.test.platform.app.InstrumentationRegistry -import github.com.st235.lib_expandablebottombar.ExpandableBottomBarMenuItem +import github.com.st235.lib_expandablebottombar.MenuItemDescriptor import github.com.st235.lib_expandablebottombar.parsers.ExpandableBottomBarParser import org.junit.Before import org.junit.runner.RunWith @@ -45,7 +45,7 @@ class ExpandableBottomBarParserTest { val items = expandableBottomBarParser.inflate(R.menu.valid_menu) val iconText = appContext.getString(R.string.icon_text) val actualItem = - ExpandableBottomBarMenuItem(R.id.icon_id, R.drawable.item_icon, iconText, Color.WHITE, null, null) + MenuItemDescriptor(R.id.icon_id, R.drawable.item_icon, iconText, Color.WHITE, null, null) assertThat(items, contains(actualItem)) } } diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBar.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBar.kt index bd90f1f..010f72b 100644 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBar.kt +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBar.kt @@ -30,7 +30,7 @@ import github.com.st235.lib_expandablebottombar.ExpandableBottomBar.ItemStyle.Co import github.com.st235.lib_expandablebottombar.behavior.ExpandableBottomBarBehavior import github.com.st235.lib_expandablebottombar.parsers.ExpandableBottomBarParser import github.com.st235.lib_expandablebottombar.state.BottomBarSavedState -import github.com.st235.lib_expandablebottombar.utils.AnimationHelper +import github.com.st235.lib_expandablebottombar.utils.* import github.com.st235.lib_expandablebottombar.utils.DrawableHelper import github.com.st235.lib_expandablebottombar.utils.StyleController import github.com.st235.lib_expandablebottombar.utils.applyForApiLAndHigher @@ -41,7 +41,7 @@ import github.com.st235.lib_expandablebottombar.utils.toPx internal const val ITEM_NOT_SELECTED = -1 -typealias OnItemClickListener = (v: View, menuItem: ExpandableBottomBarMenuItem) -> Unit +typealias OnItemClickListener = (v: View, menuItem: MenuItem) -> Unit /** * Widget, which implements bottom bar navigation pattern @@ -88,8 +88,7 @@ class ExpandableBottomBar @JvmOverloads constructor( @IdRes private var selectedItemId: Int = ITEM_NOT_SELECTED - private val menuItems = mutableListOf() - private val viewControllers: MutableMap = mutableMapOf() + private val menuItems: MutableMap = mutableMapOf() private val stateController = ExpandableBottomBarStateController(this) private lateinit var styleController: StyleController @@ -201,7 +200,7 @@ class ExpandableBottomBar @JvmOverloads constructor( } } - override fun onSaveInstanceState(): Parcelable? { + override fun onSaveInstanceState(): Parcelable { val superState = super.onSaveInstanceState() return stateController.store(superState) } @@ -220,33 +219,47 @@ class ExpandableBottomBar @JvmOverloads constructor( bounds.set(0, 0, w, h) } + /** + * Returns menu item for the given id value + * + * @throws NullPointerException when id doesn't exists + */ + fun getMenuItemFor(@IdRes id: Int): MenuItem { + return menuItems.getValue(id) + } + /** * Returns notification for passed menu item * * @throws NullPointerException when id doesn't exists */ - fun getNotificationFor(@IdRes id: Int): ExpandableBottomBarNotification { - return viewControllers.getValue(id).notification() + @Deprecated( + message = "This method was replaced with MenuItem#notification", + replaceWith = ReplaceWith(expression = "this.getMenuItemFor(id = id).notification()"), + level = DeprecationLevel.ERROR + ) + fun getNotificationFor(@IdRes id: Int): Notification { + return menuItems.getValue(id).notification() } /** * Adds passed items to widget * - * @param items - bottom bar menu items + * @param itemDescriptors - bottom bar menu items */ - fun addItems(items: List) { + fun addItems(itemDescriptors: List) { menuItems.clear() - val firstItemId = items.first().itemId - val lastItemId = items.last().itemId + val firstItemId = itemDescriptors.first().itemId + val lastItemId = itemDescriptors.last().itemId selectedItemId = firstItemId - for ((i, item) in items.withIndex()) { + for ((i, item) in itemDescriptors.withIndex()) { val viewController = createItem(item) - viewControllers[item.itemId] = viewController + menuItems[item.itemId] = viewController - val prevIconId = if (i - 1 < 0) firstItemId else items[i - 1].itemId - val nextIconId = if (i + 1 >= items.size) lastItemId else items[i + 1].itemId + val prevIconId = if (i - 1 < 0) firstItemId else itemDescriptors[i - 1].itemId + val nextIconId = if (i + 1 >= itemDescriptors.size) lastItemId else itemDescriptors[i + 1].itemId viewController.attachTo( this, @@ -255,11 +268,13 @@ class ExpandableBottomBar @JvmOverloads constructor( ) } - menuItems.addAll(items) - madeMenuItemsAccessible(items) + madeMenuItemsAccessible(itemDescriptors) } - internal fun getMenuItems(): List = menuItems + /** + * Returns all menu items + */ + fun getMenuItems(): List = menuItems.values.toList() /** * Programmatically select item @@ -267,14 +282,14 @@ class ExpandableBottomBar @JvmOverloads constructor( * @param id - identifier of menu item, which should be selected */ fun select(@IdRes id: Int) { - val itemToSelect = viewControllers.getValue(id) - onItemSelected(itemToSelect.menuItem) + val itemToSelect = menuItems.getValue(id) + onItemSelected(itemToSelect) } /** * Returns currently selected item */ - fun getSelected(): ExpandableBottomBarMenuItem = viewControllers.getValue(selectedItemId).menuItem + fun getSelected(): MenuItem = menuItems.getValue(selectedItemId) /** * Shows the bottom bar @@ -308,25 +323,25 @@ class ExpandableBottomBar @JvmOverloads constructor( } } - private fun madeMenuItemsAccessible(items: List) { - for ((i, item) in items.withIndex()) { - val prev = viewControllers[items.getOrNull(i - 1)?.itemId] - val next = viewControllers[items.getOrNull(i + 1)?.itemId] + private fun madeMenuItemsAccessible(itemDescriptors: List) { + for ((i, item) in itemDescriptors.withIndex()) { + val prev = menuItems[itemDescriptors.getOrNull(i - 1)?.itemId] + val next = menuItems[itemDescriptors.getOrNull(i + 1)?.itemId] - viewControllers[item.itemId]?.setAccessibleWith(prev = prev, next = next) + menuItems[item.itemId]?.setAccessibleWith(prev = prev, next = next) } } - private fun createItem(menuItem: ExpandableBottomBarMenuItem): ExpandableItemViewController { - val viewController = - ExpandableItemViewController.Builder(menuItem) + private fun createItem(menuItemDescriptor: MenuItemDescriptor): MenuItemImpl { + val menuItem = + MenuItemImpl.Builder(menuItemDescriptor) .styleController(styleController) .itemMargins(menuHorizontalPadding, menuVerticalPadding) .itemBackground(itemBackgroundCornerRadius, itemBackgroundOpacity) .itemInactiveColor(itemInactiveColor) .notificationBadgeColor(globalBadgeColor) .notificationBadgeTextColor(globalBadgeTextColor) - .onItemClickListener { v: View -> + .onItemClickListener { menuItem: MenuItem, v: View -> if (!v.isSelected) { onItemSelected(menuItem) onItemSelectedListener?.invoke(v, menuItem) @@ -334,38 +349,32 @@ class ExpandableBottomBar @JvmOverloads constructor( onItemReselectedListener?.invoke(v, menuItem) } } - .build(context) + .build(this) - if (selectedItemId == menuItem.itemId) { - viewController.select() + if (selectedItemId == menuItemDescriptor.itemId) { + menuItem.select() } - return viewController + return menuItem } - private fun onItemSelected(activeMenuItem: ExpandableBottomBarMenuItem) { - if (selectedItemId == activeMenuItem.itemId) { + private fun onItemSelected(activeMenuItem: MenuItem) { + if (selectedItemId == activeMenuItem.id) { return } - applyTransition() + delayTransition(duration = transitionDuration.toLong()) val set = ConstraintSet() set.clone(this) - viewControllers.getValue(activeMenuItem.itemId).select() - viewControllers.getValue(selectedItemId).unselect() - selectedItemId = activeMenuItem.itemId + menuItems.getValue(activeMenuItem.id).select() + menuItems.getValue(selectedItemId).deselect() + selectedItemId = activeMenuItem.id set.applyTo(this) } - private fun applyTransition() { - val autoTransition = AutoTransition() - autoTransition.duration = transitionDuration.toLong() - TransitionManager.beginDelayedTransition(this, autoTransition) - } - internal class ExpandableBottomBarStateController( private val expandableBottomBar: ExpandableBottomBar ) { @@ -374,8 +383,8 @@ class ExpandableBottomBar @JvmOverloads constructor( fun restore(stateBottomBar: BottomBarSavedState) { val selectedItemId = stateBottomBar.selectedItem - val viewController = expandableBottomBar.viewControllers.getValue(selectedItemId) - expandableBottomBar.onItemSelected(viewController.menuItem) + val menuItem = expandableBottomBar.menuItems.getValue(selectedItemId) + expandableBottomBar.onItemSelected(menuItem) } } diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarNotification.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarNotification.kt deleted file mode 100644 index d2671e2..0000000 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarNotification.kt +++ /dev/null @@ -1,56 +0,0 @@ -package github.com.st235.lib_expandablebottombar - -import androidx.annotation.ColorInt -import java.lang.ref.WeakReference - -class ExpandableBottomBarNotification internal constructor( - notificationView: ExpandableBottomBarNotificationBadge -) { - - private val viewRef = WeakReference(notificationView) - - private val view: ExpandableBottomBarNotificationBadge? - get() { - return viewRef.get() - } - - /** - * @param color - background color of a badge - */ - fun setBadgeColor(@ColorInt color: Int) { - view?.setNotificationBadgeBackground(color) - } - - /** - * @param color - text color of a badge - */ - fun setBadgeTextColor(@ColorInt color: Int) { - view?.setNotificationBadgeTextColor(color) - } - - /** - * Shows small dot-notification - */ - fun show() { - view?.showNotification() - } - - /** - * Shows notification badge - * with passed text - * - * Text should be no longer than 4 characters - * - * @throws IllegalArgumentException when text is longer than expected - */ - fun show(text: String) { - view?.showNotification(text) - } - - /** - * Removes notification badge - */ - fun clear() { - view?.clearNotification() - } -} diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItem.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItem.kt new file mode 100644 index 0000000..4a4c92f --- /dev/null +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItem.kt @@ -0,0 +1,33 @@ +package github.com.st235.lib_expandablebottombar + +import androidx.annotation.ColorInt +import androidx.annotation.IdRes + +interface MenuItem { + + @get:IdRes + val id: Int + + val text: CharSequence + + @get:ColorInt + val activeColor: Int + + val isShown: Boolean + + /** + * Shows item + */ + fun show() + + /** + * Hides item + * + * @throws IllegalStateException when item is selected + */ + @Throws(IllegalStateException::class) + fun hide() + + fun notification(): Notification + +} diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarMenuItem.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItemDescriptor.kt similarity index 76% rename from lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarMenuItem.kt rename to lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItemDescriptor.kt index bd72ba9..bfd9ce3 100644 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarMenuItem.kt +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItemDescriptor.kt @@ -13,7 +13,7 @@ import java.lang.IllegalStateException /** * Menu item for expandable bottom bar */ -data class ExpandableBottomBarMenuItem( +data class MenuItemDescriptor( @IdRes val itemId: Int, @DrawableRes val iconId: Int, val text: CharSequence, @@ -21,7 +21,7 @@ data class ExpandableBottomBarMenuItem( @ColorInt val badgeBackgroundColor: Int?, @ColorInt val badgeTextColor: Int? ) { - class ItemBuildRequest internal constructor( + class BuildRequest internal constructor( private val builder: Builder, private val context: Context ) { @@ -40,52 +40,52 @@ data class ExpandableBottomBarMenuItem( @ColorInt var badgeTextColor: Int? = null - fun id(@IdRes id: Int): ItemBuildRequest { + fun id(@IdRes id: Int): BuildRequest { this.itemId = id return this } - fun icon(@DrawableRes iconId: Int): ItemBuildRequest { + fun icon(@DrawableRes iconId: Int): BuildRequest { this.iconId = iconId return this } - fun text(text: CharSequence): ItemBuildRequest { + fun text(text: CharSequence): BuildRequest { this.text = text return this } - fun textRes(@StringRes textId: Int): ItemBuildRequest { + fun textRes(@StringRes textId: Int): BuildRequest { this.text = context.getText(textId) return this } - fun color(@ColorInt color: Int): ItemBuildRequest { + fun color(@ColorInt color: Int): BuildRequest { this.activeColor = color return this } - fun colorRes(@ColorRes colorId: Int): ItemBuildRequest { + fun colorRes(@ColorRes colorId: Int): BuildRequest { this.activeColor = ContextCompat.getColor(context, colorId) return this } - fun badgeBackgroundColor(@ColorInt badgeBackgroundColor: Int): ItemBuildRequest { + fun badgeBackgroundColor(@ColorInt badgeBackgroundColor: Int): BuildRequest { this.badgeBackgroundColor = badgeBackgroundColor return this } - fun badgeBackgroundColorRes(@ColorRes badgeBackgroundColorRes: Int): ItemBuildRequest { + fun badgeBackgroundColorRes(@ColorRes badgeBackgroundColorRes: Int): BuildRequest { this.badgeBackgroundColor = ContextCompat.getColor(context, badgeBackgroundColorRes) return this } - fun badgeTextColor(@ColorInt badgeTextColor: Int): ItemBuildRequest { + fun badgeTextColor(@ColorInt badgeTextColor: Int): BuildRequest { this.badgeTextColor = badgeTextColor return this } - fun badgeTextColorRes(@ColorRes badgeTextColorRes: Int): ItemBuildRequest { + fun badgeTextColorRes(@ColorRes badgeTextColorRes: Int): BuildRequest { this.badgeTextColor = ContextCompat.getColor(context, badgeTextColorRes) return this } @@ -103,7 +103,7 @@ data class ExpandableBottomBarMenuItem( fun create(): Builder { assertValidity() builder.items.add( - ExpandableBottomBarMenuItem( + MenuItemDescriptor( itemId, iconId, text!!, @@ -120,21 +120,21 @@ data class ExpandableBottomBarMenuItem( * Class-helper to create expandable bottom bar menu items */ class Builder(private val context: Context) { - internal val items = mutableListOf() + internal val items = mutableListOf() - fun addItem() = ItemBuildRequest(this, context) + fun addItem() = BuildRequest(this, context) fun addItem(@IdRes itemId: Int, @DrawableRes iconId: Int) = - ItemBuildRequest(this, context).id(itemId).icon(iconId) + BuildRequest(this, context).id(itemId).icon(iconId) fun addItem( @IdRes itemId: Int, @DrawableRes iconId: Int, @StringRes textId: Int, @ColorInt activeColor: Int = Color.BLACK - ) = ItemBuildRequest(this, context).id(itemId).icon(iconId).textRes(textId) + ) = BuildRequest(this, context).id(itemId).icon(iconId).textRes(textId) .color(activeColor).create() - fun build(): List = items + fun build(): List = items } } diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableItemViewController.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItemImpl.kt similarity index 68% rename from lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableItemViewController.kt rename to lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItemImpl.kt index 3ac498a..3ebbdf0 100644 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableItemViewController.kt +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/MenuItemImpl.kt @@ -13,18 +13,29 @@ import androidx.constraintlayout.widget.ConstraintSet import androidx.core.view.AccessibilityDelegateCompat import androidx.core.view.ViewCompat.setAccessibilityDelegate import androidx.core.view.accessibility.AccessibilityNodeInfoCompat -import github.com.st235.lib_expandablebottombar.components.ExpandableBottomBarMenuItemView +import github.com.st235.lib_expandablebottombar.components.MenuItemView +import github.com.st235.lib_expandablebottombar.utils.* import github.com.st235.lib_expandablebottombar.utils.DrawableHelper import github.com.st235.lib_expandablebottombar.utils.StyleController import github.com.st235.lib_expandablebottombar.utils.createChain +import github.com.st235.lib_expandablebottombar.utils.show -internal class ExpandableItemViewController( - internal val menuItem: ExpandableBottomBarMenuItem, - private val itemView: ExpandableBottomBarMenuItemView -) { +internal class MenuItemImpl( + menuItemDescriptor: MenuItemDescriptor, + private val rootView: ExpandableBottomBar, + private val itemView: MenuItemView +): MenuItem { - fun setAccessibleWith(prev: ExpandableItemViewController?, - next: ExpandableItemViewController?) { + private val notification = Notification(itemView) + + override val id: Int = menuItemDescriptor.itemId + + override val text: CharSequence = menuItemDescriptor.text + + override val activeColor: Int = menuItemDescriptor.activeColor + + fun setAccessibleWith(prev: MenuItemImpl?, + next: MenuItemImpl?) { setAccessibilityDelegate(itemView, object : AccessibilityDelegateCompat() { override fun onInitializeAccessibilityNodeInfo(host: View?, info: AccessibilityNodeInfoCompat?) { info?.setTraversalAfter(prev?.itemView) @@ -34,18 +45,37 @@ internal class ExpandableItemViewController( }) } - fun notification(): ExpandableBottomBarNotification { - return ExpandableBottomBarNotification(itemView) + override val isShown: Boolean + get() { + return itemView.visibility == View.VISIBLE + } + + override fun show() { + rootView.delayTransition() + itemView.show() } - fun unselect() { - itemView.deselect() + override fun hide() { + if (rootView.getSelected() == this) { + throw IllegalStateException("Cannot hide active tab") + } + + rootView.delayTransition() + itemView.show(isShown = false) + } + + override fun notification(): Notification { + return notification } fun select() { itemView.select() } + fun deselect() { + itemView.deselect() + } + fun attachTo(parent: ConstraintLayout, previousIconId: Int, nextIconId: Int, @@ -84,7 +114,7 @@ internal class ExpandableItemViewController( } //TODO(st235): separate this builder to view factory - class Builder(private val menuItem: ExpandableBottomBarMenuItem) { + class Builder(private val menuItemDescriptor: MenuItemDescriptor) { @Px private var itemVerticalPadding: Int = 0 @@ -103,7 +133,7 @@ internal class ExpandableItemViewController( private var notificationBadgeTextColor: Int = Color.WHITE private lateinit var styleController: StyleController - private lateinit var onItemClickListener: (View) -> Unit + private lateinit var onItemClickListener: (MenuItem, View) -> Unit fun itemMargins( @Px itemHorizontalPadding: Int, @@ -126,7 +156,7 @@ internal class ExpandableItemViewController( return this } - fun onItemClickListener(onItemClickListener: (View) -> Unit): Builder { + fun onItemClickListener(onItemClickListener: (MenuItem, View) -> Unit): Builder { this.onItemClickListener = onItemClickListener return this } @@ -148,41 +178,48 @@ internal class ExpandableItemViewController( private fun createHighlightedMenuShape(): Drawable { return styleController.createStateBackground( - menuItem.activeColor, + menuItemDescriptor.activeColor, backgroundCornerRadius, backgroundOpacity ) } - private fun createMenuItemView(context: Context): ExpandableBottomBarMenuItemView { - return ExpandableBottomBarMenuItemView(context = context) + private fun createMenuItemView(context: Context): MenuItemView { + return MenuItemView(context = context) } - fun build(context: Context): ExpandableItemViewController { + fun build(rootView: ExpandableBottomBar): MenuItemImpl { + val context: Context = rootView.context + val itemView = createMenuItemView(context) + val menuItem = MenuItemImpl( + menuItemDescriptor, + rootView, + itemView + ) + val backgroundColorStateList = DrawableHelper.createSelectedUnselectedStateList( - menuItem.activeColor, + menuItemDescriptor.activeColor, itemInactiveColor ) with(itemView) { - id = menuItem.itemId - contentDescription = context.resources.getString(R.string.accessibility_item_description, menuItem.text) + id = menuItemDescriptor.itemId + contentDescription = context.resources.getString(R.string.accessibility_item_description, menuItemDescriptor.text) setPadding(itemHorizontalPadding, itemVerticalPadding, itemHorizontalPadding, itemVerticalPadding) - setIcon(menuItem.iconId, backgroundColorStateList) - setText(menuItem.text, backgroundColorStateList) - setNotificationBadgeBackground(menuItem.badgeBackgroundColor ?: notificationBadgeColor) - setNotificationBadgeTextColor(menuItem.badgeTextColor ?: notificationBadgeTextColor) + setIcon(menuItemDescriptor.iconId, backgroundColorStateList) + setText(menuItemDescriptor.text, backgroundColorStateList) + notificationBadgeBackgroundColor = menuItemDescriptor.badgeBackgroundColor ?: notificationBadgeColor + notificationBadgeTextColor = menuItemDescriptor.badgeTextColor ?: notificationBadgeTextColor background = createHighlightedMenuShape() - setOnClickListener(onItemClickListener) + setOnClickListener { + onItemClickListener(menuItem, it) + } } - return ExpandableItemViewController( - menuItem, - itemView - ) + return menuItem } } } diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/Notification.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/Notification.kt new file mode 100644 index 0000000..abf2d69 --- /dev/null +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/Notification.kt @@ -0,0 +1,74 @@ +package github.com.st235.lib_expandablebottombar + +import androidx.annotation.ColorInt +import java.lang.ref.WeakReference + +class Notification internal constructor( + badge: NotificationBadge +) { + + private val viewRef = WeakReference(badge) + + private val view: NotificationBadge? + get() { + return viewRef.get() + } + + /** + * background color of a badge + * + * * @throws IllegalStateException when view is destroyed + */ + @get:ColorInt + @get:Throws(IllegalStateException::class) + var badgeColor: Int + set(@ColorInt value: Int) { + view?.notificationBadgeBackgroundColor = value + } + get() { + val view = view ?: throw IllegalStateException("View is not longer active") + return view.notificationBadgeBackgroundColor + } + + /** + * text color of a badge + * + * @throws IllegalStateException when view is destroyed + */ + @get:ColorInt + @get:Throws(IllegalStateException::class) + var badgeTextColor: Int + set(@ColorInt value: Int) { + view?.notificationBadgeTextColor = value + } + get() { + val view = view ?: throw IllegalStateException("View is not longer active") + return view.notificationBadgeTextColor + } + + /** + * Shows small dot-notification + */ + fun show() { + view?.showNotification() + } + + /** + * Shows notification badge + * with passed text + * + * Text should be no longer than 4 characters + * + * @throws IllegalArgumentException when text is longer than expected + */ + fun show(text: String) { + view?.showNotification(text) + } + + /** + * Removes notification badge + */ + fun clear() { + view?.clearNotification() + } +} diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarNotificationBadge.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/NotificationBadge.kt similarity index 56% rename from lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarNotificationBadge.kt rename to lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/NotificationBadge.kt index cc1d4e4..369c5df 100644 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/ExpandableBottomBarNotificationBadge.kt +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/NotificationBadge.kt @@ -2,7 +2,13 @@ package github.com.st235.lib_expandablebottombar import androidx.annotation.ColorInt -internal interface ExpandableBottomBarNotificationBadge { +internal interface NotificationBadge { + + @get:ColorInt + var notificationBadgeBackgroundColor: Int + + @get:ColorInt + var notificationBadgeTextColor: Int fun showNotification() @@ -11,8 +17,4 @@ internal interface ExpandableBottomBarNotificationBadge { fun clearNotification() - fun setNotificationBadgeBackground(@ColorInt color: Int) - - fun setNotificationBadgeTextColor(@ColorInt color: Int) - } diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/components/ExpandableBottomBarMenuItemView.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/components/MenuItemView.kt similarity index 79% rename from lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/components/ExpandableBottomBarMenuItemView.kt rename to lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/components/MenuItemView.kt index 947e122..ef4067c 100644 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/components/ExpandableBottomBarMenuItemView.kt +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/components/MenuItemView.kt @@ -7,16 +7,33 @@ import android.util.AttributeSet import android.view.Gravity import android.view.View import android.widget.LinearLayout +import androidx.annotation.ColorInt import androidx.annotation.DrawableRes -import github.com.st235.lib_expandablebottombar.ExpandableBottomBarNotificationBadge +import github.com.st235.lib_expandablebottombar.NotificationBadge import github.com.st235.lib_expandablebottombar.R import github.com.st235.lib_expandablebottombar.state.MenuItemSavedState import github.com.st235.lib_expandablebottombar.utils.DrawableHelper import kotlinx.android.synthetic.main.content_bottombar_menu_item.view.* -internal class ExpandableBottomBarMenuItemView @JvmOverloads constructor( +internal class MenuItemView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : LinearLayout(context, attrs, defStyleAttr), ExpandableBottomBarNotificationBadge { +) : LinearLayout(context, attrs, defStyleAttr), NotificationBadge { + + override var notificationBadgeBackgroundColor: Int + get() { + return iconView.badgeColor + } + set(@ColorInt value) { + iconView.badgeColor = value + } + + override var notificationBadgeTextColor: Int + get() { + return iconView.badgeTextColor + } + set(@ColorInt value) { + iconView.badgeTextColor = value + } init { inflate(context, R.layout.content_bottombar_menu_item, this) @@ -28,7 +45,7 @@ internal class ExpandableBottomBarMenuItemView @JvmOverloads constructor( clipChildren = false } - override fun onSaveInstanceState(): Parcelable? { + override fun onSaveInstanceState(): Parcelable { return MenuItemSavedState(iconView.getState(), super.onSaveInstanceState()) } @@ -89,11 +106,4 @@ internal class ExpandableBottomBarMenuItemView @JvmOverloads constructor( iconView.badgeText = null } - override fun setNotificationBadgeBackground(color: Int) { - iconView.badgeColor = color - } - - override fun setNotificationBadgeTextColor(color: Int) { - iconView.badgeTextColor = color - } } diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/navigation/ExpandableBottomBarNavigationUI.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/navigation/ExpandableBottomBarNavigationUI.kt index 49ea1ac..dcaaefa 100644 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/navigation/ExpandableBottomBarNavigationUI.kt +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/navigation/ExpandableBottomBarNavigationUI.kt @@ -8,7 +8,7 @@ import androidx.navigation.NavDestination import androidx.navigation.NavGraph import androidx.navigation.NavOptions import github.com.st235.lib_expandablebottombar.ExpandableBottomBar -import github.com.st235.lib_expandablebottombar.ExpandableBottomBarMenuItem +import github.com.st235.lib_expandablebottombar.MenuItem import github.com.st235.lib_expandablebottombar.R import java.lang.ref.WeakReference @@ -36,18 +36,18 @@ object ExpandableBottomBarNavigationUI { return } for (menuItem in view.getMenuItems()) { - if (destination.matchDestination(menuItem.itemId)) { - expandableBottomBar.select(menuItem.itemId) + if (destination.matchDestination(menuItem.id)) { + expandableBottomBar.select(menuItem.id) } } } }) } - //TODO(st235): https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.java?source=post_page---------------------------%2F%2F&autodive=0%2F#87 + //TODO(st235): https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt#85 private fun onNavDestinationSelected( - item: ExpandableBottomBarMenuItem, - navController: NavController + item: MenuItem, + navController: NavController ): Boolean { val builder = NavOptions.Builder() .setLaunchSingleTop(true) @@ -64,7 +64,7 @@ object ExpandableBottomBarNavigationUI { val options = builder.build() return try { - navController.navigate(item.itemId, null, options) + navController.navigate(item.id, null, options) true } catch (e: IllegalArgumentException) { false diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/parsers/ExpandableBottomBarParser.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/parsers/ExpandableBottomBarParser.kt index 5006175..dd22bc8 100644 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/parsers/ExpandableBottomBarParser.kt +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/parsers/ExpandableBottomBarParser.kt @@ -4,7 +4,7 @@ import android.content.Context import android.graphics.Color import android.util.AttributeSet import android.util.Xml -import github.com.st235.lib_expandablebottombar.ExpandableBottomBarMenuItem +import github.com.st235.lib_expandablebottombar.MenuItemDescriptor import org.xmlpull.v1.XmlPullParser import github.com.st235.lib_expandablebottombar.R @@ -21,7 +21,7 @@ internal class ExpandableBottomBarParser(private val context: Context) { // We don't use namespaces private val namespace: String? = null - fun inflate(menuId: Int): List { + fun inflate(menuId: Int): List { val parser = context.resources.getLayout(menuId) parser.use { val attrs = Xml.asAttributeSet(parser) @@ -30,8 +30,8 @@ internal class ExpandableBottomBarParser(private val context: Context) { } private fun readBottomBar(parser: XmlPullParser, - attrs: AttributeSet): List { - val items = mutableListOf() + attrs: AttributeSet): List { + val items = mutableListOf() var eventType = parser.eventType var tagName: String @@ -73,7 +73,7 @@ internal class ExpandableBottomBarParser(private val context: Context) { } private fun readBottomBarItem(parser: XmlPullParser, - attrs: AttributeSet): ExpandableBottomBarMenuItem { + attrs: AttributeSet): MenuItemDescriptor { val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ExpandableBottomBarItem) val id = typedArray.getResourceId(R.styleable.ExpandableBottomBarItem_android_id, NO_ID) @@ -95,6 +95,6 @@ internal class ExpandableBottomBarParser(private val context: Context) { typedArray.recycle() parser.require(XmlPullParser.START_TAG, namespace, MENU_ITEM_TAG) - return ExpandableBottomBarMenuItem(id, iconId, text, color, badgeBackgroundColor, badgeTextColor) + return MenuItemDescriptor(id, iconId, text, color, badgeBackgroundColor, badgeTextColor) } } diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/utils/AndroidUtils.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/utils/AndroidUtils.kt index bae1191..760ea26 100644 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/utils/AndroidUtils.kt +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/utils/AndroidUtils.kt @@ -1,6 +1,10 @@ package github.com.st235.lib_expandablebottombar.utils import android.os.Build +import android.transition.AutoTransition +import android.transition.TransitionManager +import android.view.View +import android.view.ViewGroup typealias Scope = () -> Unit @@ -9,3 +13,14 @@ internal inline fun applyForApiLAndHigher(scope: Scope) { scope() } } + +internal fun ViewGroup.delayTransition(duration: Long = -1L) { + val autoTransition = AutoTransition() + autoTransition.duration = duration + TransitionManager.beginDelayedTransition(this, autoTransition) +} + +internal fun View.show(isShown: Boolean = false) { + this.visibility = if (isShown) View.VISIBLE else View.GONE +} + diff --git a/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/ExpandableItemViewControllerTest.kt b/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/ExpandableItemViewControllerTest.kt deleted file mode 100644 index 4b40f20..0000000 --- a/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/ExpandableItemViewControllerTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package github.com.st235.expandablebottombar - -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.verify -import github.com.st235.lib_expandablebottombar.ExpandableBottomBarMenuItem -import github.com.st235.lib_expandablebottombar.ExpandableItemViewController -import github.com.st235.lib_expandablebottombar.components.ExpandableBottomBarMenuItemView -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 - -@RunWith(JUnit4::class) -class ExpandableItemViewControllerTest { - - private val menuItem = ExpandableBottomBarMenuItem(0, 0, "", 0, null, null) - private val itemView = mock() - - private lateinit var expandableItemViewController: ExpandableItemViewController - - @Before - fun setUp() { - expandableItemViewController = ExpandableItemViewController(menuItem, itemView) - } - - @Test - fun `test that select will show title and icon`() { - expandableItemViewController.select() - verify(itemView).select() - } - - @Test - fun `test that deselect item will hide title and remove highlight`() { - expandableItemViewController.unselect() - verify(itemView).deselect() - } -} diff --git a/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/ExpandableBottomBarMenuItemTest.kt b/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemDescriptorTest.kt similarity index 55% rename from lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/ExpandableBottomBarMenuItemTest.kt rename to lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemDescriptorTest.kt index d8828b9..7ea7dc3 100644 --- a/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/ExpandableBottomBarMenuItemTest.kt +++ b/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemDescriptorTest.kt @@ -2,59 +2,59 @@ package github.com.st235.expandablebottombar import android.content.Context import com.nhaarman.mockitokotlin2.mock -import github.com.st235.lib_expandablebottombar.ExpandableBottomBarMenuItem +import github.com.st235.lib_expandablebottombar.MenuItemDescriptor import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(JUnit4::class) -class ExpandableBottomBarMenuItemTest { +class MenuItemDescriptorTest { private val context = mock() - private val builder = ExpandableBottomBarMenuItem.Builder(context) + private val builder = MenuItemDescriptor.Builder(context) @Test(expected = IllegalStateException::class) fun `test that creating empty item will rise an exception`() { - val item = ExpandableBottomBarMenuItem.ItemBuildRequest(builder, context).create() + val item = MenuItemDescriptor.BuildRequest(builder, context).create() } @Test(expected = IllegalStateException::class) fun `test that creating item with id only will rise an exception`() { - val item = ExpandableBottomBarMenuItem.ItemBuildRequest(builder, context).id(0).create() + val item = MenuItemDescriptor.BuildRequest(builder, context).id(0).create() } @Test(expected = IllegalStateException::class) fun `test that creating item without color and icon will rise an exception`() { - val item = ExpandableBottomBarMenuItem.ItemBuildRequest(builder, context).id(0).text("").create() + val item = MenuItemDescriptor.BuildRequest(builder, context).id(0).text("").create() } @Test(expected = IllegalStateException::class) fun `test that creating item without title and icon will rise an exception`() { - val item = ExpandableBottomBarMenuItem.ItemBuildRequest(builder, context).id(0).color(0).create() + val item = MenuItemDescriptor.BuildRequest(builder, context).id(0).color(0).create() } @Test(expected = IllegalStateException::class) fun `test that creating item without color and text will rise an exception`() { - val item = ExpandableBottomBarMenuItem.ItemBuildRequest(builder, context).id(0).icon(0).create() + val item = MenuItemDescriptor.BuildRequest(builder, context).id(0).icon(0).create() } @Test(expected = IllegalStateException::class) fun `test that creating item without color will rise an exception`() { - val item = ExpandableBottomBarMenuItem.ItemBuildRequest(builder, context).id(0).icon(0).text("").create() + val item = MenuItemDescriptor.BuildRequest(builder, context).id(0).icon(0).text("").create() } @Test(expected = IllegalStateException::class) fun `test that creating item without text rise an exception`() { - val item = ExpandableBottomBarMenuItem.ItemBuildRequest(builder, context).id(0).color(0).icon(0).create() + val item = MenuItemDescriptor.BuildRequest(builder, context).id(0).color(0).icon(0).create() } @Test(expected = IllegalStateException::class) fun `test that creating item without icon will rise an exception`() { - val item = ExpandableBottomBarMenuItem.ItemBuildRequest(builder, context).id(0).text("").color(0).create() + val item = MenuItemDescriptor.BuildRequest(builder, context).id(0).text("").color(0).create() } @Test fun `test that right created item will not be rise an exception`() { - val item = ExpandableBottomBarMenuItem.ItemBuildRequest(builder, context).id(1).text("").icon(1).color(1).create() + val item = MenuItemDescriptor.BuildRequest(builder, context).id(1).text("").icon(1).color(1).create() } } diff --git a/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemImplTest.kt b/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemImplTest.kt new file mode 100644 index 0000000..49cbc3a --- /dev/null +++ b/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemImplTest.kt @@ -0,0 +1,37 @@ +package github.com.st235.expandablebottombar + +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import github.com.st235.lib_expandablebottombar.MenuItemDescriptor +import github.com.st235.lib_expandablebottombar.MenuItemImpl +import github.com.st235.lib_expandablebottombar.components.MenuItemView +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class MenuItemImplTest { + + private val menuItem = MenuItemDescriptor(0, 0, "", 0, null, null) + private val itemView = mock() + + private lateinit var menuItemImpl: MenuItemImpl + + @Before + fun setUp() { + menuItemImpl = MenuItemImpl(menuItem, itemView) + } + + @Test + fun `test that select will show title and icon`() { + menuItemImpl.select() + verify(itemView).select() + } + + @Test + fun `test that deselect item will hide title and remove highlight`() { + menuItemImpl.deselect() + verify(itemView).deselect() + } +} From 25eefadd1a79f8fb4a338a66abde26f61814ce73 Mon Sep 17 00:00:00 2001 From: Alexander Dadukin Date: Sun, 28 Mar 2021 22:19:38 +0100 Subject: [PATCH 2/5] changed readme. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3f4028d..d76d93b 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ Then you should add menu items to your navigation component val bottomBar: ExpandableBottomBar = findViewById(R.id.expandable_bottom_bar) bottomBar.addItems( - ExpandableBottomBarMenuItem.Builder(context = this) + MenuItemDescriptor.Builder(context = this) .addItem(R.id.icon_home, R.drawable.ic_bug, R.string.text, Color.GRAY) .addItem(R.id.icon_go, R.drawable.ic_gift, R.string.text2, 0xFFFF77A9) .addItem(R.id.icon_left, R.drawable.ic_one, R.string.text3, 0xFF58A5F0) @@ -126,7 +126,7 @@ Firstly, you should declare menu items in xml android:id="@+id/bookmarks" android:title="@string/text3" android:icon="@drawable/ic_bookmarks" - app:exb_color="#fa2 /> + app:exb_color="#fa2" /> ``` @@ -185,7 +185,7 @@ Then you should reference this xml file at the view attributes /** * Returns notification object */ - val notification = bottomBar.getNotificationFor(i.itemId) // itemId is R.id.action_id + val notification = bottomBar.getMenuItemFor(i.itemId).notification() // itemId is R.id.action_id notification.show() // shows simple dot-notification notification.show("string literal") // shows notification with counter. Counter could not exceed the 4 symbols length From 150cbd48b92c0424a701af148a01ee2b23a9a594 Mon Sep 17 00:00:00 2001 From: Alexander Dadukin Date: Sun, 28 Mar 2021 22:25:35 +0100 Subject: [PATCH 3/5] actualized navigation ui animation. --- .../ExpandableBottomBarNavigationUI.kt | 60 +++++++++++-------- .../res/animator/nav_default_enter_anim.xml | 19 ++++++ .../res/animator/nav_default_exit_anim.xml | 19 ++++++ .../animator/nav_default_pop_enter_anim.xml | 19 ++++++ .../animator/nav_default_pop_exit_anim.xml | 19 ++++++ 5 files changed, 110 insertions(+), 26 deletions(-) create mode 100644 lib-expandablebottombar/src/main/res/animator/nav_default_enter_anim.xml create mode 100644 lib-expandablebottombar/src/main/res/animator/nav_default_exit_anim.xml create mode 100644 lib-expandablebottombar/src/main/res/animator/nav_default_pop_enter_anim.xml create mode 100644 lib-expandablebottombar/src/main/res/animator/nav_default_pop_exit_anim.xml diff --git a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/navigation/ExpandableBottomBarNavigationUI.kt b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/navigation/ExpandableBottomBarNavigationUI.kt index dcaaefa..ca027a8 100644 --- a/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/navigation/ExpandableBottomBarNavigationUI.kt +++ b/lib-expandablebottombar/src/main/java/github/com/st235/lib_expandablebottombar/navigation/ExpandableBottomBarNavigationUI.kt @@ -2,11 +2,8 @@ package github.com.st235.lib_expandablebottombar.navigation import android.os.Bundle import androidx.annotation.IdRes -import androidx.navigation.NavController +import androidx.navigation.* import androidx.navigation.NavController.OnDestinationChangedListener -import androidx.navigation.NavDestination -import androidx.navigation.NavGraph -import androidx.navigation.NavOptions import github.com.st235.lib_expandablebottombar.ExpandableBottomBar import github.com.st235.lib_expandablebottombar.MenuItem import github.com.st235.lib_expandablebottombar.R @@ -16,8 +13,8 @@ object ExpandableBottomBarNavigationUI { @JvmStatic fun setupWithNavController( - expandableBottomBar: ExpandableBottomBar, - navigationController: NavController + expandableBottomBar: ExpandableBottomBar, + navigationController: NavController ) { expandableBottomBar.onItemSelectedListener = { _, menuItem -> onNavDestinationSelected(menuItem, navigationController) @@ -25,23 +22,23 @@ object ExpandableBottomBarNavigationUI { val weakReference = WeakReference(expandableBottomBar) navigationController.addOnDestinationChangedListener( - object : OnDestinationChangedListener { - override fun onDestinationChanged( - controller: NavController, - destination: NavDestination, arguments: Bundle? - ) { - val view = weakReference.get() - if (view == null) { - navigationController.removeOnDestinationChangedListener(this) - return - } - for (menuItem in view.getMenuItems()) { - if (destination.matchDestination(menuItem.id)) { - expandableBottomBar.select(menuItem.id) + object : OnDestinationChangedListener { + override fun onDestinationChanged( + controller: NavController, + destination: NavDestination, arguments: Bundle? + ) { + val view = weakReference.get() + if (view == null) { + navigationController.removeOnDestinationChangedListener(this) + return + } + for (menuItem in view.getMenuItems()) { + if (destination.matchDestination(menuItem.id)) { + expandableBottomBar.select(menuItem.id) + } } } - } - }) + }) } //TODO(st235): https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/navigation/navigation-ui/src/main/java/androidx/navigation/ui/NavigationUI.kt#85 @@ -50,11 +47,22 @@ object ExpandableBottomBarNavigationUI { navController: NavController ): Boolean { val builder = NavOptions.Builder() - .setLaunchSingleTop(true) - .setEnterAnim(R.anim.nav_default_enter_anim) - .setExitAnim(R.anim.nav_default_exit_anim) - .setPopEnterAnim(R.anim.nav_default_pop_enter_anim) - .setPopExitAnim(R.anim.nav_default_pop_exit_anim) + .setLaunchSingleTop(true) + + if (navController.currentDestination!!.parent!!.findNode(item.id) + is ActivityNavigator.Destination) { + builder + .setEnterAnim(R.anim.nav_default_enter_anim) + .setExitAnim(R.anim.nav_default_exit_anim) + .setPopEnterAnim(R.anim.nav_default_pop_enter_anim) + .setPopExitAnim(R.anim.nav_default_pop_exit_anim) + } else { + builder + .setEnterAnim(R.animator.nav_default_enter_anim) + .setExitAnim(R.animator.nav_default_exit_anim) + .setPopEnterAnim(R.animator.nav_default_pop_enter_anim) + .setPopExitAnim(R.animator.nav_default_pop_exit_anim) + } val topDestination = navController.findStartDestination() diff --git a/lib-expandablebottombar/src/main/res/animator/nav_default_enter_anim.xml b/lib-expandablebottombar/src/main/res/animator/nav_default_enter_anim.xml new file mode 100644 index 0000000..a694576 --- /dev/null +++ b/lib-expandablebottombar/src/main/res/animator/nav_default_enter_anim.xml @@ -0,0 +1,19 @@ + + + diff --git a/lib-expandablebottombar/src/main/res/animator/nav_default_exit_anim.xml b/lib-expandablebottombar/src/main/res/animator/nav_default_exit_anim.xml new file mode 100644 index 0000000..924a1c8 --- /dev/null +++ b/lib-expandablebottombar/src/main/res/animator/nav_default_exit_anim.xml @@ -0,0 +1,19 @@ + + + diff --git a/lib-expandablebottombar/src/main/res/animator/nav_default_pop_enter_anim.xml b/lib-expandablebottombar/src/main/res/animator/nav_default_pop_enter_anim.xml new file mode 100644 index 0000000..a694576 --- /dev/null +++ b/lib-expandablebottombar/src/main/res/animator/nav_default_pop_enter_anim.xml @@ -0,0 +1,19 @@ + + + diff --git a/lib-expandablebottombar/src/main/res/animator/nav_default_pop_exit_anim.xml b/lib-expandablebottombar/src/main/res/animator/nav_default_pop_exit_anim.xml new file mode 100644 index 0000000..924a1c8 --- /dev/null +++ b/lib-expandablebottombar/src/main/res/animator/nav_default_pop_exit_anim.xml @@ -0,0 +1,19 @@ + + + From 435c5cc92d09ffb7d15d119818ab141edcc4ded8 Mon Sep 17 00:00:00 2001 From: Alexander Dadukin Date: Sun, 28 Mar 2021 22:26:14 +0100 Subject: [PATCH 4/5] bumped version to 1.3.2 --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2b9f598..9966876 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,8 +4,8 @@ android.useAndroidX=true GROUP=com.github.st235 -VERSION_CODE=39 -VERSION_NAME=1.3.1 +VERSION_CODE=42 +VERSION_NAME=1.3.2 POM_DESCRIPTION=A new way to improve navigation in your app. POM_URL=https://github.com/st235/ExpandableBottomBar From 591cfe176d1e2b22b2e4727b275fdd539a621529 Mon Sep 17 00:00:00 2001 From: Alexander Dadukin Date: Sun, 28 Mar 2021 22:30:16 +0100 Subject: [PATCH 5/5] fixed tests. --- .../github/com/st235/expandablebottombar/MenuItemImplTest.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemImplTest.kt b/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemImplTest.kt index 49cbc3a..96a592c 100644 --- a/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemImplTest.kt +++ b/lib-expandablebottombar/src/test/java/github/com/st235/expandablebottombar/MenuItemImplTest.kt @@ -2,6 +2,7 @@ package github.com.st235.expandablebottombar import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify +import github.com.st235.lib_expandablebottombar.ExpandableBottomBar import github.com.st235.lib_expandablebottombar.MenuItemDescriptor import github.com.st235.lib_expandablebottombar.MenuItemImpl import github.com.st235.lib_expandablebottombar.components.MenuItemView @@ -14,13 +15,14 @@ import org.junit.runners.JUnit4 class MenuItemImplTest { private val menuItem = MenuItemDescriptor(0, 0, "", 0, null, null) + private val rootView = mock() private val itemView = mock() private lateinit var menuItemImpl: MenuItemImpl @Before fun setUp() { - menuItemImpl = MenuItemImpl(menuItem, itemView) + menuItemImpl = MenuItemImpl(menuItem, rootView, itemView) } @Test