react-native-morph-card 0.1.2 → 0.1.4
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.
|
@@ -362,7 +362,46 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
|
|
|
362
362
|
// Capture snapshot
|
|
363
363
|
val cardImage = captureSnapshot()
|
|
364
364
|
|
|
365
|
-
// Create overlay
|
|
365
|
+
// Create a full-screen overlay that blocks the modal target screen from
|
|
366
|
+
// being visible. We use PixelCopy to capture the current screen with
|
|
367
|
+
// hardware rendering preserved (clipToOutline, borderRadius, etc.).
|
|
368
|
+
val fullScreenOverlay = FrameLayout(context)
|
|
369
|
+
fullScreenOverlay.layoutParams = FrameLayout.LayoutParams(
|
|
370
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
371
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
372
|
+
)
|
|
373
|
+
fullScreenOverlay.isClickable = true
|
|
374
|
+
|
|
375
|
+
// PixelCopy captures from the surface (hardware-rendered, preserves outlines).
|
|
376
|
+
// We use a background HandlerThread for the callback to avoid deadlocking main.
|
|
377
|
+
val window = (context as? android.app.Activity)?.window
|
|
378
|
+
if (window != null) {
|
|
379
|
+
val blockerBitmap = Bitmap.createBitmap(decorView.width, decorView.height, Bitmap.Config.ARGB_8888)
|
|
380
|
+
val copyThread = android.os.HandlerThread("PixelCopyThread")
|
|
381
|
+
copyThread.start()
|
|
382
|
+
val copyHandler = Handler(copyThread.looper)
|
|
383
|
+
val latch = java.util.concurrent.CountDownLatch(1)
|
|
384
|
+
android.view.PixelCopy.request(window, blockerBitmap, { result ->
|
|
385
|
+
if (result != android.view.PixelCopy.SUCCESS) {
|
|
386
|
+
Log.d(TAG, "prepareExpand: PixelCopy failed with result=$result")
|
|
387
|
+
}
|
|
388
|
+
latch.countDown()
|
|
389
|
+
}, copyHandler)
|
|
390
|
+
// Wait for the copy (typically <5ms)
|
|
391
|
+
try { latch.await(100, java.util.concurrent.TimeUnit.MILLISECONDS) } catch (_: Exception) {}
|
|
392
|
+
copyThread.quitSafely()
|
|
393
|
+
|
|
394
|
+
val blockerImg = ImageView(context)
|
|
395
|
+
blockerImg.setImageBitmap(blockerBitmap)
|
|
396
|
+
blockerImg.scaleType = ImageView.ScaleType.FIT_XY
|
|
397
|
+
blockerImg.layoutParams = FrameLayout.LayoutParams(
|
|
398
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
399
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
400
|
+
)
|
|
401
|
+
fullScreenOverlay.addView(blockerImg)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Create card overlay at source position (on top of screen capture)
|
|
366
405
|
val bgColor = cardBgColor
|
|
367
406
|
val wrapper = FrameLayout(context)
|
|
368
407
|
wrapper.layoutParams = FrameLayout.LayoutParams(cardWidth.toInt(), cardHeight.toInt())
|
|
@@ -380,9 +419,11 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
|
|
|
380
419
|
content.scaleType = ImageView.ScaleType.FIT_XY
|
|
381
420
|
content.layoutParams = FrameLayout.LayoutParams(cardWidth.toInt(), cardHeight.toInt())
|
|
382
421
|
wrapper.addView(content)
|
|
422
|
+
wrapper.tag = "morphCardWrapper"
|
|
423
|
+
fullScreenOverlay.addView(wrapper)
|
|
383
424
|
|
|
384
|
-
decorView.addView(
|
|
385
|
-
overlayContainer =
|
|
425
|
+
decorView.addView(fullScreenOverlay)
|
|
426
|
+
overlayContainer = fullScreenOverlay
|
|
386
427
|
|
|
387
428
|
// Hide source card — overlay covers it
|
|
388
429
|
alpha = 0f
|
|
@@ -468,7 +509,9 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
|
|
|
468
509
|
Log.d(TAG, "animateExpand: pendingTarget w=${pendingTargetWidth} h=${pendingTargetHeight} br=${pendingTargetBorderRadius}")
|
|
469
510
|
|
|
470
511
|
val dur = duration.toLong()
|
|
471
|
-
|
|
512
|
+
// Find the card wrapper inside the full-screen overlay
|
|
513
|
+
val cardWrapper = wrapper.findViewWithTag<FrameLayout>("morphCardWrapper") ?: wrapper
|
|
514
|
+
val content = if (cardWrapper.childCount > 0) cardWrapper.getChildAt(0) else null
|
|
472
515
|
|
|
473
516
|
// Compute content offset for wrapper mode
|
|
474
517
|
val contentCx = if (hasWrapper && pendingContentCentered) (targetWidthPx - cardWidth) / 2f else 0f
|
|
@@ -486,13 +529,14 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
|
|
|
486
529
|
|
|
487
530
|
animator.addUpdateListener { anim ->
|
|
488
531
|
val t = anim.animatedValue as Float
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
532
|
+
|
|
533
|
+
cardWrapper.x = lerp(cardLeft, targetLeft, t)
|
|
534
|
+
cardWrapper.y = lerp(cardTop, targetTop, t)
|
|
535
|
+
val lp = cardWrapper.layoutParams
|
|
492
536
|
lp.width = lerp(cardWidth, targetWidthPx, t).toInt()
|
|
493
537
|
lp.height = lerp(cardHeight, targetHeightPx, t).toInt()
|
|
494
|
-
|
|
495
|
-
setRoundedCorners(
|
|
538
|
+
cardWrapper.layoutParams = lp
|
|
539
|
+
setRoundedCorners(cardWrapper, lerp(cardCornerRadiusPx, targetCornerRadiusPx, t))
|
|
496
540
|
|
|
497
541
|
if (content != null) {
|
|
498
542
|
if (hasWrapper) {
|
|
@@ -510,11 +554,17 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
|
|
|
510
554
|
}
|
|
511
555
|
|
|
512
556
|
// Crossfade: at 15% of animation, make target screen VISIBLE with alpha=0
|
|
513
|
-
// then fade alpha to 1 over 50% of duration
|
|
557
|
+
// then fade alpha to 1 over 50% of duration. Also remove the blocker image.
|
|
514
558
|
val targetScreen = targetScreenContainerRef?.get()
|
|
515
|
-
val
|
|
516
|
-
|
|
559
|
+
val sourceScreen2 = sourceScreenContainerRef?.get()
|
|
560
|
+
// Find the blocker image (first child of the full-screen overlay, before the card wrapper)
|
|
561
|
+
val blockerView = if (wrapper.childCount > 1) wrapper.getChildAt(0) else null
|
|
562
|
+
if (targetScreen != null && targetScreen !== sourceScreen2) {
|
|
517
563
|
mainHandler.postDelayed({
|
|
564
|
+
// Remove blocker — source screen is visible underneath
|
|
565
|
+
if (blockerView != null && blockerView.tag != "morphCardWrapper") {
|
|
566
|
+
(blockerView.parent as? ViewGroup)?.removeView(blockerView)
|
|
567
|
+
}
|
|
518
568
|
// Switch from INVISIBLE to VISIBLE but with alpha=0
|
|
519
569
|
targetScreen.alpha = 0f
|
|
520
570
|
targetScreen.visibility = View.VISIBLE
|
|
@@ -569,8 +619,9 @@ class MorphCardSourceView(context: Context) : ReactViewGroup(context) {
|
|
|
569
619
|
return
|
|
570
620
|
}
|
|
571
621
|
|
|
572
|
-
// Get the bitmap from the overlay
|
|
573
|
-
val
|
|
622
|
+
// Get the bitmap from the card wrapper inside the overlay
|
|
623
|
+
val cardWrap = overlay.findViewWithTag<FrameLayout>("morphCardWrapper") ?: overlay
|
|
624
|
+
val origImg = if (cardWrap.childCount > 0) cardWrap.getChildAt(0) as? ImageView else null
|
|
574
625
|
val bitmap = if (origImg != null) {
|
|
575
626
|
// Extract the bitmap from the drawable
|
|
576
627
|
val drawable = origImg.drawable
|
package/package.json
CHANGED