react-native-screens 4.21.0 → 4.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/swmansion/rnscreens/ext/ViewExt.kt +9 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/host/FragmentOperation.kt +69 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/host/FragmentOperationExecutor.kt +82 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/host/StackContainer.kt +118 -48
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/host/StackHost.kt +8 -1
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/screen/StackScreen.kt +8 -1
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/screen/StackScreenFragment.kt +7 -5
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/TabsHost.kt +3 -2
- package/ios/RNSScreen.mm +3 -0
- package/lib/typescript/components/helpers/prepareHeaderBarButtonItems.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +1 -1
- package/package.json +1 -1
- package/src/types.tsx +1 -1
|
@@ -3,6 +3,8 @@ package com.swmansion.rnscreens.ext
|
|
|
3
3
|
import android.graphics.drawable.ColorDrawable
|
|
4
4
|
import android.view.View
|
|
5
5
|
import android.view.ViewGroup
|
|
6
|
+
import androidx.fragment.app.Fragment
|
|
7
|
+
import androidx.fragment.app.findFragment
|
|
6
8
|
|
|
7
9
|
internal fun View.parentAsView() = this.parent as? View
|
|
8
10
|
|
|
@@ -37,3 +39,10 @@ internal fun View.maybeBgColor(): Int? {
|
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
internal fun View.asViewGroupOrNull(): ViewGroup? = this as? ViewGroup
|
|
42
|
+
|
|
43
|
+
internal fun View.findFragmentOrNull(): Fragment? =
|
|
44
|
+
try {
|
|
45
|
+
this.findFragment()
|
|
46
|
+
} catch (_: IllegalStateException) {
|
|
47
|
+
null
|
|
48
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
package com.swmansion.rnscreens.gamma.stack.host
|
|
2
|
+
|
|
3
|
+
import androidx.fragment.app.FragmentManager
|
|
4
|
+
import com.swmansion.rnscreens.gamma.stack.screen.StackScreenFragment
|
|
5
|
+
|
|
6
|
+
internal sealed class FragmentOperation {
|
|
7
|
+
internal abstract fun execute(
|
|
8
|
+
fragmentManager: FragmentManager,
|
|
9
|
+
executor: FragmentOperationExecutor,
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
internal class AddOp(
|
|
14
|
+
val fragment: StackScreenFragment,
|
|
15
|
+
val containerViewId: Int,
|
|
16
|
+
val addToBackStack: Boolean,
|
|
17
|
+
val allowStateLoss: Boolean = true,
|
|
18
|
+
) : FragmentOperation() {
|
|
19
|
+
override fun execute(
|
|
20
|
+
fragmentManager: FragmentManager,
|
|
21
|
+
executor: FragmentOperationExecutor,
|
|
22
|
+
) {
|
|
23
|
+
executor.executeAddOp(fragmentManager, this)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
internal class PopBackStackOp(
|
|
28
|
+
val fragment: StackScreenFragment,
|
|
29
|
+
) : FragmentOperation() {
|
|
30
|
+
override fun execute(
|
|
31
|
+
fragmentManager: FragmentManager,
|
|
32
|
+
executor: FragmentOperationExecutor,
|
|
33
|
+
) {
|
|
34
|
+
executor.executePopBackStackOp(fragmentManager, this)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
internal class RemoveOp(
|
|
39
|
+
val fragment: StackScreenFragment,
|
|
40
|
+
val allowStateLoss: Boolean = true,
|
|
41
|
+
val flushSync: Boolean = false,
|
|
42
|
+
) : FragmentOperation() {
|
|
43
|
+
override fun execute(
|
|
44
|
+
fragmentManager: FragmentManager,
|
|
45
|
+
executor: FragmentOperationExecutor,
|
|
46
|
+
) {
|
|
47
|
+
executor.executeRemoveOp(fragmentManager, this)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
internal class FlushNowOp : FragmentOperation() {
|
|
52
|
+
override fun execute(
|
|
53
|
+
fragmentManager: FragmentManager,
|
|
54
|
+
executor: FragmentOperationExecutor,
|
|
55
|
+
) {
|
|
56
|
+
executor.executeFlushOp(fragmentManager, this)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
internal class SetPrimaryNavFragmentOp(
|
|
61
|
+
val fragment: StackScreenFragment,
|
|
62
|
+
) : FragmentOperation() {
|
|
63
|
+
override fun execute(
|
|
64
|
+
fragmentManager: FragmentManager,
|
|
65
|
+
executor: FragmentOperationExecutor,
|
|
66
|
+
) {
|
|
67
|
+
executor.executeSetPrimaryNavFragmentOp(fragmentManager, this)
|
|
68
|
+
}
|
|
69
|
+
}
|
package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/host/FragmentOperationExecutor.kt
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
package com.swmansion.rnscreens.gamma.stack.host
|
|
2
|
+
|
|
3
|
+
import androidx.fragment.app.FragmentManager
|
|
4
|
+
import androidx.fragment.app.FragmentTransaction
|
|
5
|
+
import com.swmansion.rnscreens.gamma.helpers.createTransactionWithReordering
|
|
6
|
+
|
|
7
|
+
internal class FragmentOperationExecutor {
|
|
8
|
+
internal fun executeOperations(
|
|
9
|
+
fragmentManager: FragmentManager,
|
|
10
|
+
ops: List<FragmentOperation>,
|
|
11
|
+
flushSync: Boolean = false
|
|
12
|
+
) {
|
|
13
|
+
ops.forEach { it.execute(fragmentManager, this) }
|
|
14
|
+
|
|
15
|
+
if (flushSync) {
|
|
16
|
+
fragmentManager.executePendingTransactions()
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
internal fun executeAddOp(fragmentManager: FragmentManager, op: AddOp) {
|
|
21
|
+
fragmentManager.createTransactionWithReordering().let { tx ->
|
|
22
|
+
tx.add(op.containerViewId, op.fragment)
|
|
23
|
+
if (op.addToBackStack) {
|
|
24
|
+
tx.addToBackStack(op.fragment.stackScreen.screenKey)
|
|
25
|
+
}
|
|
26
|
+
commitTransaction(tx, op.allowStateLoss)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
internal fun executePopBackStackOp(fragmentManager: FragmentManager, op: PopBackStackOp) {
|
|
31
|
+
fragmentManager.popBackStack(
|
|
32
|
+
op.fragment.stackScreen.screenKey,
|
|
33
|
+
FragmentManager.POP_BACK_STACK_INCLUSIVE
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
internal fun executeRemoveOp(fragmentManager: FragmentManager, op: RemoveOp) {
|
|
38
|
+
fragmentManager.createTransactionWithReordering().let { tx ->
|
|
39
|
+
tx.remove(op.fragment)
|
|
40
|
+
commitTransaction(tx, op.allowStateLoss, op.flushSync)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
internal fun executeFlushOp(fragmentManager: FragmentManager, op: FlushNowOp) {
|
|
45
|
+
fragmentManager.executePendingTransactions()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
internal fun executeSetPrimaryNavFragmentOp(fragmentManager: FragmentManager, op: SetPrimaryNavFragmentOp) {
|
|
49
|
+
fragmentManager.createTransactionWithReordering().let { tx ->
|
|
50
|
+
tx.setPrimaryNavigationFragment(op.fragment)
|
|
51
|
+
commitTransaction(tx, allowStateLoss = true, flushSync = false)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private fun commitTransaction(
|
|
56
|
+
tx: FragmentTransaction,
|
|
57
|
+
allowStateLoss: Boolean,
|
|
58
|
+
flushSync: Boolean = false
|
|
59
|
+
) {
|
|
60
|
+
if (flushSync) {
|
|
61
|
+
commitSync(tx, allowStateLoss)
|
|
62
|
+
} else {
|
|
63
|
+
commitAsync(tx, allowStateLoss)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private fun commitAsync(tx: FragmentTransaction, allowStateLoss: Boolean) {
|
|
68
|
+
if (allowStateLoss) {
|
|
69
|
+
tx.commitAllowingStateLoss()
|
|
70
|
+
} else {
|
|
71
|
+
tx.commit()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private fun commitSync(tx: FragmentTransaction, allowStateLoss: Boolean) {
|
|
76
|
+
if (allowStateLoss) {
|
|
77
|
+
tx.commitNowAllowingStateLoss()
|
|
78
|
+
} else {
|
|
79
|
+
tx.commitNow()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -2,11 +2,12 @@ package com.swmansion.rnscreens.gamma.stack.host
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
|
+
import android.util.Log
|
|
5
6
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
7
|
+
import androidx.fragment.app.Fragment
|
|
6
8
|
import androidx.fragment.app.FragmentManager
|
|
7
9
|
import com.swmansion.rnscreens.gamma.helpers.FragmentManagerHelper
|
|
8
10
|
import com.swmansion.rnscreens.gamma.helpers.ViewIdGenerator
|
|
9
|
-
import com.swmansion.rnscreens.gamma.helpers.createTransactionWithReordering
|
|
10
11
|
import com.swmansion.rnscreens.gamma.stack.screen.StackScreen
|
|
11
12
|
import com.swmansion.rnscreens.gamma.stack.screen.StackScreenFragment
|
|
12
13
|
import com.swmansion.rnscreens.utils.RNSLog
|
|
@@ -16,16 +17,27 @@ import java.lang.ref.WeakReference
|
|
|
16
17
|
internal class StackContainer(
|
|
17
18
|
context: Context,
|
|
18
19
|
private val delegate: WeakReference<StackContainerDelegate>,
|
|
19
|
-
) : CoordinatorLayout(context)
|
|
20
|
+
) : CoordinatorLayout(context),
|
|
21
|
+
FragmentManager.OnBackStackChangedListener {
|
|
20
22
|
private var fragmentManager: FragmentManager? = null
|
|
21
23
|
|
|
22
|
-
private
|
|
24
|
+
private fun requireFragmentManager(): FragmentManager =
|
|
25
|
+
checkNotNull(fragmentManager) { "[RNScreens] Attempt to use nullish FragmentManager" }
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Describes most up-to-date view of the stack. It might be different from
|
|
29
|
+
* state kept by FragmentManager as this data structure is updated immediately,
|
|
30
|
+
* while operations on fragment manager are scheduled.
|
|
31
|
+
*/
|
|
32
|
+
private val stackModel: MutableList<StackScreenFragment> = arrayListOf()
|
|
23
33
|
|
|
24
34
|
private val pendingPopOperations: MutableList<PopOperation> = arrayListOf()
|
|
25
35
|
private val pendingPushOperations: MutableList<PushOperation> = arrayListOf()
|
|
26
36
|
private val hasPendingOperations: Boolean
|
|
27
37
|
get() = pendingPushOperations.isNotEmpty() || pendingPopOperations.isNotEmpty()
|
|
28
38
|
|
|
39
|
+
private val fragmentOpExecutor: FragmentOperationExecutor = FragmentOperationExecutor()
|
|
40
|
+
|
|
29
41
|
init {
|
|
30
42
|
id = ViewIdGenerator.generateViewId()
|
|
31
43
|
}
|
|
@@ -34,16 +46,28 @@ internal class StackContainer(
|
|
|
34
46
|
RNSLog.d(TAG, "StackContainer [$id] attached to window")
|
|
35
47
|
super.onAttachedToWindow()
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
checkNotNull(FragmentManagerHelper.findFragmentManagerForView(this)) {
|
|
39
|
-
"[RNScreens] Nullish fragment manager - can't run container operations"
|
|
40
|
-
}
|
|
49
|
+
setupFragmentManger()
|
|
41
50
|
|
|
42
51
|
// We run container update to handle any pending updates requested before container was
|
|
43
52
|
// attached to window.
|
|
44
53
|
performContainerUpdateIfNeeded()
|
|
45
54
|
}
|
|
46
55
|
|
|
56
|
+
override fun onDetachedFromWindow() {
|
|
57
|
+
super.onDetachedFromWindow()
|
|
58
|
+
requireFragmentManager().removeOnBackStackChangedListener(this)
|
|
59
|
+
fragmentManager = null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
internal fun setupFragmentManger() {
|
|
63
|
+
fragmentManager =
|
|
64
|
+
checkNotNull(FragmentManagerHelper.findFragmentManagerForView(this)) {
|
|
65
|
+
"[RNScreens] Nullish fragment manager - can't run container operations"
|
|
66
|
+
}.also {
|
|
67
|
+
it.addOnBackStackChangedListener(this)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
47
71
|
/**
|
|
48
72
|
* Call this function to trigger container update
|
|
49
73
|
*/
|
|
@@ -52,9 +76,7 @@ internal class StackContainer(
|
|
|
52
76
|
// the call because we don't have valid fragmentManager yet.
|
|
53
77
|
// Update will be eventually executed in onAttachedToWindow().
|
|
54
78
|
if (hasPendingOperations && isAttachedToWindow) {
|
|
55
|
-
|
|
56
|
-
checkNotNull(fragmentManager) { "[RNScreens] Fragment manager was null during stack container update" }
|
|
57
|
-
performOperations(fragmentManager)
|
|
79
|
+
performOperations(requireFragmentManager())
|
|
58
80
|
}
|
|
59
81
|
}
|
|
60
82
|
|
|
@@ -67,59 +89,107 @@ internal class StackContainer(
|
|
|
67
89
|
}
|
|
68
90
|
|
|
69
91
|
private fun performOperations(fragmentManager: FragmentManager) {
|
|
70
|
-
|
|
71
|
-
|
|
92
|
+
val fragmentOps = applyOperationsAndComputeFragmentManagerOperations()
|
|
93
|
+
fragmentOpExecutor.executeOperations(fragmentManager, fragmentOps, flushSync = false)
|
|
72
94
|
|
|
73
|
-
|
|
74
|
-
pendingPushOperations.clear()
|
|
95
|
+
dumpStackModel()
|
|
75
96
|
}
|
|
76
97
|
|
|
77
|
-
private fun
|
|
78
|
-
|
|
79
|
-
operation: PushOperation,
|
|
80
|
-
) {
|
|
81
|
-
val transaction = fragmentManager.createTransactionWithReordering()
|
|
98
|
+
private fun applyOperationsAndComputeFragmentManagerOperations(): List<FragmentOperation> {
|
|
99
|
+
val fragmentOps = mutableListOf<FragmentOperation>()
|
|
82
100
|
|
|
83
|
-
|
|
84
|
-
|
|
101
|
+
// Handle pop operations first.
|
|
102
|
+
// We don't care about pop/push duplicates, as long as we don't let the main loop progress
|
|
103
|
+
// before we commit all the transactions, FragmentManager will handle that for us.
|
|
85
104
|
|
|
86
|
-
|
|
105
|
+
pendingPopOperations.forEach { operation ->
|
|
106
|
+
val fragment =
|
|
107
|
+
checkNotNull(stackModel.find { it.stackScreen === operation.screen }) {
|
|
108
|
+
"[RNScreens] Unable to find a fragment to pop"
|
|
109
|
+
}
|
|
87
110
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
111
|
+
check(stackModel.size > 1) {
|
|
112
|
+
"[RNScreens] Attempt to pop last screen from the stack"
|
|
113
|
+
}
|
|
92
114
|
|
|
93
|
-
|
|
94
|
-
}
|
|
115
|
+
fragmentOps.add(PopBackStackOp(fragment))
|
|
95
116
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
) {
|
|
100
|
-
val associatedFragment = stackScreenFragments.find { it.stackScreen === operation.screen }
|
|
101
|
-
require(associatedFragment != null) {
|
|
102
|
-
"[RNScreens] Unable to find a fragment to pop."
|
|
117
|
+
check(stackModel.removeAt(stackModel.lastIndex) === fragment) {
|
|
118
|
+
"[RNScreens] Attempt to pop non-top screen"
|
|
119
|
+
}
|
|
103
120
|
}
|
|
104
121
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
122
|
+
pendingPushOperations.forEach { operation ->
|
|
123
|
+
val newFragment = createFragmentForScreen(operation.screen)
|
|
124
|
+
fragmentOps.add(
|
|
125
|
+
AddOp(
|
|
126
|
+
newFragment,
|
|
127
|
+
containerViewId = this.id,
|
|
128
|
+
addToBackStack = stackModel.isNotEmpty(),
|
|
129
|
+
),
|
|
110
130
|
)
|
|
111
|
-
|
|
112
|
-
// When fast refresh is used on root screen, we need to remove the screen manually.
|
|
113
|
-
val transaction = fragmentManager.createTransactionWithReordering()
|
|
114
|
-
transaction.remove(associatedFragment)
|
|
115
|
-
transaction.commitNowAllowingStateLoss()
|
|
131
|
+
stackModel.add(newFragment)
|
|
116
132
|
}
|
|
117
133
|
|
|
118
|
-
|
|
134
|
+
check(stackModel.isNotEmpty()) { "[RNScreens] Stack should never be empty after updates" }
|
|
135
|
+
|
|
136
|
+
// Top fragment is the primary navigation fragment.
|
|
137
|
+
fragmentOps.add(SetPrimaryNavFragmentOp(stackModel.last()))
|
|
138
|
+
|
|
139
|
+
pendingPopOperations.clear()
|
|
140
|
+
pendingPushOperations.clear()
|
|
141
|
+
|
|
142
|
+
return fragmentOps
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private fun onNativeFragmentPop(fragment: StackScreenFragment) {
|
|
146
|
+
Log.d(TAG, "StackContainer [$id] natively removed fragment ${fragment.stackScreen.screenKey}")
|
|
147
|
+
require(stackModel.remove(fragment)) { "[RNScreens] onNativeFragmentPop must be called with the fragment present in stack model" }
|
|
148
|
+
check(stackModel.isNotEmpty()) { "[RNScreens] Stack model should not be empty after a native pop" }
|
|
149
|
+
|
|
150
|
+
val fragmentManager = requireFragmentManager()
|
|
151
|
+
if (fragmentManager.primaryNavigationFragment === fragment) {
|
|
152
|
+
// We need to update the primary navigation fragment, otherwise the fragment manager
|
|
153
|
+
// will have invalid state, pointing to the dismissed fragment.
|
|
154
|
+
fragmentOpExecutor.executeOperations(
|
|
155
|
+
fragmentManager,
|
|
156
|
+
listOf(SetPrimaryNavFragmentOp(stackModel.last())),
|
|
157
|
+
)
|
|
158
|
+
}
|
|
119
159
|
}
|
|
120
160
|
|
|
121
|
-
|
|
122
|
-
|
|
161
|
+
private fun dumpStackModel() {
|
|
162
|
+
Log.d(TAG, "StackContainer [$id] MODEL BEGIN")
|
|
163
|
+
stackModel.forEach {
|
|
164
|
+
Log.d(TAG, "${it.stackScreen.screenKey}")
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private fun createFragmentForScreen(screen: StackScreen): StackScreenFragment =
|
|
169
|
+
StackScreenFragment(screen).also {
|
|
170
|
+
Log.d(TAG, "Created Fragment $it for screen ${screen.screenKey}")
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// This is called after special effects (animations) are dispatched
|
|
174
|
+
override fun onBackStackChanged() = Unit
|
|
175
|
+
|
|
176
|
+
// This is called before the special effects (animations) are dispatched, however mid transaction!
|
|
177
|
+
// Therefore make sure to not execute any action that might cause synchronous transaction synchronously
|
|
178
|
+
// from this callback.
|
|
179
|
+
override fun onBackStackChangeCommitted(
|
|
180
|
+
fragment: Fragment,
|
|
181
|
+
pop: Boolean,
|
|
182
|
+
) {
|
|
183
|
+
if (fragment !is StackScreenFragment) {
|
|
184
|
+
Log.w(TAG, "[RNScreens] Unexpected type of fragment: ${fragment.javaClass.simpleName}")
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
if (pop) {
|
|
188
|
+
delegate.get()?.onScreenDismiss(fragment.stackScreen)
|
|
189
|
+
if (stackModel.contains(fragment)) {
|
|
190
|
+
onNativeFragmentPop(fragment)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
123
193
|
}
|
|
124
194
|
|
|
125
195
|
companion object {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package com.swmansion.rnscreens.gamma.stack.host
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.util.Log
|
|
4
5
|
import android.view.ViewGroup
|
|
5
6
|
import com.facebook.react.bridge.UIManager
|
|
6
7
|
import com.facebook.react.bridge.UIManagerListener
|
|
@@ -75,6 +76,8 @@ class StackHost(
|
|
|
75
76
|
if (stackScreen.activityMode == StackScreen.ActivityMode.ATTACHED && !stackScreen.isNativelyDismissed) {
|
|
76
77
|
// This shouldn't happen in typical scenarios but it can happen with fast-refresh.
|
|
77
78
|
containerUpdateCoordinator.addPopOperation(stackScreen)
|
|
79
|
+
} else {
|
|
80
|
+
Log.d(TAG, "Ignoring pop operation of ${stackScreen.screenKey}, already not attached or natively dismissed")
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
|
|
@@ -85,7 +88,11 @@ class StackHost(
|
|
|
85
88
|
}
|
|
86
89
|
}
|
|
87
90
|
|
|
88
|
-
override fun onScreenDismiss(stackScreen: StackScreen)
|
|
91
|
+
override fun onScreenDismiss(stackScreen: StackScreen) {
|
|
92
|
+
if (stackScreen.activityMode == StackScreen.ActivityMode.ATTACHED) {
|
|
93
|
+
stackScreen.isNativelyDismissed = true
|
|
94
|
+
}
|
|
95
|
+
}
|
|
89
96
|
|
|
90
97
|
override fun onMeasure(
|
|
91
98
|
widthMeasureSpec: Int,
|
|
@@ -2,8 +2,11 @@ package com.swmansion.rnscreens.gamma.stack.screen
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.view.ViewGroup
|
|
5
|
+
import androidx.fragment.app.Fragment
|
|
5
6
|
import androidx.lifecycle.LifecycleOwner
|
|
6
7
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
8
|
+
import com.swmansion.rnscreens.ext.findFragmentOrNull
|
|
9
|
+
import com.swmansion.rnscreens.gamma.common.FragmentProviding
|
|
7
10
|
import com.swmansion.rnscreens.gamma.stack.host.StackHost
|
|
8
11
|
import java.lang.ref.WeakReference
|
|
9
12
|
import kotlin.properties.Delegates
|
|
@@ -11,7 +14,7 @@ import kotlin.properties.Delegates
|
|
|
11
14
|
@SuppressLint("ViewConstructor") // should never be restored
|
|
12
15
|
class StackScreen(
|
|
13
16
|
private val reactContext: ThemedReactContext,
|
|
14
|
-
) : ViewGroup(reactContext) {
|
|
17
|
+
) : ViewGroup(reactContext), FragmentProviding {
|
|
15
18
|
enum class ActivityMode {
|
|
16
19
|
DETACHED,
|
|
17
20
|
ATTACHED,
|
|
@@ -65,4 +68,8 @@ class StackScreen(
|
|
|
65
68
|
r: Int,
|
|
66
69
|
b: Int,
|
|
67
70
|
) = Unit
|
|
71
|
+
|
|
72
|
+
override fun getAssociatedFragment(): Fragment? = this.findFragmentOrNull()?.also {
|
|
73
|
+
check(it is StackScreenFragment) { "[RNScreens] Unexpected fragment type: ${it.javaClass.simpleName}"}
|
|
74
|
+
}
|
|
68
75
|
}
|
package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/screen/StackScreenFragment.kt
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
package com.swmansion.rnscreens.gamma.stack.screen
|
|
2
2
|
|
|
3
3
|
import android.os.Bundle
|
|
4
|
+
import android.util.Log
|
|
4
5
|
import android.view.LayoutInflater
|
|
5
6
|
import android.view.View
|
|
6
7
|
import android.view.ViewGroup
|
|
7
8
|
import androidx.fragment.app.Fragment
|
|
8
|
-
import com.swmansion.rnscreens.gamma.stack.host.StackContainer
|
|
9
|
-
import java.lang.ref.WeakReference
|
|
10
9
|
|
|
11
10
|
internal class StackScreenFragment(
|
|
12
|
-
private val stackContainer: WeakReference<StackContainer>,
|
|
13
11
|
internal val stackScreen: StackScreen,
|
|
14
12
|
) : Fragment() {
|
|
15
13
|
private var screenLifecycleEventEmitter: StackScreenAppearanceEventsEmitter? = null
|
|
@@ -30,8 +28,12 @@ internal class StackScreenFragment(
|
|
|
30
28
|
|
|
31
29
|
override fun onDestroyView() {
|
|
32
30
|
super.onDestroyView()
|
|
33
|
-
stackScreen.onDismiss()
|
|
34
|
-
stackContainer.get()?.onFragmentDestroyView(this)
|
|
35
31
|
screenLifecycleEventEmitter = null
|
|
36
32
|
}
|
|
33
|
+
|
|
34
|
+
override fun onDestroy() {
|
|
35
|
+
super.onDestroy()
|
|
36
|
+
Log.i("StackScreenFragment", "onDestroy")
|
|
37
|
+
stackScreen.onDismiss()
|
|
38
|
+
}
|
|
37
39
|
}
|
|
@@ -382,8 +382,9 @@ class TabsHost(
|
|
|
382
382
|
private fun updateSelectedTab() {
|
|
383
383
|
val newFocusedTab = currentFocusedTab
|
|
384
384
|
|
|
385
|
-
|
|
386
|
-
|
|
385
|
+
val tabFragments = requireFragmentManager.fragments.filterIsInstance<TabScreenFragment>()
|
|
386
|
+
check(tabFragments.size <= 1) { "[RNScreens] There can be only a single focused tab" }
|
|
387
|
+
val oldFocusedTab = tabFragments.firstOrNull()
|
|
387
388
|
|
|
388
389
|
if (newFocusedTab === oldFocusedTab) {
|
|
389
390
|
return
|
package/ios/RNSScreen.mm
CHANGED
|
@@ -2097,6 +2097,9 @@ Class<RCTComponentViewProtocol> RNSScreenCls(void)
|
|
|
2097
2097
|
if ([vc isKindOfClass:[RNSScreen class]]) {
|
|
2098
2098
|
return ((RNSScreen *)vc).screenView.screenOrientation;
|
|
2099
2099
|
}
|
|
2100
|
+
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
|
2101
|
+
return UIInterfaceOrientationMaskAll;
|
|
2102
|
+
}
|
|
2100
2103
|
return UIInterfaceOrientationMaskAllButUpsideDown;
|
|
2101
2104
|
}
|
|
2102
2105
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepareHeaderBarButtonItems.d.ts","sourceRoot":"","sources":["../../../../src/components/helpers/prepareHeaderBarButtonItems.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AAkCpC,eAAO,MAAM,2BAA2B,GACtC,gBAAgB,mBAAmB,EAAE,EACrC,MAAM,MAAM,GAAG,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"prepareHeaderBarButtonItems.d.ts","sourceRoot":"","sources":["../../../../src/components/helpers/prepareHeaderBarButtonItems.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AAkCpC,eAAO,MAAM,2BAA2B,GACtC,gBAAgB,mBAAmB,EAAE,EACrC,MAAM,MAAM,GAAG,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAoD89yC,CAAC;;uBAAwG,CAAC;wBAA+B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAD/nzC,CAAC"}
|
|
@@ -287,7 +287,7 @@ export interface ScreenProps extends ViewProps {
|
|
|
287
287
|
/**
|
|
288
288
|
* In which orientation should the screen appear.
|
|
289
289
|
* The following values are currently supported:
|
|
290
|
-
* - "default" - resolves to "all" without "portrait_down" on
|
|
290
|
+
* - "default" - resolves to "all" without "portrait_down" on iPhone devices, "all" on iPad devices. On Android, this lets the system decide the best orientation.
|
|
291
291
|
* - "all" – all orientations are permitted
|
|
292
292
|
* - "portrait" – portrait orientations are permitted
|
|
293
293
|
* - "portrait_up" – right-side portrait orientation is permitted
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-screens",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.22.0",
|
|
4
4
|
"description": "Native navigation primitives for your React Native app.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"submodules": "git submodule update --init --recursive && (cd react-navigation && yarn && yarn build && cd ../)",
|
package/src/types.tsx
CHANGED
|
@@ -378,7 +378,7 @@ export interface ScreenProps extends ViewProps {
|
|
|
378
378
|
/**
|
|
379
379
|
* In which orientation should the screen appear.
|
|
380
380
|
* The following values are currently supported:
|
|
381
|
-
* - "default" - resolves to "all" without "portrait_down" on
|
|
381
|
+
* - "default" - resolves to "all" without "portrait_down" on iPhone devices, "all" on iPad devices. On Android, this lets the system decide the best orientation.
|
|
382
382
|
* - "all" – all orientations are permitted
|
|
383
383
|
* - "portrait" – portrait orientations are permitted
|
|
384
384
|
* - "portrait_up" – right-side portrait orientation is permitted
|