From 4ab60d2be8db931f07b476b043d077b07a41d4f1 Mon Sep 17 00:00:00 2001 From: Sebastian Barz Date: Sat, 14 Dec 2019 20:20:54 +0100 Subject: [PATCH] New library version 0.5.2: - Added new action mode to toolbar (similar to android toolbar actionmode) - Fixed wrong main button state when using gesture to open main menu - Toolbar items are now directly accessible to copy them for changes - Renamed the viewmodel to prevent unwanted usage - Refactoring - Updated libraries and kotlin version --- .../main/java/de/si/backdrop/MainActivity.kt | 6 +- .../de/si/backdrop/children/BaseFragment.kt | 23 +--- .../de/si/backdrop/children/TestFragment.kt | 21 +++ .../children/TopCardBackdropFragment.kt | 20 ++- app/src/main/res/menu/test_menu.xml | 16 +++ backdroplibrary/build.gradle | 12 +- .../si/backdroplibrary/BackdropComponent.kt | 54 ++++++-- .../si/backdroplibrary/BackdropViewModel.kt | 8 +- .../main/java/de/si/backdroplibrary/Event.kt | 5 + .../activity/ActivityEventHandling.kt | 78 +++++++---- .../activity/BackdropActivity.kt | 49 +++---- .../children/BackdropFragment.kt | 19 +-- .../children/CardBackdropFragment.kt | 4 +- .../children/MainCardBackdropFragment.kt | 2 +- .../components/BackdropContent.kt | 2 +- .../{ => toolbar}/BackdropToolbar.kt | 125 ++++++++++++------ .../{ => toolbar}/BackdropToolbarItem.kt | 9 +- .../toolbar/BackdropToolbarItemDiff.kt | 6 + .../toolbar/BackdropToolbarMainButtonState.kt | 8 ++ .../src/main/res/layout/layout_toolbar.xml | 7 +- build.gradle | 4 +- 21 files changed, 312 insertions(+), 166 deletions(-) create mode 100644 app/src/main/java/de/si/backdrop/children/TestFragment.kt create mode 100644 app/src/main/res/menu/test_menu.xml rename backdroplibrary/src/main/java/de/si/backdroplibrary/components/{ => toolbar}/BackdropToolbar.kt (63%) rename backdroplibrary/src/main/java/de/si/backdroplibrary/components/{ => toolbar}/BackdropToolbarItem.kt (63%) create mode 100644 backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarItemDiff.kt create mode 100644 backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarMainButtonState.kt diff --git a/app/src/main/java/de/si/backdrop/MainActivity.kt b/app/src/main/java/de/si/backdrop/MainActivity.kt index 749de2f..14592f6 100644 --- a/app/src/main/java/de/si/backdrop/MainActivity.kt +++ b/app/src/main/java/de/si/backdrop/MainActivity.kt @@ -22,7 +22,7 @@ class MainActivity : BackdropActivity() { override fun onBackdropContentVisible(view: View): Boolean { return when (view.id) { - R.id.menu_main_layout -> { + R.id.menu_main_layout -> { configureTestMenuView(view) true } @@ -32,14 +32,14 @@ class MainActivity : BackdropActivity() { } true } - else -> false + else -> false } } private fun configureTestMenuView(menuView: View) { when { menuView.id != MainMenu.resourceId -> return - mainMenu == null -> { + mainMenu == null -> { mainMenu = MainMenu(menuView, this) } } diff --git a/app/src/main/java/de/si/backdrop/children/BaseFragment.kt b/app/src/main/java/de/si/backdrop/children/BaseFragment.kt index 64b0abc..771026e 100644 --- a/app/src/main/java/de/si/backdrop/children/BaseFragment.kt +++ b/app/src/main/java/de/si/backdrop/children/BaseFragment.kt @@ -4,11 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.FragmentTransaction import de.si.backdrop.R import de.si.backdroplibrary.children.MainCardBackdropFragment -import de.si.backdroplibrary.components.BackdropToolbarItem -import de.si.backdroplibrary.components.BackdropToolbarMainButtonState +import de.si.backdroplibrary.components.toolbar.BackdropToolbarItem +import de.si.backdroplibrary.components.toolbar.BackdropToolbarMainButtonState import kotlinx.android.synthetic.main.base_card.* import kotlin.random.Random @@ -16,10 +15,11 @@ class BaseFragment : MainCardBackdropFragment() { override val menuButtonState: BackdropToolbarMainButtonState get() = BackdropToolbarMainButtonState.MENU - override val toolbarItem: BackdropToolbarItem = BackdropToolbarItem(title = "Backdrop", - subtitle = "Demonstration", - primaryAction = R.drawable.ic_add, - moreActionEnabled = true) + override val toolbarItem: BackdropToolbarItem = + BackdropToolbarItem(title = "Backdrop", + subtitle = "Demonstration", + primaryAction = R.drawable.ic_add, + moreActionEnabled = true) override fun onCreateContentView(inflater: LayoutInflater, container: ViewGroup?, @@ -32,15 +32,6 @@ class BaseFragment : MainCardBackdropFragment() { button.setOnClickListener { } - - bottomNavigationView.setOnNavigationItemSelectedListener { - val transaction = childFragmentManager.beginTransaction() - transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - transaction.replace(R.id.testContainer, TestFragment()) - transaction.commit() - - true - } } override fun onPrimaryActionClicked(): Boolean { diff --git a/app/src/main/java/de/si/backdrop/children/TestFragment.kt b/app/src/main/java/de/si/backdrop/children/TestFragment.kt new file mode 100644 index 0000000..1e90cd8 --- /dev/null +++ b/app/src/main/java/de/si/backdrop/children/TestFragment.kt @@ -0,0 +1,21 @@ +package de.si.backdrop.children + +import android.graphics.Color +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import de.si.backdrop.R +import de.si.backdroplibrary.children.BackdropFragment +import kotlin.random.Random + +class TestFragment : BackdropFragment() { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.test_content, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + view.setBackgroundColor(Color.rgb(Random.nextInt(256), Random.nextInt(256), Random.nextInt(256))) + } +} \ No newline at end of file diff --git a/app/src/main/java/de/si/backdrop/children/TopCardBackdropFragment.kt b/app/src/main/java/de/si/backdrop/children/TopCardBackdropFragment.kt index 87cc1cd..4c42f05 100644 --- a/app/src/main/java/de/si/backdrop/children/TopCardBackdropFragment.kt +++ b/app/src/main/java/de/si/backdrop/children/TopCardBackdropFragment.kt @@ -6,12 +6,13 @@ import android.view.View import android.view.ViewGroup import de.si.backdrop.R import de.si.backdroplibrary.children.CardBackdropFragment -import de.si.backdroplibrary.components.BackdropToolbarItem +import de.si.backdroplibrary.components.toolbar.BackdropToolbarItem class TopCardBackdropFragment : CardBackdropFragment() { - override var toolbarItem: BackdropToolbarItem = BackdropToolbarItem(title = "Mid card", - moreActionEnabled = false, - primaryAction = R.drawable.ic_add) + override var toolbarItem: BackdropToolbarItem = + BackdropToolbarItem(title = "Mid card", + moreActionEnabled = true, + primaryAction = R.drawable.ic_add) override fun onCreateContentView(inflater: LayoutInflater, container: ViewGroup?, @@ -33,4 +34,15 @@ class TopCardBackdropFragment : CardBackdropFragment() { changeToolbarItem(toolbarItem) return true } + + override fun onMoreActionClicked(): Boolean { + startToolbarActionMode(BackdropToolbarItem(title = "Card action mode", + primaryAction = R.drawable.ic_change_content)) + return true + } + + override fun onToolbarActionModeFinished(): Boolean { + println("TopCardBackdropFragment.onToolbarActionModeFinished") + return true + } } \ No newline at end of file diff --git a/app/src/main/res/menu/test_menu.xml b/app/src/main/res/menu/test_menu.xml new file mode 100644 index 0000000..0c0f8c9 --- /dev/null +++ b/app/src/main/res/menu/test_menu.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/backdroplibrary/build.gradle b/backdroplibrary/build.gradle index 8aab2e0..f077cd7 100644 --- a/backdroplibrary/build.gradle +++ b/backdroplibrary/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'kotlin-android-extensions' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'digital.wup.android-maven-publish' -group='com.github.Str3l0k' +group = 'com.github.Str3l0k' android { compileSdkVersion 29 @@ -55,10 +55,10 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.1.0' - implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-beta01' + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-rc03' implementation 'androidx.cardview:cardview:1.0.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2' - implementation 'com.google.android.material:material:1.1.0-beta01' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3' + implementation 'com.google.android.material:material:1.2.0-alpha02' testImplementation 'junit:junit:4.12' testImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -68,7 +68,7 @@ dependencies { testImplementation 'org.robolectric:robolectric:4.3.1' testImplementation 'androidx.test.ext:truth:1.2.0' - androidTestImplementation 'androidx.test:core:1.2.1-alpha02' + androidTestImplementation 'androidx.test:core:1.3.0-alpha03' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'androidx.test.ext:junit:1.1.1' @@ -80,7 +80,7 @@ publishing { maven(MavenPublication) { groupId = 'de.si.backdrop' artifactId = 'core' - version = '0.4.0' + version = '0.5.2' from components.android } diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/BackdropComponent.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/BackdropComponent.kt index 96deba8..5ee98ec 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/BackdropComponent.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/BackdropComponent.kt @@ -7,7 +7,7 @@ import de.si.backdroplibrary.activity.BackdropActivity import de.si.backdroplibrary.children.CardBackdropFragment import de.si.backdroplibrary.children.FullscreenBackdropFragment import de.si.backdroplibrary.children.FullscreenRevealBackdropFragment -import de.si.backdroplibrary.components.BackdropToolbarItem +import de.si.backdroplibrary.components.toolbar.BackdropToolbarItem interface BackdropComponent { @@ -15,61 +15,61 @@ interface BackdropComponent { //----------------------------------------- val backdropActivity: BackdropActivity - val viewModel: BackdropViewModel + val backdropViewModel: BackdropViewModel get() = BackdropViewModel.registeredInstance(backdropActivity) //----------------------------------------- // General //----------------------------------------- fun enableGestureNavigation() { - viewModel.gestureNavigationEnabled = true + backdropViewModel.gestureNavigationEnabled = true } fun disableGestureNavigation() { - viewModel.gestureNavigationEnabled = false + backdropViewModel.gestureNavigationEnabled = false } //----------------------------------------- // Card stack //----------------------------------------- fun addCardFragment(cardFragment: CardBackdropFragment) { - viewModel.emit(Event.ADD_TOP_CARD, cardFragment) + backdropViewModel.emit(Event.ADD_TOP_CARD, cardFragment) } fun removeTopCardFragment() { - viewModel.emit(Event.REMOVE_TOP_CARD) + backdropViewModel.emit(Event.REMOVE_TOP_CARD) } //----------------------------------------- // Fullscreen fragments //----------------------------------------- fun showFullscreenFragment(fragment: FullscreenBackdropFragment) { - viewModel.emit(Event.SHOW_FULLSCREEN_FRAGMENT, fragment) + backdropViewModel.emit(Event.SHOW_FULLSCREEN_FRAGMENT, fragment) } fun revealFullscreenFragment(parameters: FullscreenRevealBackdropFragment, revealEpicenter: Point, concealEpicenter: Point) { parameters.revealEpiCenter = revealEpicenter parameters.concealEpiCenter = concealEpicenter - viewModel.emit(Event.REVEAL_FULLSCREEN_FRAGMENT, parameters) + backdropViewModel.emit(Event.REVEAL_FULLSCREEN_FRAGMENT, parameters) } fun hideFullscreenFragment() { - viewModel.emit(Event.HIDE_FULLSCREEN_FRAGMENT) + backdropViewModel.emit(Event.HIDE_FULLSCREEN_FRAGMENT) } //----------------------------------------- // Content //----------------------------------------- fun prefetchBackdropContent(@LayoutRes layoutResId: Int) { - viewModel.emit(Event.PREFETCH_BACKDROP_CONTENT_VIEW, layoutResId) + backdropViewModel.emit(Event.PREFETCH_BACKDROP_CONTENT_VIEW, layoutResId) } fun showBackdropContent(@LayoutRes layoutResId: Int) { - viewModel.emit(Event.SHOW_BACKDROP_CONTENT, layoutResId) + backdropViewModel.emit(Event.SHOW_BACKDROP_CONTENT, layoutResId) } fun hideBackdropContent() { - viewModel.emit(Event.HIDE_BACKDROP_CONTENT) + backdropViewModel.emit(Event.HIDE_BACKDROP_CONTENT) } fun onBackdropContentVisible(view: View): Boolean { @@ -83,8 +83,24 @@ interface BackdropComponent { //----------------------------------------- // Toolbar //----------------------------------------- + fun currentToolbarItem(): BackdropToolbarItem { + return backdropActivity.backdropToolbar.currentToolbarItem + } + + fun actionModeToolbarItem(): BackdropToolbarItem? { + return backdropActivity.backdropToolbar.actionModeToolbarItem + } + fun changeToolbarItem(toolbarItem: BackdropToolbarItem) { - viewModel.emit(Event.CHANGE_NAVIGATION_ITEM, toolbarItem) + backdropViewModel.emit(Event.CHANGE_NAVIGATION_ITEM, toolbarItem) + } + + fun startToolbarActionMode(toolbarItem: BackdropToolbarItem) { + backdropViewModel.emit(Event.START_ACTION_MODE, toolbarItem) + } + + fun finishToolbarActionMode() { + backdropViewModel.emit(Event.FINISH_ACTION_MODE) } fun onPrimaryActionClicked(): Boolean { @@ -94,4 +110,16 @@ interface BackdropComponent { fun onMoreActionClicked(): Boolean { return false } + + fun onPrimaryActionInActionModeClicked(): Boolean { + return false + } + + fun onMoreActionInActionModeClicked(): Boolean { + return false + } + + fun onToolbarActionModeFinished(): Boolean { + return false + } } \ No newline at end of file diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/BackdropViewModel.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/BackdropViewModel.kt index 8728fe0..2c4b891 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/BackdropViewModel.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/BackdropViewModel.kt @@ -3,7 +3,7 @@ package de.si.backdroplibrary import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProviders +import androidx.lifecycle.ViewModelProvider internal typealias BackdropEventCallback = ((Event, Any?) -> Boolean) @@ -29,7 +29,9 @@ class BackdropViewModel : ViewModel() { } internal fun emit(event: Event, payload: Any? = null) { - val callbackResult = callbackReceivers.reversed().firstOrNull { it.invoke(event, payload) } + val callbackResult = callbackReceivers.reversed().firstOrNull { + it.invoke(event, payload) + } if (callbackResult == null) { Log.w("Backdrop Event System", "Nobody consumed event = [$event], payload = [$payload]") @@ -40,7 +42,7 @@ class BackdropViewModel : ViewModel() { //----------------------------------------- companion object { internal fun registeredInstance(activity: AppCompatActivity): BackdropViewModel { - return ViewModelProviders.of(activity)[BackdropViewModel::class.java] + return ViewModelProvider(activity)[BackdropViewModel::class.java] } } } \ No newline at end of file diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/Event.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/Event.kt index 151fd5a..6e0fc01 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/Event.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/Event.kt @@ -12,6 +12,11 @@ internal enum class Event { PRIMARY_ACTION_TRIGGERED, MORE_ACTION_TRIGGERED, CHANGE_NAVIGATION_ITEM, + START_ACTION_MODE, + FINISH_ACTION_MODE, + PRIMARY_ACTION_ACTIONMODE_TRIGGERED, + MORE_ACTION_ACTIONMODE_TRIGGERED, + ACTION_MODE_FINISHED, // card stack ADD_TOP_CARD, diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/activity/ActivityEventHandling.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/activity/ActivityEventHandling.kt index 4df7196..4eed0fb 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/activity/ActivityEventHandling.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/activity/ActivityEventHandling.kt @@ -5,35 +5,43 @@ import de.si.backdroplibrary.Event import de.si.backdroplibrary.children.CardBackdropFragment import de.si.backdroplibrary.children.FullscreenBackdropFragment import de.si.backdroplibrary.children.FullscreenRevealBackdropFragment -import de.si.backdroplibrary.components.BackdropToolbarItem -import de.si.backdroplibrary.components.BackdropToolbarMainButtonState +import de.si.backdroplibrary.components.toolbar.BackdropToolbarItem +import de.si.backdroplibrary.components.toolbar.BackdropToolbarMainButtonState internal fun BackdropActivity.onEvent(event: Event, payload: Any?): Boolean { return when (event) { // content events - Event.PREFETCH_BACKDROP_CONTENT_VIEW -> handlePrefetchBackdropContentEvent(payload as Int) - Event.SHOW_BACKDROP_CONTENT -> handleShowBackdropContentEvent(payload as Int) - Event.HIDE_BACKDROP_CONTENT -> handleHideBackdropContentEvent() - Event.BACKDROP_CONTENT_VISIBLE -> onBackdropContentVisible(payload as View) - Event.BACKDROP_CONTENT_INVISIBLE -> onBackdropContentInvisible() + Event.PREFETCH_BACKDROP_CONTENT_VIEW -> handlePrefetchBackdropContentEvent(payload as Int) + Event.SHOW_BACKDROP_CONTENT -> handleShowBackdropContentEvent(payload as Int) + Event.HIDE_BACKDROP_CONTENT -> handleHideBackdropContentEvent() + Event.BACKDROP_CONTENT_VISIBLE -> onBackdropContentVisible(payload as View) + Event.BACKDROP_CONTENT_INVISIBLE -> onBackdropContentInvisible() // toolbar events - Event.CHANGE_NAVIGATION_ITEM -> handleToolbarItemChangedEvent(payload as BackdropToolbarItem) - Event.PRIMARY_ACTION_TRIGGERED -> onPrimaryActionClicked() - Event.MORE_ACTION_TRIGGERED -> onMoreActionClicked() + Event.CHANGE_NAVIGATION_ITEM -> handleToolbarItemChangedEvent(payload as BackdropToolbarItem) + Event.PRIMARY_ACTION_TRIGGERED -> onPrimaryActionClicked() + Event.MORE_ACTION_TRIGGERED -> onMoreActionClicked() + Event.START_ACTION_MODE -> handleToolbarActionModeStart(payload as BackdropToolbarItem) + Event.FINISH_ACTION_MODE -> handleToolbarActionModeFinish() + Event.PRIMARY_ACTION_ACTIONMODE_TRIGGERED -> onPrimaryActionInActionModeClicked() + Event.MORE_ACTION_ACTIONMODE_TRIGGERED -> onMoreActionInActionModeClicked() + Event.ACTION_MODE_FINISHED -> onToolbarActionModeFinished() // card stack events - Event.ADD_TOP_CARD -> handleAddTopCardEvent(payload as CardBackdropFragment) - Event.REMOVE_TOP_CARD -> handleRemoveTopCardEvent() + Event.ADD_TOP_CARD -> handleAddTopCardEvent(payload as CardBackdropFragment) + Event.REMOVE_TOP_CARD -> handleRemoveTopCardEvent() // fullscreen - Event.SHOW_FULLSCREEN_FRAGMENT -> handleShowFullscreenFragmentEvent(payload as FullscreenBackdropFragment) - Event.REVEAL_FULLSCREEN_FRAGMENT -> handleRevealFullscreenFragmentEvent(payload as FullscreenRevealBackdropFragment) - Event.HIDE_FULLSCREEN_FRAGMENT -> handleHideFullscreenFragmentEvent() + Event.SHOW_FULLSCREEN_FRAGMENT -> handleShowFullscreenFragmentEvent(payload as FullscreenBackdropFragment) + Event.REVEAL_FULLSCREEN_FRAGMENT -> handleRevealFullscreenFragmentEvent(payload as FullscreenRevealBackdropFragment) + Event.HIDE_FULLSCREEN_FRAGMENT -> handleHideFullscreenFragmentEvent() } } -/* region backdrop content event handling */ +//----------------------------------------- +// backdrop content event handling +//----------------------------------------- + private fun BackdropActivity.handlePrefetchBackdropContentEvent(layoutResId: Int): Boolean { backdropContent.preCacheContentView(layoutResId) return true @@ -55,12 +63,14 @@ private fun BackdropActivity.handleHideBackdropContentEvent(): Boolean { backdropCardStack.enable() backdropToolbar.enableActions() backdropToolbar.showMenuButton() - viewModel.emit(Event.BACKDROP_CONTENT_INVISIBLE) + backdropViewModel.emit(Event.BACKDROP_CONTENT_INVISIBLE) return true } -/* endregion */ -/* region toolbar event handling */ +//----------------------------------------- +// toolbar event handling +//----------------------------------------- + private fun BackdropActivity.handleToolbarItemChangedEvent(toolbarItem: BackdropToolbarItem): Boolean { val mainButtonState: BackdropToolbarMainButtonState = if (backdropCardStack.hasMoreThanOneEntry) { BackdropToolbarMainButtonState.BACK @@ -71,9 +81,27 @@ private fun BackdropActivity.handleToolbarItemChangedEvent(toolbarItem: Backdrop backdropToolbar.configure(toolbarItem, mainButtonState) return true } -/* endregion */ -/* region card stack event handling */ +private fun BackdropActivity.handleToolbarActionModeStart(toolbarItem: BackdropToolbarItem): Boolean { + backdropToolbar.startActionMode(toolbarItem) + return true +} + +private fun BackdropActivity.handleToolbarActionModeFinish(): Boolean { + val mainButtonState: BackdropToolbarMainButtonState = if (backdropCardStack.hasMoreThanOneEntry) { + BackdropToolbarMainButtonState.BACK + } else { + baseCardFragment.menuButtonState + } + + backdropToolbar.finishActionMode(mainButtonState) + return true +} + +//----------------------------------------- +// card stack event handling +//----------------------------------------- + private fun BackdropActivity.handleAddTopCardEvent(cardFragment: CardBackdropFragment): Boolean { val toolbarItem = cardFragment.toolbarItem backdropCardStack.push(cardFragment) @@ -93,9 +121,10 @@ private fun BackdropActivity.handleRemoveTopCardEvent(): Boolean { backdropToolbar.configure(backdropCardStack.topFragment.toolbarItem, mainButtonState) return true } -/* endregion card stack event handling functions */ -/* region fullscreen fragment event handling */ +//----------------------------------------- +// fullscreen fragment event handling +//----------------------------------------- private fun BackdropActivity.handleShowFullscreenFragmentEvent(fragment: FullscreenBackdropFragment): Boolean { fullscreenDialogs.showFullscreenFragment(fragment) return true @@ -109,5 +138,4 @@ private fun BackdropActivity.handleHideFullscreenFragmentEvent(): Boolean { private fun BackdropActivity.handleRevealFullscreenFragmentEvent(fragment: FullscreenRevealBackdropFragment): Boolean { fullscreenDialogs.revealFullscreen(fragment) return true -} -/* endregion */ \ No newline at end of file +} \ No newline at end of file diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/activity/BackdropActivity.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/activity/BackdropActivity.kt index ad0f962..6be2ec4 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/activity/BackdropActivity.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/activity/BackdropActivity.kt @@ -16,15 +16,17 @@ import de.si.backdroplibrary.R import de.si.backdroplibrary.children.MainCardBackdropFragment import de.si.backdroplibrary.components.BackdropCardStack import de.si.backdroplibrary.components.BackdropContent -import de.si.backdroplibrary.components.BackdropToolbar import de.si.backdroplibrary.components.FullscreenDialogs +import de.si.backdroplibrary.components.toolbar.BackdropToolbar import de.si.backdroplibrary.gestures.BackdropGestureNavigationListener import kotlinx.android.synthetic.main.layout_main.* abstract class BackdropActivity : AppCompatActivity(), BackdropComponent { + //----------------------------------------- // viewModel - override val viewModel by lazy { + //----------------------------------------- + override val backdropViewModel by lazy { BackdropViewModel.registeredInstance(this) } @@ -60,7 +62,7 @@ abstract class BackdropActivity : AppCompatActivity(), BackdropComponent { } //----------------------------------------- - // region lifecycle + // lifecycle //----------------------------------------- override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -79,23 +81,16 @@ abstract class BackdropActivity : AppCompatActivity(), BackdropComponent { override fun onPause() { super.onPause() - viewModel.unregisterEventCallbacks(this::onEvent) + backdropViewModel.unregisterEventCallbacks(this::onEvent) } override fun onBackPressed() { when { - fullscreenDialogs.isVisible -> { - fullscreenDialogs.hideFullscreenFragment() - } - backdropOpen -> { - hideBackdropContent() - } - backdropCardStack.hasMoreThanOneEntry -> { - removeTopCardFragment() - } - else -> { - super.onBackPressed() - } + fullscreenDialogs.isVisible -> fullscreenDialogs.hideFullscreenFragment() + backdropOpen -> hideBackdropContent() + backdropCardStack.hasMoreThanOneEntry -> removeTopCardFragment() + backdropToolbar.isInActionMode -> finishToolbarActionMode() + else -> super.onBackPressed() } } @@ -104,7 +99,7 @@ abstract class BackdropActivity : AppCompatActivity(), BackdropComponent { } private fun initializeViewModel() { - viewModel.registerEventCallback(this::onEvent) + backdropViewModel.registerEventCallback(this::onEvent) } private fun initializeComponents() { @@ -114,6 +109,9 @@ abstract class BackdropActivity : AppCompatActivity(), BackdropComponent { backdropToolbar.closeBackdropClickCallback = { hideBackdropContent() } + backdropToolbar.finishActionModeCallback = { + finishToolbarActionMode() + } fullscreenDialogs = FullscreenDialogs(this) } @@ -130,7 +128,7 @@ abstract class BackdropActivity : AppCompatActivity(), BackdropComponent { gestureDetector = GestureDetector(applicationContext, gestureNavigationListener) gestureNavigationListener.onFlingDownCallback = { - if (viewModel.gestureNavigationEnabled) { + if (backdropViewModel.gestureNavigationEnabled) { if (backdropCardStack.hasMoreThanOneEntry) { removeTopCardFragment() } else if (backdropToolbar.menuButtonVisible && backdropOpen.not() && menuLayoutRes > 0) { @@ -139,12 +137,9 @@ abstract class BackdropActivity : AppCompatActivity(), BackdropComponent { } } } - //----------------------------------------- - // endregion lifecycle - //----------------------------------------- //----------------------------------------- - // region animation functions + // animation functions //----------------------------------------- internal fun animateBackdropOpening(translationY: Float) { backdropOpenCloseAnimator.setFloatValues(translationY) @@ -155,12 +150,9 @@ abstract class BackdropActivity : AppCompatActivity(), BackdropComponent { backdropOpenCloseAnimator.setFloatValues(BACKDROP_CLOSED_TRANSLATION_Y) backdropOpenCloseAnimator.start() } - //----------------------------------------- - // endregion animation functions - //----------------------------------------- //----------------------------------------- - // region main menu + // main menu //----------------------------------------- @Suppress("unused") fun setMenuButtonClickCallback(clickCallback: () -> Unit) { @@ -174,13 +166,10 @@ abstract class BackdropActivity : AppCompatActivity(), BackdropComponent { fun setMenuLayout(@LayoutRes layoutResId: Int) { menuLayoutRes = layoutResId - viewModel.emit(Event.PREFETCH_BACKDROP_CONTENT_VIEW, layoutResId) + backdropViewModel.emit(Event.PREFETCH_BACKDROP_CONTENT_VIEW, layoutResId) backdropToolbar.showMenuButton() backdropToolbar.openMenuClickCallback = { showBackdropContent(layoutResId) } } - //----------------------------------------- - // endregion - //----------------------------------------- } \ No newline at end of file diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/children/BackdropFragment.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/children/BackdropFragment.kt index c788b34..47cdf58 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/children/BackdropFragment.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/children/BackdropFragment.kt @@ -12,27 +12,30 @@ abstract class BackdropFragment : Fragment(), BackdropComponent { override val backdropActivity: BackdropActivity get() = requireActivity() as BackdropActivity - override val viewModel: BackdropViewModel by lazy { + override val backdropViewModel: BackdropViewModel by lazy { BackdropViewModel.registeredInstance(backdropActivity) } override fun onStart() { super.onStart() - viewModel.registerEventCallback(this::onEvent) + backdropViewModel.registerEventCallback(this::onEvent) } override fun onPause() { super.onPause() - viewModel.unregisterEventCallbacks(this::onEvent) + backdropViewModel.unregisterEventCallbacks(this::onEvent) } private fun onEvent(event: Event, payload: Any?): Boolean { return when (event) { - Event.BACKDROP_CONTENT_VISIBLE -> onBackdropContentVisible(payload as View) - Event.BACKDROP_CONTENT_INVISIBLE -> onBackdropContentInvisible() - Event.PRIMARY_ACTION_TRIGGERED -> onPrimaryActionClicked() - Event.MORE_ACTION_TRIGGERED -> onMoreActionClicked() - else -> false + Event.BACKDROP_CONTENT_VISIBLE -> onBackdropContentVisible(payload as View) + Event.BACKDROP_CONTENT_INVISIBLE -> onBackdropContentInvisible() + Event.PRIMARY_ACTION_TRIGGERED -> onPrimaryActionClicked() + Event.MORE_ACTION_TRIGGERED -> onMoreActionClicked() + Event.PRIMARY_ACTION_ACTIONMODE_TRIGGERED -> onPrimaryActionInActionModeClicked() + Event.MORE_ACTION_ACTIONMODE_TRIGGERED -> onMoreActionInActionModeClicked() + Event.ACTION_MODE_FINISHED -> onToolbarActionModeFinished() + else -> false } } } \ No newline at end of file diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/children/CardBackdropFragment.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/children/CardBackdropFragment.kt index e4d019b..9ea5b8f 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/children/CardBackdropFragment.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/children/CardBackdropFragment.kt @@ -7,7 +7,7 @@ import androidx.core.view.get import androidx.core.view.isVisible import de.si.backdroplibrary.Backdrop import de.si.backdroplibrary.R -import de.si.backdroplibrary.components.BackdropToolbarItem +import de.si.backdroplibrary.components.toolbar.BackdropToolbarItem import de.si.backdroplibrary.gestures.BackdropGestureNavigationListener import de.si.kotlinx.fadeInAnimator import de.si.kotlinx.fadeOut @@ -62,7 +62,7 @@ abstract class CardBackdropFragment : BackdropFragment() { private fun initializeGestureNavigation() { gestureNavigationListener.onFlingUpCallback = { - if (viewModel.gestureNavigationEnabled) { + if (backdropViewModel.gestureNavigationEnabled) { hideBackdropContent() } } diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/children/MainCardBackdropFragment.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/children/MainCardBackdropFragment.kt index dcd2d42..d8c4e6d 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/children/MainCardBackdropFragment.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/children/MainCardBackdropFragment.kt @@ -1,6 +1,6 @@ package de.si.backdroplibrary.children -import de.si.backdroplibrary.components.BackdropToolbarMainButtonState +import de.si.backdroplibrary.components.toolbar.BackdropToolbarMainButtonState abstract class MainCardBackdropFragment : CardBackdropFragment() { abstract val menuButtonState: BackdropToolbarMainButtonState diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropContent.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropContent.kt index a7acddb..2fec57f 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropContent.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropContent.kt @@ -80,7 +80,7 @@ internal class BackdropContent(override val backdropActivity: BackdropActivity) newContentView?.doOnNextLayout { newContentViewAfterLayout -> nextLayoutCallback(newContentViewAfterLayout) - viewModel.emit(Event.BACKDROP_CONTENT_VISIBLE, newContentViewAfterLayout) + backdropViewModel.emit(Event.BACKDROP_CONTENT_VISIBLE, newContentViewAfterLayout) } return newContentView diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropToolbar.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbar.kt similarity index 63% rename from backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropToolbar.kt rename to backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbar.kt index 0435550..d1a7d33 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropToolbar.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbar.kt @@ -1,4 +1,4 @@ -package de.si.backdroplibrary.components +package de.si.backdroplibrary.components.toolbar import android.animation.AnimatorSet import android.animation.LayoutTransition @@ -33,9 +33,6 @@ internal class BackdropToolbar(override val backdropActivity: BackdropActivity) private val titleLayout: LinearLayout = backdropActivity.layout_backdrop_toolbar_titles private val textTitle: TextView = backdropActivity.text_backdrop_toolbar_title private val textSubTitle: TextView = backdropActivity.text_backdrop_toolbar_subtitle - //----------------------------------------- - // endregion - //----------------------------------------- //----------------------------------------- // @@ -54,38 +51,55 @@ internal class BackdropToolbar(override val backdropActivity: BackdropActivity) textSubTitle.text = value } + var currentToolbarItem: BackdropToolbarItem = BackdropToolbarItem(title = "Toolbar") + private set + var actionModeToolbarItem: BackdropToolbarItem? = null + private set + //----------------------------------------- // //----------------------------------------- init { buttonMoreAction.setOnClickListener { - viewModel.emit(Event.MORE_ACTION_TRIGGERED) + if (actionModeToolbarItem != null) { + backdropViewModel.emit(Event.MORE_ACTION_ACTIONMODE_TRIGGERED) + } else { + backdropViewModel.emit(Event.MORE_ACTION_TRIGGERED) + } } buttonPrimaryAction.setOnClickListener { - viewModel.emit(Event.PRIMARY_ACTION_TRIGGERED) + if (actionModeToolbarItem != null) { + backdropViewModel.emit(Event.PRIMARY_ACTION_ACTIONMODE_TRIGGERED) + } else { + backdropViewModel.emit(Event.PRIMARY_ACTION_TRIGGERED) + } } buttonMenu.setOnClickListener { when (buttonMenu.tag as? BackdropToolbarMainButtonState) { - BackdropToolbarMainButtonState.MENU -> { + BackdropToolbarMainButtonState.MENU -> { openMenuClickCallback?.invoke() buttonMenu.tag = BackdropToolbarMainButtonState.CLOSE buttonMenu.fade { buttonMenu.setImageResource(R.drawable.ic_clear) } } - BackdropToolbarMainButtonState.BACK -> { + BackdropToolbarMainButtonState.BACK -> { backdropActivity.onBackPressed() } BackdropToolbarMainButtonState.CLOSE -> { - closeBackdropClickCallback?.invoke() - buttonMenu.tag = BackdropToolbarMainButtonState.MENU - buttonMenu.fade { - buttonMenu.setImageResource(R.drawable.ic_menu) + if (actionModeToolbarItem != null) { + finishActionModeCallback?.invoke() ?: finishActionMode(BackdropToolbarMainButtonState.MENU) + } else { + closeBackdropClickCallback?.invoke() + buttonMenu.tag = BackdropToolbarMainButtonState.MENU + buttonMenu.fade { + buttonMenu.setImageResource(R.drawable.ic_menu) + } } } - else -> { + else -> { // Nothing to do here } } @@ -94,26 +108,40 @@ internal class BackdropToolbar(override val backdropActivity: BackdropActivity) buttonMenu.setOnLongClickListener { when (buttonMenu.tag as? BackdropToolbarMainButtonState) { BackdropToolbarMainButtonState.MENU -> openMenuLongClickCallback?.invoke() ?: false - else -> false + else -> false } } } - /* callbacks */ + //----------------------------------------- + // Callbacks + //----------------------------------------- + internal var openMenuClickCallback: (() -> Unit)? = null internal var closeBackdropClickCallback: (() -> Unit)? = null internal var openMenuLongClickCallback: (() -> Boolean)? = null + internal var finishActionModeCallback: (() -> Unit)? = null + + //----------------------------------------- + // API + //----------------------------------------- - /* API */ internal val menuButtonVisible: Boolean get() = buttonMenu.tag == BackdropToolbarMainButtonState.MENU - internal fun configure(item: BackdropToolbarItem, mainButtonState: BackdropToolbarMainButtonState) { + internal val isInActionMode: Boolean + get() = actionModeToolbarItem != null - val itemDiff: BackdropToolbarItemDiff = item.calculateDiff(BackdropToolbarItem(title = title, - subtitle = subTitle, - primaryAction = buttonPrimaryAction.tag as Int?, - moreActionEnabled = buttonMoreAction.isVisible)) + internal fun configure(toolbarItem: BackdropToolbarItem, mainButtonState: BackdropToolbarMainButtonState) { + calculateAndStartToolbarAnimations(toolbarItem, mainButtonState) + currentToolbarItem = toolbarItem + } + + private fun calculateAndStartToolbarAnimations(toolbarItem: BackdropToolbarItem, mainButtonState: BackdropToolbarMainButtonState) { + val itemDiff: BackdropToolbarItemDiff = toolbarItem.calculateDiff(BackdropToolbarItem(title = title, + subtitle = subTitle, + primaryAction = buttonPrimaryAction.tag as Int?, + moreActionEnabled = buttonMoreAction.isVisible)) val toolbarAnimations: MutableList = mutableListOf() @@ -121,7 +149,7 @@ internal class BackdropToolbar(override val backdropActivity: BackdropActivity) toolbarAnimations.add(ObjectAnimator.ofFloat(titleLayout, View.ALPHA, 1f, 0f)) } else if (itemDiff.subtitleChanged) { titleLayout.layoutTransition = LayoutTransition() - subTitle = item.subtitle + subTitle = toolbarItem.subtitle titleLayout.layoutTransition = null } else if (itemDiff.titleChanged) { toolbarAnimations.add(ObjectAnimator.ofFloat(textTitle, View.ALPHA, 1f, 0f)) @@ -146,19 +174,19 @@ internal class BackdropToolbar(override val backdropActivity: BackdropActivity) val animatorSet = AnimatorSet() animatorSet.playTogether(*toolbarAnimations.toTypedArray()) animatorSet.addListener(onEnd = { - title = item.title - subTitle = item.subtitle - buttonMoreAction.isVisible = item.moreActionEnabled - buttonPrimaryAction.tag = item.primaryAction - buttonPrimaryAction.isVisible = item.primaryAction != null - item.primaryAction?.let { buttonPrimaryAction.setImageResource(it) } + title = toolbarItem.title + subTitle = toolbarItem.subtitle + buttonMoreAction.isVisible = toolbarItem.moreActionEnabled + buttonPrimaryAction.tag = toolbarItem.primaryAction + buttonPrimaryAction.isVisible = toolbarItem.primaryAction != null + toolbarItem.primaryAction?.let { buttonPrimaryAction.setImageResource(it) } when (mainButtonState) { - BackdropToolbarMainButtonState.MENU -> { + BackdropToolbarMainButtonState.MENU -> { buttonMenu.isVisible = true buttonMenu.setImageResource(R.drawable.ic_menu) } - BackdropToolbarMainButtonState.BACK -> { + BackdropToolbarMainButtonState.BACK -> { buttonMenu.isVisible = true buttonMenu.setImageResource(R.drawable.ic_back) } @@ -166,7 +194,7 @@ internal class BackdropToolbar(override val backdropActivity: BackdropActivity) buttonMenu.isVisible = true buttonMenu.setImageResource(R.drawable.ic_clear) } - BackdropToolbarMainButtonState.NONE -> { + BackdropToolbarMainButtonState.NONE -> { buttonMenu.isVisible = false } } @@ -204,24 +232,37 @@ internal class BackdropToolbar(override val backdropActivity: BackdropActivity) } internal fun showMenuButton() { - buttonMenu.tag = BackdropToolbarMainButtonState.MENU - buttonMenu.isVisible = true - buttonMenu.fadeIn() + if (buttonMenu.tag == BackdropToolbarMainButtonState.MENU) { + return + } + + buttonMenu.fade { + buttonMenu.tag = BackdropToolbarMainButtonState.MENU + buttonMenu.isVisible = true + buttonMenu.setImageResource(R.drawable.ic_menu) + } } internal fun showBackdropCloseButton() { - if (buttonMenu.isVisible.not()) { + if (buttonMenu.tag == BackdropToolbarMainButtonState.CLOSE) { + return + } + + buttonMenu.fade { buttonMenu.tag = BackdropToolbarMainButtonState.CLOSE buttonMenu.isVisible = true buttonMenu.setImageResource(R.drawable.ic_clear) - buttonMenu.fadeIn() } } -} -enum class BackdropToolbarMainButtonState { - MENU, - BACK, - CLOSE, - NONE; + internal fun startActionMode(toolbarItem: BackdropToolbarItem) { + calculateAndStartToolbarAnimations(toolbarItem, BackdropToolbarMainButtonState.CLOSE) + actionModeToolbarItem = toolbarItem + } + + internal fun finishActionMode(mainButtonState: BackdropToolbarMainButtonState) { + calculateAndStartToolbarAnimations(currentToolbarItem, mainButtonState) + actionModeToolbarItem = null + backdropViewModel.emit(Event.ACTION_MODE_FINISHED) + } } \ No newline at end of file diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropToolbarItem.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarItem.kt similarity index 63% rename from backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropToolbarItem.kt rename to backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarItem.kt index 20791da..4dfbaff 100644 --- a/backdroplibrary/src/main/java/de/si/backdroplibrary/components/BackdropToolbarItem.kt +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarItem.kt @@ -1,19 +1,14 @@ -package de.si.backdroplibrary.components +package de.si.backdroplibrary.components.toolbar data class BackdropToolbarItem(val title: String, val subtitle: String? = null, val primaryAction: Int? = null, val moreActionEnabled: Boolean = false) { - fun calculateDiff(other: BackdropToolbarItem): BackdropToolbarItemDiff { + internal fun calculateDiff(other: BackdropToolbarItem): BackdropToolbarItemDiff { return BackdropToolbarItemDiff(titleChanged = this.title != other.title, subtitleChanged = this.subtitle != (other.subtitle ?: ""), primaryActionChanged = this.primaryAction != other.primaryAction, moreActionChanged = this.moreActionEnabled != other.moreActionEnabled) } } - -data class BackdropToolbarItemDiff(val titleChanged: Boolean, - val subtitleChanged: Boolean, - val primaryActionChanged: Boolean, - val moreActionChanged: Boolean) \ No newline at end of file diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarItemDiff.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarItemDiff.kt new file mode 100644 index 0000000..3a774e2 --- /dev/null +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarItemDiff.kt @@ -0,0 +1,6 @@ +package de.si.backdroplibrary.components.toolbar + +internal data class BackdropToolbarItemDiff(val titleChanged: Boolean, + val subtitleChanged: Boolean, + val primaryActionChanged: Boolean, + val moreActionChanged: Boolean) \ No newline at end of file diff --git a/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarMainButtonState.kt b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarMainButtonState.kt new file mode 100644 index 0000000..6eccfa8 --- /dev/null +++ b/backdroplibrary/src/main/java/de/si/backdroplibrary/components/toolbar/BackdropToolbarMainButtonState.kt @@ -0,0 +1,8 @@ +package de.si.backdroplibrary.components.toolbar + +enum class BackdropToolbarMainButtonState { + MENU, + BACK, + CLOSE, + NONE; +} \ No newline at end of file diff --git a/backdroplibrary/src/main/res/layout/layout_toolbar.xml b/backdroplibrary/src/main/res/layout/layout_toolbar.xml index b422b13..5328555 100644 --- a/backdroplibrary/src/main/res/layout/layout_toolbar.xml +++ b/backdroplibrary/src/main/res/layout/layout_toolbar.xml @@ -43,22 +43,23 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> - -