Skip to content

Commit f0a040b

Browse files
author
Vailence
committed
MOBILE-342: Leave the pinned version alone and keep the notes to the public API
The SDK version was only lifted into a variable, not changed — and a branch that changes nothing about it should not touch the line at all. The two dependencies the block needs are spelled with the version develop already pins. The notes stay where a caller reads them: the props, the outcomes and the component itself. The native sides, the codegen spec and the suite carry none.
1 parent f36278d commit f0a040b

9 files changed

Lines changed: 4 additions & 347 deletions

‎android/build.gradle‎

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ buildscript {
1616

1717
apply plugin: 'com.android.library'
1818
apply plugin: 'kotlin-android'
19-
// After `com.android.library`: the React plugin wires its codegen tasks from the Android library
20-
// extension, and applying it first leaves the library without them.
2119
apply plugin: "com.facebook.react"
2220

2321
def getExtOrDefault(name) {
@@ -125,18 +123,11 @@ repositories {
125123

126124
def kotlin_version = getExtOrDefault('kotlinVersion')
127125

128-
// Held next to the SDK version develop already pins, so the two move together.
129-
def nativeSdkVersion = '2.15.4'
130-
131126
dependencies {
132127
// noinspection GradleDynamicVersion
133128
api 'com.facebook.react:react-native:+'
134129
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
135-
api "cloud.mindbox:mobile-sdk:$nativeSdkVersion"
136-
// The block reads its host screen's lifecycle off the view tree, and this wrapper has to put one
137-
// there: React Native's own view lifetime, not the fragment's.
130+
api 'cloud.mindbox:mobile-sdk:2.15.4'
138131
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.7"
139-
// The SDK keeps mindbox-common an `implementation` dependency, so `@InternalMindboxApi` — the
140-
// annotation the embedded block hooks are marked with — is not on the compile classpath without this.
141-
compileOnly "cloud.mindbox:mindbox-common:$nativeSdkVersion"
132+
compileOnly 'cloud.mindbox:mindbox-common:2.15.4'
142133
}

‎android/src/main/java/com/mindboxsdk/embedded/MindboxEmbeddedBlockEvents.kt‎

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,11 @@ import com.facebook.react.bridge.Arguments
44
import com.facebook.react.bridge.WritableMap
55
import com.facebook.react.uimanager.events.Event
66

7-
/**
8-
* Where the block stands now. A state and not an event: the same value arrives more than once, and the
9-
* JS side keeps the last one it knew.
10-
*/
117
internal class AppearanceChangeEvent(
128
surfaceId: Int,
139
viewTag: Int,
1410
private val appearance: String,
1511
) : Event<AppearanceChangeEvent>(surfaceId, viewTag) {
16-
1712
override fun getEventName(): String = EVENT_NAME
1813

1914
override fun getEventData(): WritableMap = Arguments.createMap().apply {
@@ -25,9 +20,7 @@ internal class AppearanceChangeEvent(
2520
}
2621
}
2722

28-
/** The content is shown. */
2923
internal class BlockLoadEvent(surfaceId: Int, viewTag: Int) : Event<BlockLoadEvent>(surfaceId, viewTag) {
30-
3124
override fun getEventName(): String = EVENT_NAME
3225

3326
override fun getEventData(): WritableMap = Arguments.createMap()
@@ -37,12 +30,7 @@ internal class BlockLoadEvent(surfaceId: Int, viewTag: Int) : Event<BlockLoadEve
3730
}
3831
}
3932

40-
/**
41-
* The place ended up without content. No payload yet — the reason for the failure is not something the
42-
* SDK tells apart today, and when it does it lands in this map.
43-
*/
4433
internal class BlockFailEvent(surfaceId: Int, viewTag: Int) : Event<BlockFailEvent>(surfaceId, viewTag) {
45-
4634
override fun getEventName(): String = EVENT_NAME
4735

4836
override fun getEventData(): WritableMap = Arguments.createMap()

‎android/src/main/java/com/mindboxsdk/embedded/MindboxEmbeddedBlockHostView.kt‎

Lines changed: 0 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,10 @@ import cloud.mindbox.mobile_sdk.embedded.MindboxEmbeddedBlockListener
1515
import cloud.mindbox.mobile_sdk.embedded.MindboxEmbeddedBlockView
1616
import cloud.mindbox.mobile_sdk.logger.Level
1717

18-
/**
19-
* The React Native side of one embedded block: a frame that holds the SDK's own container and turns
20-
* its two signals into RN events.
21-
*
22-
* The block itself is the SDK's `MindboxEmbeddedBlockView`, whole and unchanged — the content
23-
* factory, the waiting budget, the page and its bridge stay on the native side, and RN gets a view to
24-
* place plus the signals to react to.
25-
*
26-
* Why a frame around it rather than the block itself: the SDK block takes its place system name in
27-
* the constructor, and RN creates a view before it has any props. So the block is built once the
28-
* props of the first transaction are all in (see [commitProps]) and lives inside this frame.
29-
*/
3018
@OptIn(InternalMindboxApi::class)
3119
internal class MindboxEmbeddedBlockHostView(context: Context) : FrameLayout(context) {
32-
33-
/** Native → RN: where the block stands now, as one of the wire words. */
3420
var onAppearance: ((String) -> Unit)? = null
3521

36-
/** Native → RN: how the load ended — `load` or `fail`. */
3722
var onOutcome: ((String) -> Unit)? = null
3823

3924
private var blockView: MindboxEmbeddedBlockView? = null
@@ -43,22 +28,9 @@ internal class MindboxEmbeddedBlockHostView(context: Context) : FrameLayout(cont
4328
private var hasPlaceholder: Boolean = false
4429
private var hasErrorView: Boolean = false
4530

46-
/**
47-
* The stand-ins currently handed to the container, kept to tell "the host still draws its own
48-
* screen" from "it has just started to".
49-
*/
5031
private var placeholderStandIn: View? = null
5132
private var errorStandIn: View? = null
5233

53-
/**
54-
* The lifecycle the block reads as its host screen's.
55-
*
56-
* The container gives up for good when the lifecycle owner above it is destroyed — the right rule
57-
* for a native screen, and the wrong one here. React Native keeps this view across screens while
58-
* `react-native-screens` destroys the fragment of a screen that gets covered: the block would hear
59-
* its host die, free its page, and come back to a screen it can no longer load anything for. So the
60-
* block is told about the lifetime that actually matters — this view's own.
61-
*/
6234
private val hostLifecycleOwner = object : LifecycleOwner {
6335
val registry: LifecycleRegistry = LifecycleRegistry(this)
6436

@@ -71,21 +43,8 @@ internal class MindboxEmbeddedBlockHostView(context: Context) : FrameLayout(cont
7143
setViewTreeLifecycleOwner(hostLifecycleOwner)
7244
}
7345

74-
/**
75-
* Lays the block out again after React Native has stopped listening.
76-
*
77-
* Yoga owns layout in RN, so the view groups on the way up answer `requestLayout()` with nothing.
78-
* The container swaps its own children as the block resolves — the shimmer for the page, the page
79-
* for the failure — and every child added after the last layout pass would stay at zero size: the
80-
* page loads, reports its content, and nobody ever sees it. So the frame measures and lays itself
81-
* out on the next turn of the looper, with the bounds RN gave it.
82-
*/
8346
private val measureAndLayout = Runnable {
8447
isLayoutScheduled = false
85-
// `forceLayout` and not just `measure`: the container swaps a child while RN is already inside
86-
// its own layout pass, and that pass clears the flag `requestLayout` had set — a `measure` with
87-
// unchanged specs would then return without measuring anything, and the new child would keep
88-
// its zero size for good.
8948
forceLayout()
9049
measure(
9150
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
@@ -96,7 +55,6 @@ internal class MindboxEmbeddedBlockHostView(context: Context) : FrameLayout(cont
9655

9756
private var isLayoutScheduled = false
9857

99-
/** Whether RN has asked for a block at all — the props of the first transaction have landed. */
10058
private var isBlockWanted = false
10159

10260
override fun requestLayout() {
@@ -111,29 +69,14 @@ internal class MindboxEmbeddedBlockHostView(context: Context) : FrameLayout(cont
11169
}
11270

11371
fun setPlaceSystemName(name: String?) {
114-
// Taken exactly as given: the SDK compares names without trimming on every platform, so a
115-
// padded name is a name like any other — one that simply never resolves. Filtering it here
116-
// would turn that into a block that never settles, which is worse than one that collapses.
11772
if (name == placeSystemName) {
11873
return
11974
}
12075

121-
// A different place is a different block, and the old one has nothing to hand over. The
122-
// wrapper keys the whole component by the place, so this is a safety net and not the usual
123-
// path — but a place changed under a live block must not leave the old one running.
12476
placeSystemName = name
12577
dropBlock()
12678
}
12779

128-
/**
129-
* The waiting budget the block is built with, in milliseconds as they came over the wire.
130-
*
131-
* Zero is the wire word for "the host said nothing" and turns back into the null the SDK
132-
* constructor reads as its own default; anything else — a negative included — is handed over as it
133-
* is, for the container to sanitize and log. A value that arrives after the block is built goes
134-
* nowhere: a running wait cannot be re-budgeted, the JS wrapper both freezes the value and warns,
135-
* and this is only the native end of that same rule.
136-
*/
13780
fun setTimeoutMs(timeoutMs: Double) {
13881
if (blockView == null) {
13982
this.timeoutMs = timeoutMs.takeIf { it != 0.0 }?.toLong()
@@ -167,46 +110,23 @@ internal class MindboxEmbeddedBlockHostView(context: Context) : FrameLayout(cont
167110
syncStandIns()
168111
}
169112

170-
/**
171-
* The props of a transaction are all in — the block can be built as soon as there is a frame to
172-
* build it in.
173-
*
174-
* Called from here and nowhere else: `createViewInstance` has no props yet, and a single prop
175-
* setter would build a block on the place system name while the stand-in flags were still the
176-
* defaults.
177-
*/
178113
fun commitProps() {
179114
isBlockWanted = true
180115
buildBlockIfPossible()
181116
}
182117

183-
/**
184-
* The frame has bounds now, which is what the block was waiting for.
185-
*
186-
* A block built before them starts its page in a view of zero size: the page lays itself out
187-
* against a zero-width viewport, reports content that occupies nothing, and a later resize does
188-
* not make it lay out again — the block reports `onLoad` for a feed nobody can see. RN gives a view
189-
* its bounds after the props, so the block waits for them.
190-
*/
191118
override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
192119
super.onSizeChanged(width, height, oldWidth, oldHeight)
193120
buildBlockIfPossible()
194121
}
195122

196-
/**
197-
* The container hands out its appearance the moment the observer subscribes — and a place with
198-
* nothing behind it settles right there — so subscribing happens before the block ever reaches the
199-
* window.
200-
*/
201123
private fun buildBlockIfPossible() {
202124
val place = placeSystemName ?: return
203125
if (blockView != null || !isBlockWanted || width == 0 || height == 0) {
204126
return
205127
}
206128

207129
if (place.isEmpty()) {
208-
// Built all the same: the SDK settles a nameless place as empty, so the host hears
209-
// `collapsed` and `onFail` instead of watching a placeholder that never resolves.
210130
Mindbox.writeLog(
211131
message = "[EmbeddedBlock] A React Native block was created without a place system name and has nothing to resolve",
212132
logLevel = Level.ERROR,
@@ -231,21 +151,13 @@ internal class MindboxEmbeddedBlockHostView(context: Context) : FrameLayout(cont
231151
)
232152
block.setAppearanceObserver { appearance -> onAppearance?.invoke(nameOf(appearance)) }
233153

234-
// Last: attaching to the window is what starts the content, and by now everything that has an
235-
// opinion about it has been said.
236154
addView(block, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
237155
}
238156

239-
/**
240-
* The RN view is gone, so the block's screen is gone with it. Waiting for the host Activity to be
241-
* destroyed instead would keep a page loading for a screen nobody can see.
242-
*/
243157
fun release() {
244158
dropBlock()
245159
onAppearance = null
246160
onOutcome = null
247-
// Now the host screen really is gone, and a block that outlived this call — one the platform
248-
// still holds a reference to — has to hear it.
249161
hostLifecycleOwner.registry.currentState = Lifecycle.State.DESTROYED
250162
}
251163

@@ -261,16 +173,6 @@ internal class MindboxEmbeddedBlockHostView(context: Context) : FrameLayout(cont
261173
removeView(block)
262174
}
263175

264-
/**
265-
* Puts an empty view where the host draws its own screen — the same arrangement the Compose and
266-
* Flutter wrappers use for a slot they cannot hand over directly.
267-
*
268-
* RN children are real Android views, but the ones above this block belong to Fabric: it mounts
269-
* them, and Yoga lays them out. Handing them to the container would take them out of both. So the
270-
* container is not given the screen: it is given the fact that the place is taken. That is all it
271-
* needs — its own placeholder is held back, and a failed block keeps its height instead of
272-
* collapsing. What is actually drawn there is an RN overlay above this frame.
273-
*/
274176
private fun syncStandIns() {
275177
val block = blockView ?: return
276178

@@ -297,21 +199,14 @@ internal class MindboxEmbeddedBlockHostView(context: Context) : FrameLayout(cont
297199

298200
private fun makeStandIn(): View = View(context).apply {
299201
setBackgroundColor(Color.TRANSPARENT)
300-
// The stand-in is a placeholder for space, not for touches: what the host drew over it is an
301-
// RN view, and it is RN that has to hear the taps on it.
302202
isClickable = false
303203
isFocusable = false
304204
}
305205

306206
private companion object {
307-
308207
const val OUTCOME_LOAD = "load"
309208
const val OUTCOME_FAIL = "fail"
310209

311-
/**
312-
* Spelled out rather than taken from the enum name: the wire word is a contract with the JS
313-
* side, and renaming a case in the SDK must not quietly change it.
314-
*/
315210
fun nameOf(appearance: MindboxEmbeddedBlockAppearance): String = when (appearance) {
316211
MindboxEmbeddedBlockAppearance.PLACEHOLDER -> "placeholder"
317212
MindboxEmbeddedBlockAppearance.CONTENT -> "content"

‎android/src/main/java/com/mindboxsdk/embedded/MindboxEmbeddedBlockViewManager.kt‎

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ import com.facebook.react.uimanager.events.Event
1010
import com.facebook.react.viewmanagers.MindboxEmbeddedBlockViewManagerDelegate
1111
import com.facebook.react.viewmanagers.MindboxEmbeddedBlockViewManagerInterface
1212

13-
/** The manager of the embedded block component: props in, the block's two signals out. */
1413
@ReactModule(name = MindboxEmbeddedBlockViewManager.NAME)
1514
internal class MindboxEmbeddedBlockViewManager :
1615
SimpleViewManager<MindboxEmbeddedBlockHostView>(),
1716
MindboxEmbeddedBlockViewManagerInterface<MindboxEmbeddedBlockHostView> {
18-
1917
private val managerDelegate = MindboxEmbeddedBlockViewManagerDelegate(this)
2018

2119
override fun getDelegate(): ViewManagerDelegate<MindboxEmbeddedBlockHostView> = managerDelegate
@@ -37,10 +35,6 @@ internal class MindboxEmbeddedBlockViewManager :
3735
}
3836
}
3937

40-
/**
41-
* The block is built here and not in a prop setter: this is the first moment every prop of the
42-
* transaction is in, and the container needs the place system name and the stand-in flags together.
43-
*/
4438
override fun onAfterUpdateTransaction(view: MindboxEmbeddedBlockHostView) {
4539
super.onAfterUpdateTransaction(view)
4640
view.commitProps()
@@ -51,11 +45,6 @@ internal class MindboxEmbeddedBlockViewManager :
5145
super.onDropViewInstance(view)
5246
}
5347

54-
/**
55-
* Never recycled. Fabric would hand this frame to another place, and the SDK block inside it cannot
56-
* be revived — `release()` is one way. Creating the block with the view and killing it with the view
57-
* is what keeps the lifecycle here simple.
58-
*/
5948
override fun prepareToRecycleView(
6049
reactContext: ThemedReactContext,
6150
view: MindboxEmbeddedBlockHostView,
@@ -65,10 +54,6 @@ internal class MindboxEmbeddedBlockViewManager :
6554
view.setPlaceSystemName(value)
6655
}
6756

68-
/**
69-
* Read and ignored: on Android the block is a frame sized by its parent, and here that parent is
70-
* RN — the view is laid out to the height the style gives it. The prop exists because iOS needs it.
71-
*/
7257
override fun setBlockHeight(view: MindboxEmbeddedBlockHostView, value: Double) = Unit
7358

7459
override fun setTimeoutMs(view: MindboxEmbeddedBlockHostView, value: Double) {

0 commit comments

Comments
 (0)