-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathModalViewManager.kt
More file actions
150 lines (131 loc) · 6.07 KB
/
ModalViewManager.kt
File metadata and controls
150 lines (131 loc) · 6.07 KB
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
144
145
146
147
148
149
150
package com.reactnativenavigation.react.modal
import android.app.Activity
import android.content.Context
import android.graphics.Point
import android.view.WindowManager
import com.facebook.infer.annotation.Assertions
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.common.MapBuilder
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.LayoutShadowNode
import com.facebook.react.uimanager.ReactShadowNodeImpl
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.ViewGroupManager
import com.facebook.react.uimanager.annotations.ReactProp
import com.reactnativenavigation.NavigationActivity
import com.reactnativenavigation.options.ModalPresentationStyle
import com.reactnativenavigation.options.Options
import com.reactnativenavigation.options.params.Bool
import com.reactnativenavigation.options.parseTransitionAnimationOptions
import com.reactnativenavigation.options.parsers.JSONParser
import com.reactnativenavigation.react.CommandListener
import com.reactnativenavigation.react.CommandListenerAdapter
import com.reactnativenavigation.utils.SystemUiUtils
import com.reactnativenavigation.viewcontrollers.navigator.Navigator
private const val MODAL_MANAGER_NAME = "RNNModalViewManager"
@ReactModule(name = MODAL_MANAGER_NAME)
class ModalViewManager(val reactContext: ReactContext) : ViewGroupManager<ModalHostLayout>() {
private val navigator: Navigator?
get() {
val navigationActivity = reactContext.currentActivity as? NavigationActivity
return navigationActivity?.let {
if (it.isFinishing || it.isDestroyed) null else it.navigator
}
}
private val jsonParser = JSONParser()
override fun getName(): String = MODAL_MANAGER_NAME
override fun createViewInstance(reactContext: ThemedReactContext): ModalHostLayout {
return ModalHostLayout(reactContext)
}
override fun createShadowNodeInstance(): LayoutShadowNode {
return ModalHostShadowNode()
}
override fun getShadowNodeClass(): Class<out LayoutShadowNode> {
return ModalHostShadowNode::class.java
}
override fun onDropViewInstance(modal: ModalHostLayout) {
super.onDropViewInstance(modal)
navigator?.let {
it.dismissModal(modal.viewController.id, CommandListenerAdapter())
modal.onDropInstance()
}
}
override fun onAfterUpdateTransaction(modal: ModalHostLayout) {
super.onAfterUpdateTransaction(modal)
navigator?.showModal(modal.viewController, CommandListenerAdapter(object : CommandListener {
override fun onSuccess(childId: String?) {
modal.viewController.sendShowEvent()
}
override fun onError(message: String?) {
}
}))
}
override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
return MapBuilder.builder<String, Any>()
.put(RequestCloseModalEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRequestClose"))
.put(ShowModalEvent.EVENT_NAME, MapBuilder.of("registrationName", "onShow"))
.build()
}
@ReactProp(name = "animation")
fun setAnimation(modal: ModalHostLayout, animation: ReadableMap) {
modal.viewController.mergeOptions(Options().apply {
val animationJson = jsonParser.parse(animation)
val showModal = parseTransitionAnimationOptions(animationJson.optJSONObject("showModal"))
val dismissModal = parseTransitionAnimationOptions(animationJson.optJSONObject("dismissModal"))
this.animations.showModal = showModal
this.animations.dismissModal = dismissModal
})
}
@ReactProp(name = "blurOnUnmount")
fun setBlurOnUnmount(modal: ModalHostLayout, blurOnUnmount: Boolean) {
modal.viewController.mergeOptions(Options().apply {
this.modal.blurOnUnmount = Bool(blurOnUnmount)
})
}
@ReactProp(name = "transparent")
fun setTransparent(modal: ModalHostLayout, transparent: Boolean) {
modal.viewController.mergeOptions(Options().apply {
this.modal.presentationStyle =
if (transparent) ModalPresentationStyle.OverCurrentContext else ModalPresentationStyle.None
})
}
}
private fun getModalHostSize(activity: Activity): Point {
val MIN_POINT = Point()
val MAX_POINT = Point()
val SIZE_POINT = Point()
val wm = activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val display = Assertions.assertNotNull(wm).defaultDisplay
// getCurrentSizeRange will return the min and max width and height that the window can be
display.getCurrentSizeRange(MIN_POINT, MAX_POINT)
// getSize will return the dimensions of the screen in its current orientation
display.getSize(SIZE_POINT)
val attrs = intArrayOf(android.R.attr.windowFullscreen)
val theme = activity.theme
val ta = theme.obtainStyledAttributes(attrs)
val windowFullscreen = ta.getBoolean(0, false)
// We need to add the status bar height to the height if we have a fullscreen window,
// because Display.getCurrentSizeRange doesn't include it.
var statusBarHeight = 0
if (windowFullscreen) {
statusBarHeight = SystemUiUtils.getStatusBarHeight(activity)
}
return if (SIZE_POINT.x < SIZE_POINT.y) {
// If we are vertical the width value comes from min width and height comes from max height
Point(MIN_POINT.x, MAX_POINT.y + statusBarHeight)
} else {
// If we are horizontal the width value comes from max width and height comes from min height
Point(MAX_POINT.x, MIN_POINT.y + statusBarHeight)
}
}
private class ModalHostShadowNode : LayoutShadowNode() {
override fun addChildAt(child: ReactShadowNodeImpl, i: Int) {
super.addChildAt(child, i)
themedContext?.currentActivity?.let {
val modalSize = getModalHostSize(it)
child.setStyleWidth(modalSize.x.toFloat())
child.setStyleHeight(modalSize.y.toFloat())
}
}
}