-
Notifications
You must be signed in to change notification settings - Fork 70
/
LazySetNavigator.kt
143 lines (126 loc) · 4.6 KB
/
LazySetNavigator.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package com.wealthfront.magellan.navigation
import android.content.Context
import android.view.View
import androidx.annotation.VisibleForTesting
import com.wealthfront.magellan.Direction
import com.wealthfront.magellan.ScreenContainer
import com.wealthfront.magellan.init.shouldRunAnimations
import com.wealthfront.magellan.lifecycle.LifecycleAwareComponent
import com.wealthfront.magellan.lifecycle.LifecycleLimit
import com.wealthfront.magellan.lifecycle.LifecycleState
import com.wealthfront.magellan.transitions.DefaultTransition
import com.wealthfront.magellan.transitions.MagellanTransition
import com.wealthfront.magellan.transitions.NoAnimationTransition
import com.wealthfront.magellan.view.whenMeasured
public open class LazySetNavigator(
protected val container: () -> ScreenContainer
) : LifecycleAwareComponent() {
private var currentNavigableSetup: ((NavigableCompat) -> Unit)? = null
private val navigationPropagator: NavigationPropagator = NavigationPropagator
private var ongoingTransition: MagellanTransition? = null
@VisibleForTesting
internal var containerView: ScreenContainer? = null
private var currentNavigable: NavigableCompat? = null
protected val context: Context?
get() = currentState.context
public fun addNavigables(navigables: Set<NavigableCompat>) {
for (navigable in navigables) {
addNavigable(navigable)
}
}
public fun addNavigable(navigable: NavigableCompat) {
lifecycleRegistry.attachToLifecycleWithMaxState(navigable, LifecycleLimit.CREATED)
}
override fun onShow(context: Context) {
containerView = container()
currentNavigable?.let { currentNavigable ->
containerView!!.addView(currentNavigable.view!!)
currentNavigable.transitionStarted()
currentNavigable.transitionFinished()
}
}
override fun onHide(context: Context) {
containerView = null
}
override fun onDestroy(context: Context) {
lifecycleRegistry.children.forEach { lifecycleRegistry.removeFromLifecycle(it) }
}
public fun replace(
navigable: NavigableCompat,
requestedTransition: MagellanTransition = DefaultTransition()
) {
if (currentNavigable == navigable) {
return
}
ongoingTransition?.interrupt()
val transition = if (currentNavigable == null) {
NoAnimationTransition()
} else {
requestedTransition
}
containerView?.setInterceptTouchEvents(true)
navigationPropagator.beforeNavigation()
val from = navigateFrom(currentNavigable)
currentNavigable = navigable
currentNavigableSetup?.invoke(navigable)
val to = navigateTo(navigable)
animateAndRemove(from, to, transition)
}
protected open fun animateAndRemove(
from: View?,
to: View?,
magellanTransition: MagellanTransition
) {
if (to != null) {
currentNavigable!!.transitionStarted()
}
to?.whenMeasured {
val transition = if (shouldRunAnimations()) {
magellanTransition
} else {
NoAnimationTransition()
}
ongoingTransition = transition
transition.animate(from, to, Direction.FORWARD) {
if (context != null && containerView != null) {
containerView!!.removeView(from)
currentNavigable!!.transitionFinished()
navigationPropagator.afterNavigation()
containerView!!.setInterceptTouchEvents(false)
}
ongoingTransition = null
}
}
}
protected open fun navigateTo(currentNavigable: NavigableCompat): View? {
lifecycleRegistry.updateMaxState(currentNavigable, LifecycleLimit.NO_LIMIT)
navigationPropagator.onNavigatedTo(currentNavigable)
when (currentState) {
is LifecycleState.Shown, is LifecycleState.Resumed -> {
val currentView = currentNavigable.view!!
val currentViewParent = currentView.parent
if (currentViewParent == null) {
containerView!!.addView(currentView, 0)
} else if (currentViewParent != containerView) {
throw IllegalStateException(
"currentNavigable ${currentNavigable.javaClass.simpleName} has view already attached to a parent"
)
}
}
is LifecycleState.Destroyed, is LifecycleState.Created -> {
}
}
return currentNavigable.view
}
protected open fun navigateFrom(currentNavigable: NavigableCompat?): View? {
return currentNavigable?.let { oldNavigable ->
val currentView = oldNavigable.view
lifecycleRegistry.updateMaxState(oldNavigable, LifecycleLimit.SHOWN)
navigationPropagator.onNavigatedFrom(oldNavigable)
currentView
}
}
override fun backPressed(): Boolean {
return currentNavigable?.backPressed() ?: false
}
}