Skip to content

Commit

Permalink
Merge pull request #27 from Trendyol/ChangingLifecycleShowcaseBugFix
Browse files Browse the repository at this point in the history
Changing lifecycle showcase bug fix
  • Loading branch information
Muhammedguven authored Sep 6, 2022
2 parents 4c2e6a3 + c5c6f08 commit ae00c8c
Show file tree
Hide file tree
Showing 20 changed files with 398 additions and 74 deletions.
2 changes: 1 addition & 1 deletion library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ android {
minSdkVersion 17
targetSdkVersion 30
versionCode 14
versionName "1.2.1"
versionName "1.3.0"

vectorDrawables.useSupportLibrary = true
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.trendyol.showcase.showcase

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner

class ShowcaseLifecycleOwner(
private val lifecycle: Lifecycle,
private val controller: ShowcaseStateController,
) : LifecycleEventObserver {

init {
lifecycle.addObserver(this)
}

override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {
onDestroy()
return
}
if (event == Lifecycle.Event.ON_STOP) {
onDestroy()
return
}
}

private fun onDestroy() {
lifecycle.removeObserver(this)
controller.onStateChanged(ShowcaseState.DESTROY)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.annotation.*
import androidx.annotation.IntRange
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LifecycleOwner
import com.trendyol.showcase.R
import com.trendyol.showcase.ui.showcase.HighlightType
import com.trendyol.showcase.ui.showcase.ShowcaseActivity
Expand All @@ -25,13 +26,21 @@ class ShowcaseManager private constructor(
@StyleRes val resId: Int?
) {

fun show(activity: FragmentActivity, requestCode: Int? = null) {
if (showcaseModel.isDebugMode) return
fun show(
fragment: FragmentActivity,
requestCode: Int? = null,
lifecycleOwner: LifecycleOwner
) {
val stateController = show(fragment, requestCode)
ShowcaseLifecycleOwner(lifecycleOwner.lifecycle, stateController)
}

if (showcaseModel.attachOnParentLifecycle) {
val observer = DefaultLifecycleObserver(activity, activity)
if (observer.isLifecycleReady().not()) return
}
private fun show(
activity: FragmentActivity,
requestCode: Int? = null,
): ShowcaseStateController {
val stateController = ShowcaseStateController(context = activity)
if (showcaseModel.isDebugMode) return stateController

val intent = Intent(activity, ShowcaseActivity::class.java)
val model = if (resId != null) readFromStyle(activity, resId) else showcaseModel
Expand All @@ -42,17 +51,25 @@ class ShowcaseManager private constructor(
} else {
activity.startActivityForResult(intent, requestCode)
}
return stateController
}

fun show(fragment: Fragment, requestCode: Int? = null) {
if (showcaseModel.isDebugMode) return
fun show(
fragment: Fragment,
requestCode: Int? = null,
lifecycleOwner: LifecycleOwner
) {
val stateController = show(fragment, requestCode)
ShowcaseLifecycleOwner(lifecycleOwner.lifecycle, stateController)
}

private fun show(
fragment: Fragment,
requestCode: Int? = null,
): ShowcaseStateController {
val stateController = ShowcaseStateController(context = fragment.requireActivity())
if (showcaseModel.isDebugMode) return stateController
fragment.activity?.let { activity ->
if (showcaseModel.attachOnParentLifecycle) {
val observer = DefaultLifecycleObserver(fragment.viewLifecycleOwner, activity)
if (observer.isLifecycleReady().not()) return@let
}

val intent = Intent(activity, ShowcaseActivity::class.java)
val model = if (resId != null) readFromStyle(activity, resId) else showcaseModel
intent.putExtra(ShowcaseActivity.BUNDLE_KEY, model)
Expand All @@ -63,6 +80,7 @@ class ShowcaseManager private constructor(
fragment.startActivityForResult(intent, requestCode)
}
}
return stateController
}

private fun readFromStyle(context: Context, resId: Int): ShowcaseModel {
Expand Down Expand Up @@ -136,7 +154,6 @@ class ShowcaseManager private constructor(
Constants.DEFAULT_CANCELLABLE_FROM_OUTSIDE_TOUCH
private var isShowcaseViewClickable: Boolean = Constants.DEFAULT_SHOWCASE_VIEW_CLICKABLE
private var isDebugMode: Boolean = false
private var attachOnParentLifecycle: Boolean = false
private var textPosition: TextPosition = Constants.DEFAULT_TEXT_POSITION
private var imageUrl: String = Constants.DEFAULT_TEXT
private var radiusTopStart: Float = Constants.DEFAULT_HIGHLIGHT_RADIUS
Expand Down Expand Up @@ -313,9 +330,6 @@ class ShowcaseManager private constructor(
fun setSlidableContentList(slidableContentList: List<SlidableContent>) =
apply { this.slidableContentList = slidableContentList }

fun attachOnParentLifecycle(attachOnParentLifecycle: Boolean) =
apply { this.attachOnParentLifecycle = attachOnParentLifecycle }

fun build(): ShowcaseManager {
if (focusViews.isNullOrEmpty()) {
throw Exception("view should not be null!")
Expand Down Expand Up @@ -357,7 +371,6 @@ class ShowcaseManager private constructor(
cancellableFromOutsideTouch = cancellableFromOutsideTouch,
isShowcaseViewClickable = isShowcaseViewClickable,
isDebugMode = isDebugMode,
attachOnParentLifecycle = attachOnParentLifecycle,
textPosition = textPosition,
imageUrl = imageUrl,
customContent = customContent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ data class ShowcaseModel(
val highlightPadding: Float,
val cancellableFromOutsideTouch: Boolean,
val isShowcaseViewClickable: Boolean,
val attachOnParentLifecycle: Boolean,
val isDebugMode: Boolean,
val textPosition: TextPosition,
val imageUrl: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.trendyol.showcase.showcase

sealed class ShowcaseState {
object IDLE : ShowcaseState()
object DESTROY : ShowcaseState()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,20 @@ import android.app.Activity
import android.app.Application
import android.content.Context
import android.os.Bundle
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import com.trendyol.showcase.ui.showcase.ShowcaseActivity
import com.trendyol.showcase.util.ActionType

internal class DefaultLifecycleObserver(
private val lifecycleOwner: LifecycleOwner,
context: Context
) : LifecycleObserver, Application.ActivityLifecycleCallbacks {

private var activity: ShowcaseActivity? = null
class ShowcaseStateController(context: Context) : Application.ActivityLifecycleCallbacks {

init {
lifecycleOwner.lifecycle.addObserver(this)
(context.applicationContext as Application).registerActivityLifecycleCallbacks(this)
}

@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
if (shouldFinishShowcase()) {
finishShowcase()
}
}

fun isLifecycleReady(): Boolean = isDestroyed().not()

private fun isDestroyed(): Boolean =
lifecycleOwner.lifecycle.currentState == Lifecycle.State.DESTROYED

private fun shouldFinishShowcase() = activity != null && isDestroyed()

private fun finishShowcase(): Unit? {
lifecycleOwner.lifecycle.removeObserver(this)
return this.activity?.finishShowcase(ActionType.EXIT, -1)
}
//region activity
private var activity: ShowcaseActivity? = null

override fun onActivityStarted(activity: Activity) {
this.activity = activity as? ShowcaseActivity
this.activity = activity as? ShowcaseActivity ?: return
if (shouldFinishShowcase()) {
finishShowcase()
}
Expand All @@ -63,4 +37,23 @@ internal class DefaultLifecycleObserver(
(activity.applicationContext as Application).unregisterActivityLifecycleCallbacks(this)
this.activity = null
}
}

private fun finishShowcase(): Unit? {
return this.activity?.finishShowcase(ActionType.EXIT, -1)
}
//endregion

//region state
private var prevState: ShowcaseState? = null

fun onStateChanged(state: ShowcaseState) {
if (state == ShowcaseState.DESTROY) {
finishShowcase()
}
prevState = state
}
//endregion

private fun shouldFinishShowcase(): Boolean = prevState == ShowcaseState.DESTROY
}

2 changes: 2 additions & 0 deletions sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ dependencies {

implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.trendyol:medusa:0.10.1'
implementation 'com.google.android.material:material:1.3.0-alpha03'
}
78 changes: 68 additions & 10 deletions sample/src/main/java/com/trendyol/sample/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,81 @@ package com.trendyol.sample
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.trendyol.medusalib.navigator.MultipleStackNavigator
import com.trendyol.medusalib.navigator.Navigator
import com.trendyol.medusalib.navigator.NavigatorConfiguration
import com.trendyol.medusalib.navigator.transaction.NavigatorTransaction

class MainActivity : AppCompatActivity(R.layout.activity_main) {
class MainActivity : AppCompatActivity(R.layout.activity_main), Navigator.NavigatorListener {

private var onTabChangeListener: ((tabIndex: Int) -> Unit)? = null
private lateinit var navigator: Navigator
private val bottomNavigation: BottomNavigationView by lazy {
findViewById(R.id.bottomNavigation)
}
private lateinit var navigationOperationHandler: NavigationOperationHandler

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navigator = createNavigator()
initializeMainActivity(savedInstanceState)
}

if (savedInstanceState == null) {
show(SampleFragment())
private fun initializeMainActivity(savedInstanceState: Bundle?) {
navigator.initialize(savedInstanceState)
navigationOperationHandler = NavigationOperationHandler(navigator)
initializeBottomBarListener()
}

private fun initializeBottomBarListener() {
bottomNavigation.setOnNavigationItemSelectedListener {
navigator.switchTab(it.order)
true
}
bottomNavigation.setOnNavigationItemReselectedListener {
val selectedTabIndex = it.order
if (navigator.hasOnlyRoot(selectedTabIndex).not()) {
navigator.reset(selectedTabIndex)
}
}
}

private fun createNavigator(): Navigator =
MultipleStackNavigator(
fragmentManager = supportFragmentManager,
containerId = R.id.containerMain,
rootFragmentProvider = getRootFragments().map { { it } },
navigatorListener = this,
navigatorConfiguration = NavigatorConfiguration(
initialTabIndex = 0,
alwaysExitFromInitial = true,
defaultNavigatorTransaction = NavigatorTransaction.SHOW_HIDE
)
)

private fun getRootFragments(): ArrayList<Fragment> = arrayListOf(
SampleFragment.newInstance(),
OneFragment.newInstance(),
TwoFragment.newInstance(),
ThreeFragment.newInstance(),
)

fun getNavigator(): Navigator {
return navigator
}

fun setNavigator(navigator: Navigator) {
this.navigator = navigator
}
}

internal fun FragmentActivity.show(fragment: Fragment) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, fragment)
.addToBackStack(fragment.javaClass.simpleName)
.commit()
override fun onTabChanged(tabIndex: Int) {
val bottomNavigationView = bottomNavigation
val selectedItemId = bottomNavigationView.menu.getItem(tabIndex).itemId
onTabChangeListener?.invoke(tabIndex)

if (selectedItemId != bottomNavigationView.selectedItemId) {
bottomNavigationView.selectedItemId = selectedItemId
}
}
}
11 changes: 11 additions & 0 deletions sample/src/main/java/com/trendyol/sample/MedusaLifecycleOwner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.trendyol.sample

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry

class MedusaLifecycleOwner : LifecycleOwner {

private val lifecycleRegistry = LifecycleRegistry(this)

override fun getLifecycle(): LifecycleRegistry = lifecycleRegistry
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.trendyol.sample

import com.trendyol.medusalib.navigator.Navigator

interface NavigationOperation {

fun operate(navigator: Navigator)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.trendyol.sample

import com.trendyol.medusalib.navigator.Navigator

class NavigationOperationHandler constructor(private val navigator: Navigator) {

fun execute(navigationOperation: NavigationOperation) {
navigationOperation.operate(navigator)
}
}
11 changes: 11 additions & 0 deletions sample/src/main/java/com/trendyol/sample/OneFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.trendyol.sample

import androidx.fragment.app.Fragment

class OneFragment : Fragment(R.layout.fragment_one){

companion object{
@JvmStatic
fun newInstance() = OneFragment()
}
}
Loading

0 comments on commit ae00c8c

Please sign in to comment.