craft-native 0.0.162 → 0.0.164
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/dist/android/templates/MainActivityNative.kt.template +133 -114
- package/dist/api/mobile.d.ts +147 -2
- package/dist/cli.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/ios/src/index.d.ts +18 -0
- package/dist/ios/src/index.js +12 -1
- package/dist/ios/templates/CraftApp.swift +68 -0
- package/dist/ios/templates/CraftHealth.swift +48 -2
- package/dist/ios/templates/CraftHybrid.swift +49 -0
- package/dist/ios/templates/CraftNativeActions.swift +125 -1
- package/dist/ios/templates/CraftNativeFiles.swift +107 -0
- package/dist/ios/templates/CraftNativeScreen.swift +38 -3
- package/dist/ios/templates/CraftScheduledWorkouts.swift +524 -0
- package/dist/ios/templates/project.yml.template +1 -0
- package/dist/mobile.js +75 -0
- package/package.json +1 -1
|
@@ -88,6 +88,7 @@ import java.util.UUID
|
|
|
88
88
|
import kotlin.math.max
|
|
89
89
|
import kotlin.math.min
|
|
90
90
|
import kotlin.math.PI
|
|
91
|
+
import kotlin.math.ceil
|
|
91
92
|
import kotlin.math.roundToInt
|
|
92
93
|
import kotlin.math.roundToLong
|
|
93
94
|
import kotlin.math.sin
|
|
@@ -202,13 +203,16 @@ private class CraftNativeSvgView(context: Context) : View(context) {
|
|
|
202
203
|
props.has(name) && !props.isNull(name) -> props.optString(name)
|
|
203
204
|
else -> null
|
|
204
205
|
}
|
|
206
|
+
// Keep the cascade explicit: computed style wins over a raw prop
|
|
207
|
+
// when both provide the same SVG paint value.
|
|
205
208
|
val weight = value("fontWeight")
|
|
209
|
+
val ownOpacity = value("opacity")?.toFloatOrNull() ?: 1f
|
|
206
210
|
return copy(
|
|
207
211
|
fill = value("fill") ?: fill,
|
|
208
212
|
stroke = value("stroke") ?: stroke,
|
|
209
213
|
strokeWidth = value("strokeWidth")?.toFloatOrNull() ?: strokeWidth,
|
|
210
214
|
color = value("color") ?: color,
|
|
211
|
-
opacity =
|
|
215
|
+
opacity = ownOpacity * opacity,
|
|
212
216
|
typeface = if (weight in setOf("bold", "700")) Typeface.DEFAULT_BOLD else typeface,
|
|
213
217
|
)
|
|
214
218
|
}
|
|
@@ -393,8 +397,8 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
393
397
|
private var alignItems = "stretch"
|
|
394
398
|
private var alignContent = "flex-start"
|
|
395
399
|
private var justifyContent = "flex-start"
|
|
396
|
-
private var rowGap =
|
|
397
|
-
private var columnGap =
|
|
400
|
+
private var rowGap = 0f
|
|
401
|
+
private var columnGap = 0f
|
|
398
402
|
private var grid = false
|
|
399
403
|
private var gridColumns = 1
|
|
400
404
|
private var gridAutoRows: CraftNativeLength? = null
|
|
@@ -407,9 +411,9 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
407
411
|
alignItems = style.optString("alignItems", "stretch")
|
|
408
412
|
alignContent = style.optString("alignContent", "flex-start")
|
|
409
413
|
justifyContent = style.optString("justifyContent", "flex-start")
|
|
410
|
-
val gap =
|
|
411
|
-
rowGap =
|
|
412
|
-
columnGap =
|
|
414
|
+
val gap = style.optDouble("gap", 0.0) * density
|
|
415
|
+
rowGap = style.optDouble("rowGap", gap / density.toDouble()).toFloat() * density
|
|
416
|
+
columnGap = style.optDouble("columnGap", gap / density.toDouble()).toFloat() * density
|
|
413
417
|
grid = style.optString("display") == "grid"
|
|
414
418
|
gridColumns = craftNativeGridColumnCount(
|
|
415
419
|
if (style.has("gridTemplateColumns")) style.opt("gridTemplateColumns") else style.opt("gridColumns")
|
|
@@ -438,8 +442,8 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
438
442
|
}
|
|
439
443
|
|
|
440
444
|
private data class Entry(val view: View, val style: CraftNativeLayoutStyle, val width: Int, val height: Int)
|
|
441
|
-
private data class Line(val entries: MutableList<Entry> = mutableListOf(), var main:
|
|
442
|
-
private data class GridLayout(val rows: List<List<Entry>>, val absolute: List<Entry>, val cellWidth:
|
|
445
|
+
private data class Line(val entries: MutableList<Entry> = mutableListOf(), var main: Float = 0f, var cross: Float = 0f)
|
|
446
|
+
private data class GridLayout(val rows: List<List<Entry>>, val absolute: List<Entry>, val cellWidth: Float, val rowHeights: List<Float>)
|
|
443
447
|
|
|
444
448
|
private fun entries(width: Int, height: Int): Pair<List<Line>, List<Entry>> {
|
|
445
449
|
val availableMain = if (orientation == HORIZONTAL) max(0, width - paddingLeft - paddingRight)
|
|
@@ -487,8 +491,8 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
487
491
|
}
|
|
488
492
|
var line = Line()
|
|
489
493
|
pending.forEachIndexed { index, entry ->
|
|
490
|
-
val childMain = if (orientation == HORIZONTAL) entry.width +
|
|
491
|
-
else entry.height +
|
|
494
|
+
val childMain = if (orientation == HORIZONTAL) entry.width.toFloat() + margins[index * 2] + margins[index * 2 + 1]
|
|
495
|
+
else entry.height.toFloat() + margins[index * 2] + margins[index * 2 + 1]
|
|
492
496
|
val lp = entry.view.layoutParams as? MarginLayoutParams
|
|
493
497
|
val crossMargins = if (orientation == HORIZONTAL) (lp?.topMargin ?: 0) + (lp?.bottomMargin ?: 0)
|
|
494
498
|
else (lp?.leftMargin ?: 0) + (lp?.rightMargin ?: 0)
|
|
@@ -502,17 +506,22 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
502
506
|
}
|
|
503
507
|
line.entries += entry
|
|
504
508
|
line.main = if (line.entries.size == 1) childMain else line.main + gap + childMain
|
|
505
|
-
line.cross = max(line.cross, childCross)
|
|
509
|
+
line.cross = max(line.cross, childCross.toFloat())
|
|
506
510
|
}
|
|
507
511
|
if (line.entries.isNotEmpty()) lines += line
|
|
508
512
|
}
|
|
513
|
+
// Reconciliation reverses the child order so the main axis runs in
|
|
514
|
+
// the requested direction. With wrapping, that also reverses the
|
|
515
|
+
// line order; flexbox keeps wrap lines in cross-axis order, so restore
|
|
516
|
+
// the groups while retaining the reversed entries inside each line.
|
|
517
|
+
if (reverse && wrap && lines.size > 1) lines.reverse()
|
|
509
518
|
return lines to absolute
|
|
510
519
|
}
|
|
511
520
|
|
|
512
521
|
private fun gridLayout(width: Int, height: Int): GridLayout {
|
|
513
522
|
val availableWidth = max(0, width - paddingLeft - paddingRight)
|
|
514
523
|
val gap = columnGap
|
|
515
|
-
val cellWidth = max(
|
|
524
|
+
val cellWidth = max(0f, (availableWidth.toFloat() - max(0, gridColumns - 1) * gap) / max(1, gridColumns).toFloat())
|
|
516
525
|
val rows = mutableListOf<MutableList<Entry>>()
|
|
517
526
|
val absolute = mutableListOf<Entry>()
|
|
518
527
|
for (index in 0 until childCount) {
|
|
@@ -532,7 +541,7 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
532
541
|
absolute += Entry(child, style, modalWidth, modalHeight)
|
|
533
542
|
continue
|
|
534
543
|
}
|
|
535
|
-
val childWidth = measureChildWidth(child, style, cellWidth, horizontalMargins)
|
|
544
|
+
val childWidth = measureChildWidth(child, style, cellWidth.roundToInt(), horizontalMargins)
|
|
536
545
|
val childHeight = measureChildHeight(child, style, height - paddingTop - paddingBottom, verticalMargins)
|
|
537
546
|
val entry = Entry(child, style, childWidth, childHeight)
|
|
538
547
|
if (style.position == "absolute") absolute += entry
|
|
@@ -542,10 +551,10 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
542
551
|
}
|
|
543
552
|
}
|
|
544
553
|
val rowHeights = rows.map { row ->
|
|
545
|
-
max(gridAutoRows?.resolve(height - paddingTop - paddingBottom) ?: 0, row.maxOfOrNull { entry ->
|
|
554
|
+
max((gridAutoRows?.resolve(height - paddingTop - paddingBottom) ?: 0).toFloat(), row.maxOfOrNull { entry ->
|
|
546
555
|
val lp = entry.view.layoutParams as? MarginLayoutParams
|
|
547
|
-
entry.height + (lp?.topMargin ?: 0) + (lp?.bottomMargin ?: 0)
|
|
548
|
-
} ?:
|
|
556
|
+
(entry.height + (lp?.topMargin ?: 0) + (lp?.bottomMargin ?: 0)).toFloat()
|
|
557
|
+
} ?: 0f)
|
|
549
558
|
}
|
|
550
559
|
return GridLayout(rows, absolute, cellWidth, rowHeights)
|
|
551
560
|
}
|
|
@@ -573,9 +582,9 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
573
582
|
flowIndex += 1
|
|
574
583
|
}
|
|
575
584
|
val cellWidth = columnWidths.maxOrNull() ?: 0
|
|
576
|
-
val width = paddingLeft + paddingRight + cellWidth * columns + max(0, columns - 1) * columnGap
|
|
585
|
+
val width = paddingLeft + paddingRight + cellWidth * columns + (max(0, columns - 1) * columnGap).roundToInt()
|
|
577
586
|
val rowGapTotal = max(0, rowHeights.size - 1) * rowGap
|
|
578
|
-
val measuredHeight = paddingTop + paddingBottom + rowHeights.sum() + rowGapTotal
|
|
587
|
+
val measuredHeight = paddingTop + paddingBottom + rowHeights.sum() + rowGapTotal.roundToInt()
|
|
579
588
|
return width to measuredHeight
|
|
580
589
|
}
|
|
581
590
|
|
|
@@ -658,15 +667,15 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
658
667
|
}
|
|
659
668
|
|
|
660
669
|
/** Keep the old-runtime shim on the same bounded-flex water-fill rule as the Zig bridge. */
|
|
661
|
-
private fun fallbackFlexWidths(line: Line, available: Int, gap:
|
|
670
|
+
private fun fallbackFlexWidths(line: Line, available: Int, gap: Float): IntArray {
|
|
662
671
|
val horizontal = orientation == HORIZONTAL
|
|
663
672
|
val hypothetical = line.entries.sumOf { entry ->
|
|
664
673
|
val lp = entry.view.layoutParams as? MarginLayoutParams
|
|
665
674
|
val margins = if (horizontal) (lp?.leftMargin ?: 0) + (lp?.rightMargin ?: 0)
|
|
666
675
|
else (lp?.topMargin ?: 0) + (lp?.bottomMargin ?: 0)
|
|
667
|
-
(if (horizontal) entry.width else entry.height) + margins
|
|
668
|
-
} + max(0, line.entries.size - 1) * gap
|
|
669
|
-
val free = available - hypothetical
|
|
676
|
+
((if (horizontal) entry.width else entry.height) + margins).toDouble()
|
|
677
|
+
} + max(0, line.entries.size - 1) * gap.toDouble()
|
|
678
|
+
val free = available.toDouble() - hypothetical
|
|
670
679
|
val growTotal = line.entries.sumOf { it.style.flexGrow }
|
|
671
680
|
val shrinkTotal = line.entries.sumOf {
|
|
672
681
|
(it.style.flexShrink ?: defaultFlexShrink(it.view)) * (if (horizontal) it.width else it.height)
|
|
@@ -695,7 +704,7 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
695
704
|
}
|
|
696
705
|
}
|
|
697
706
|
if (factor <= 0) return@repeat
|
|
698
|
-
val remaining = available - fixed - activeBasis
|
|
707
|
+
val remaining = available.toDouble() - fixed - activeBasis
|
|
699
708
|
var froze = false
|
|
700
709
|
for ((index, entry) in line.entries.withIndex()) {
|
|
701
710
|
if (frozen[index]) continue
|
|
@@ -733,16 +742,16 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
733
742
|
return
|
|
734
743
|
}
|
|
735
744
|
val layout = gridLayout(width, height)
|
|
736
|
-
val desiredWidth = paddingLeft + paddingRight + layout.cellWidth * gridColumns + max(0, gridColumns - 1) * columnGap
|
|
737
|
-
val desiredHeight = paddingTop + paddingBottom + layout.rowHeights.sum() + max(0, layout.rowHeights.size - 1) * rowGap
|
|
745
|
+
val desiredWidth = paddingLeft + paddingRight + (layout.cellWidth * gridColumns + max(0, gridColumns - 1) * columnGap).roundToInt()
|
|
746
|
+
val desiredHeight = paddingTop + paddingBottom + layout.rowHeights.sum().roundToInt() + (max(0, layout.rowHeights.size - 1) * rowGap).roundToInt()
|
|
738
747
|
setMeasuredDimension(resolveSize(desiredWidth, widthMeasureSpec), resolveSize(desiredHeight, heightMeasureSpec))
|
|
739
748
|
return
|
|
740
749
|
}
|
|
741
750
|
val (lines, absolute) = entries(width, height)
|
|
742
|
-
val main = lines.maxOfOrNull { it.main } ?:
|
|
743
|
-
val cross = lines.sumOf { it.cross } + max(0, lines.size - 1) * (if (orientation == HORIZONTAL) rowGap else columnGap)
|
|
744
|
-
val desiredWidth = if (orientation == HORIZONTAL) main else cross
|
|
745
|
-
val desiredHeight = if (orientation == HORIZONTAL) cross else main
|
|
751
|
+
val main = lines.maxOfOrNull { it.main } ?: 0f
|
|
752
|
+
val cross = lines.sumOf { it.cross.toDouble() } + max(0, lines.size - 1) * (if (orientation == HORIZONTAL) rowGap else columnGap).toDouble()
|
|
753
|
+
val desiredWidth = if (orientation == HORIZONTAL) main.roundToInt() else cross.roundToInt()
|
|
754
|
+
val desiredHeight = if (orientation == HORIZONTAL) cross.roundToInt() else main.roundToInt()
|
|
746
755
|
val absWidth = absolute.maxOfOrNull { it.width } ?: 0
|
|
747
756
|
val absHeight = absolute.maxOfOrNull { it.height } ?: 0
|
|
748
757
|
setMeasuredDimension(
|
|
@@ -760,12 +769,12 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
760
769
|
// Older runtimes return null for the optional symbol; the local
|
|
761
770
|
// layout below remains the compatibility path in that case.
|
|
762
771
|
val sharedFrames = CraftNative.grid(
|
|
763
|
-
contentWidth.toFloat(), contentHeight.toFloat(), gridColumns, columnGap
|
|
772
|
+
contentWidth.toFloat(), contentHeight.toFloat(), gridColumns, columnGap, rowGap,
|
|
764
773
|
flow.map { it.width.toFloat() }.toFloatArray(), flow.map { it.height.toFloat() }.toFloatArray(),
|
|
765
|
-
flow.map { it.style.width?.resolve(layout.cellWidth)?.toFloat() ?: Float.NaN }.toFloatArray(),
|
|
774
|
+
flow.map { it.style.width?.resolve(layout.cellWidth.roundToInt())?.toFloat() ?: Float.NaN }.toFloatArray(),
|
|
766
775
|
flow.map { it.style.height?.resolve(null)?.toFloat() ?: Float.NaN }.toFloatArray(),
|
|
767
|
-
flow.map { it.style.minWidth?.resolve(layout.cellWidth)?.toFloat() ?: Float.NaN }.toFloatArray(),
|
|
768
|
-
flow.map { it.style.maxWidth?.resolve(layout.cellWidth)?.toFloat() ?: Float.NaN }.toFloatArray(),
|
|
776
|
+
flow.map { it.style.minWidth?.resolve(layout.cellWidth.roundToInt())?.toFloat() ?: Float.NaN }.toFloatArray(),
|
|
777
|
+
flow.map { it.style.maxWidth?.resolve(layout.cellWidth.roundToInt())?.toFloat() ?: Float.NaN }.toFloatArray(),
|
|
769
778
|
flow.map { it.style.minHeight?.resolve(null)?.toFloat() ?: Float.NaN }.toFloatArray(),
|
|
770
779
|
flow.map { it.style.maxHeight?.resolve(null)?.toFloat() ?: Float.NaN }.toFloatArray(),
|
|
771
780
|
flow.flatMap {
|
|
@@ -790,29 +799,29 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
790
799
|
}
|
|
791
800
|
} else {
|
|
792
801
|
val totalRows = layout.rowHeights.sum()
|
|
793
|
-
val rowGaps = max(0, layout.rowHeights.size - 1) * rowGap
|
|
794
|
-
val freeRows = max(
|
|
802
|
+
val rowGaps = max(0, layout.rowHeights.size - 1) * rowGap.toFloat()
|
|
803
|
+
val freeRows = max(0f, contentHeight.toFloat() - totalRows - rowGaps)
|
|
795
804
|
val rowCount = max(1, layout.rowHeights.size)
|
|
796
|
-
var rowLeading =
|
|
797
|
-
var rowBetween = rowGap
|
|
798
|
-
var rowExtra =
|
|
805
|
+
var rowLeading = 0f
|
|
806
|
+
var rowBetween = rowGap.toFloat()
|
|
807
|
+
var rowExtra = 0f
|
|
799
808
|
when (alignContentCode()) {
|
|
800
|
-
1 -> rowLeading = freeRows /
|
|
809
|
+
1 -> rowLeading = freeRows / 2f
|
|
801
810
|
2 -> rowLeading = freeRows
|
|
802
|
-
3 -> if (rowCount > 1) rowBetween += freeRows / (rowCount - 1)
|
|
811
|
+
3 -> if (rowCount > 1) rowBetween += freeRows / (rowCount - 1).toFloat()
|
|
803
812
|
4 -> {
|
|
804
|
-
rowLeading = freeRows / (rowCount * 2)
|
|
805
|
-
rowBetween += freeRows / rowCount
|
|
813
|
+
rowLeading = freeRows / (rowCount * 2).toFloat()
|
|
814
|
+
rowBetween += freeRows / rowCount.toFloat()
|
|
806
815
|
}
|
|
807
816
|
6 -> {
|
|
808
|
-
rowLeading = freeRows / (rowCount + 1)
|
|
809
|
-
rowBetween += freeRows / (rowCount + 1)
|
|
817
|
+
rowLeading = freeRows / (rowCount + 1).toFloat()
|
|
818
|
+
rowBetween += freeRows / (rowCount + 1).toFloat()
|
|
810
819
|
}
|
|
811
|
-
5 -> rowExtra = freeRows / rowCount
|
|
820
|
+
5 -> rowExtra = freeRows / rowCount.toFloat()
|
|
812
821
|
}
|
|
813
|
-
var rowTop = paddingTop + rowLeading
|
|
822
|
+
var rowTop = paddingTop.toFloat() + rowLeading
|
|
814
823
|
for ((rowIndex, row) in layout.rows.withIndex()) {
|
|
815
|
-
val rowHeight = layout.rowHeights[rowIndex] + rowExtra
|
|
824
|
+
val rowHeight = layout.rowHeights[rowIndex].toFloat() + rowExtra
|
|
816
825
|
for ((column, entry) in row.withIndex()) {
|
|
817
826
|
val align = entry.style.alignSelf ?: alignItems
|
|
818
827
|
val lp = entry.view.layoutParams as? MarginLayoutParams
|
|
@@ -820,20 +829,20 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
820
829
|
val marginRight = lp?.rightMargin ?: 0
|
|
821
830
|
val marginTop = lp?.topMargin ?: 0
|
|
822
831
|
val marginBottom = lp?.bottomMargin ?: 0
|
|
823
|
-
val availableWidth = max(
|
|
824
|
-
val availableHeight = max(0, rowHeight - marginTop - marginBottom)
|
|
825
|
-
val childWidth = if (align == "stretch" && entry.style.width == null) availableWidth else min(availableWidth, entry.width)
|
|
832
|
+
val availableWidth = max(0f, layout.cellWidth - marginLeft - marginRight)
|
|
833
|
+
val availableHeight = max(0, (rowHeight - marginTop - marginBottom).roundToInt())
|
|
834
|
+
val childWidth = if (align == "stretch" && entry.style.width == null) availableWidth.roundToInt() else min(availableWidth.roundToInt(), entry.width)
|
|
826
835
|
val childHeight = if (align == "stretch" && entry.style.height == null) availableHeight else min(availableHeight, entry.height)
|
|
827
|
-
val x = paddingLeft + column * (layout.cellWidth + columnGap) + marginLeft + when (align) {
|
|
828
|
-
"center" -> (availableWidth - childWidth) /
|
|
836
|
+
val x = (paddingLeft + column * (layout.cellWidth + columnGap) + marginLeft + when (align) {
|
|
837
|
+
"center" -> (availableWidth - childWidth) / 2f
|
|
829
838
|
"flex-end" -> availableWidth - childWidth
|
|
830
|
-
else ->
|
|
831
|
-
}
|
|
832
|
-
val y = rowTop + marginTop + when (align) {
|
|
839
|
+
else -> 0f
|
|
840
|
+
}).roundToInt()
|
|
841
|
+
val y = (rowTop + marginTop + when (align) {
|
|
833
842
|
"center" -> (availableHeight - childHeight) / 2
|
|
834
843
|
"flex-end" -> availableHeight - childHeight
|
|
835
844
|
else -> 0
|
|
836
|
-
}
|
|
845
|
+
}).roundToInt()
|
|
837
846
|
entry.view.layout(x, y, x + childWidth, y + childHeight)
|
|
838
847
|
}
|
|
839
848
|
rowTop += rowHeight + rowBetween
|
|
@@ -857,42 +866,42 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
857
866
|
val crossGap = if (orientation == HORIZONTAL) rowGap else columnGap
|
|
858
867
|
val availableMain = if (orientation == HORIZONTAL) contentWidth else contentHeight
|
|
859
868
|
val availableCross = if (orientation == HORIZONTAL) contentHeight else contentWidth
|
|
860
|
-
val totalCross = lines.sumOf { it.cross } + max(0, lines.size - 1) * crossGap
|
|
861
|
-
val crossFree = max(
|
|
862
|
-
var crossLeading =
|
|
869
|
+
val totalCross = lines.sumOf { it.cross.toDouble() }.toFloat() + max(0, lines.size - 1) * crossGap
|
|
870
|
+
val crossFree = max(0f, availableCross.toFloat() - totalCross)
|
|
871
|
+
var crossLeading = 0f
|
|
863
872
|
var crossBetween = crossGap
|
|
864
873
|
val sharedCross = if (wrap && lines.size > 1) {
|
|
865
874
|
CraftNative.flexLineDistribution(
|
|
866
|
-
availableCross.toFloat(), crossGap
|
|
875
|
+
availableCross.toFloat(), crossGap, alignContentCode(), lines.map { it.cross }.toFloatArray()
|
|
867
876
|
)
|
|
868
877
|
} else null
|
|
869
|
-
sharedCross?.second?.forEachIndexed { index, size -> lines[index].cross = size
|
|
878
|
+
sharedCross?.second?.forEachIndexed { index, size -> lines[index].cross = size }
|
|
870
879
|
if (wrap && lines.size > 1) {
|
|
871
880
|
if (sharedCross == null) when (alignContent) {
|
|
872
|
-
"center" -> crossLeading = crossFree /
|
|
881
|
+
"center" -> crossLeading = crossFree / 2f
|
|
873
882
|
"flex-end" -> crossLeading = crossFree
|
|
874
|
-
"space-between" -> crossBetween = crossFree / (lines.size - 1) + crossGap
|
|
883
|
+
"space-between" -> crossBetween = crossFree / (lines.size - 1).toFloat() + crossGap
|
|
875
884
|
"space-around" -> {
|
|
876
|
-
crossBetween = crossFree / lines.size + crossGap
|
|
877
|
-
crossLeading = crossFree / (lines.size * 2)
|
|
885
|
+
crossBetween = crossFree / lines.size.toFloat() + crossGap
|
|
886
|
+
crossLeading = crossFree / (lines.size * 2).toFloat()
|
|
878
887
|
}
|
|
879
888
|
"space-evenly" -> {
|
|
880
|
-
crossBetween = crossFree / (lines.size + 1) + crossGap
|
|
881
|
-
crossLeading = crossFree / (lines.size + 1)
|
|
882
|
-
}
|
|
883
|
-
"stretch" -> {
|
|
884
|
-
val extra = crossFree / lines.size
|
|
885
|
-
lines.forEach { it.cross += extra }
|
|
889
|
+
crossBetween = crossFree / (lines.size + 1).toFloat() + crossGap
|
|
890
|
+
crossLeading = crossFree / (lines.size + 1).toFloat()
|
|
886
891
|
}
|
|
887
892
|
}
|
|
888
893
|
}
|
|
889
|
-
|
|
894
|
+
val stretchExtra = if (sharedCross == null && wrap && lines.size > 1 && alignContent == "stretch")
|
|
895
|
+
crossFree / lines.size.toFloat()
|
|
896
|
+
else 0f
|
|
897
|
+
var crossOffset = (if (orientation == HORIZONTAL) paddingTop else paddingLeft).toFloat() + crossLeading
|
|
890
898
|
for ((lineIndex, line) in lines.withIndex()) {
|
|
891
|
-
val
|
|
899
|
+
val lineCross = line.cross.toFloat() + stretchExtra
|
|
900
|
+
val lineOffset = sharedCross?.first?.get(lineIndex)?.let { (if (orientation == HORIZONTAL) paddingTop else paddingLeft).toFloat() + it } ?: crossOffset
|
|
892
901
|
val fallbackWidths = fallbackFlexWidths(line, availableMain, gap)
|
|
893
902
|
val sharedPrimary = CraftNative.flexRow(
|
|
894
903
|
availableMain.toFloat(),
|
|
895
|
-
gap
|
|
904
|
+
gap,
|
|
896
905
|
justifyCode(),
|
|
897
906
|
line.entries.map { entry -> if (orientation == HORIZONTAL) entry.width.toFloat() else entry.height.toFloat() }.toFloatArray(),
|
|
898
907
|
line.entries.map { it.style.flexGrow.toFloat() }.toFloatArray(),
|
|
@@ -917,8 +926,8 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
917
926
|
val lp = line.entries[index].view.layoutParams as? MarginLayoutParams
|
|
918
927
|
val margins = if (orientation == HORIZONTAL) (lp?.leftMargin ?: 0) + (lp?.rightMargin ?: 0)
|
|
919
928
|
else (lp?.topMargin ?: 0) + (lp?.bottomMargin ?: 0)
|
|
920
|
-
sharedPrimary[index].
|
|
921
|
-
} + max(0, line.entries.size - 1) * gap
|
|
929
|
+
sharedPrimary[index].toDouble() + margins
|
|
930
|
+
} + max(0, line.entries.size - 1) * gap.toDouble()
|
|
922
931
|
} else {
|
|
923
932
|
line.entries.indices.sumOf { index ->
|
|
924
933
|
val constrained = fallbackWidths[index]
|
|
@@ -926,49 +935,50 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
926
935
|
val margins = if (orientation == HORIZONTAL) (lp?.leftMargin ?: 0) + (lp?.rightMargin ?: 0)
|
|
927
936
|
else (lp?.topMargin ?: 0) + (lp?.bottomMargin ?: 0)
|
|
928
937
|
constrained + margins
|
|
929
|
-
} + max(0, line.entries.size - 1) * gap
|
|
938
|
+
}.toDouble() + max(0, line.entries.size - 1) * gap.toDouble()
|
|
930
939
|
}
|
|
931
|
-
val free = max(
|
|
940
|
+
val free = max(0f, availableMain.toFloat() - distributedMain.toFloat())
|
|
932
941
|
val (leading, between) = distribution(free, line.entries.size)
|
|
933
|
-
var mainOffset = if (orientation == HORIZONTAL) paddingLeft else paddingTop
|
|
934
|
-
mainOffset += leading
|
|
942
|
+
var mainOffset = (if (orientation == HORIZONTAL) paddingLeft else paddingTop).toFloat() + leading
|
|
935
943
|
for ((index, entry) in line.entries.withIndex()) {
|
|
936
944
|
val lp = entry.view.layoutParams as? MarginLayoutParams
|
|
937
945
|
val marginStart = if (orientation == HORIZONTAL) lp?.leftMargin ?: 0 else lp?.topMargin ?: 0
|
|
938
946
|
val marginEnd = if (orientation == HORIZONTAL) lp?.rightMargin ?: 0 else lp?.bottomMargin ?: 0
|
|
939
947
|
val crossSize = if ((entry.style.alignSelf ?: alignItems) == "stretch" && (if (orientation == HORIZONTAL) entry.style.height else entry.style.width) == null)
|
|
940
|
-
max(0,
|
|
948
|
+
max(0, (lineCross - (if (orientation == HORIZONTAL) (lp?.topMargin ?: 0) + (lp?.bottomMargin ?: 0) else (lp?.leftMargin ?: 0) + (lp?.rightMargin ?: 0))).roundToInt())
|
|
941
949
|
else if (orientation == HORIZONTAL) entry.height else entry.width
|
|
942
950
|
val align = entry.style.alignSelf ?: alignItems
|
|
943
|
-
val crossLeading = if (orientation == HORIZONTAL) lp?.topMargin ?: 0 else lp?.leftMargin ?: 0
|
|
944
|
-
val crossTrailing = if (orientation == HORIZONTAL) lp?.bottomMargin ?: 0 else lp?.rightMargin ?: 0
|
|
951
|
+
val crossLeading = (if (orientation == HORIZONTAL) lp?.topMargin ?: 0 else lp?.leftMargin ?: 0).toFloat()
|
|
952
|
+
val crossTrailing = (if (orientation == HORIZONTAL) lp?.bottomMargin ?: 0 else lp?.rightMargin ?: 0).toFloat()
|
|
945
953
|
val alignment = when (align) {
|
|
946
954
|
"center" -> 1
|
|
947
955
|
"flex-end" -> 2
|
|
948
956
|
else -> 0
|
|
949
957
|
}
|
|
950
958
|
val crossPosition = CraftNative.crossAxisPosition(
|
|
951
|
-
|
|
952
|
-
)
|
|
953
|
-
1 -> crossLeading + (
|
|
954
|
-
2 ->
|
|
959
|
+
lineCross, crossSize.toFloat(), crossLeading, crossTrailing, alignment
|
|
960
|
+
) ?: when (alignment) {
|
|
961
|
+
1 -> crossLeading + (lineCross - crossLeading - crossTrailing - crossSize) / 2f
|
|
962
|
+
2 -> lineCross - crossTrailing - crossSize
|
|
955
963
|
else -> crossLeading
|
|
956
964
|
}
|
|
957
965
|
// Shared positions cover every non-reverse justification; the
|
|
958
966
|
// local main-axis rule remains the fallback for old runtimes
|
|
959
967
|
// that return widths only.
|
|
960
|
-
|
|
961
|
-
|
|
968
|
+
// The shared result stores widths in the first half and
|
|
969
|
+
// main-axis positions in the second half.
|
|
970
|
+
val sharedPosition = if (!reverse) sharedPositions?.get(line.entries.size + index) else null
|
|
971
|
+
val positionedMain = sharedPosition?.let { (if (orientation == HORIZONTAL) paddingLeft else paddingTop).toFloat() + it }
|
|
962
972
|
?: mainOffset + marginStart
|
|
963
|
-
val x = if (orientation == HORIZONTAL) positionedMain else lineOffset + crossPosition
|
|
964
|
-
val y = if (orientation == HORIZONTAL) lineOffset + crossPosition else positionedMain
|
|
973
|
+
val x = if (orientation == HORIZONTAL) positionedMain.roundToInt() else (lineOffset + crossPosition).roundToInt()
|
|
974
|
+
val y = if (orientation == HORIZONTAL) (lineOffset + crossPosition).roundToInt() else positionedMain.roundToInt()
|
|
965
975
|
val distributedPrimary = sharedPrimary?.get(index)?.roundToInt() ?: fallbackWidths[index]
|
|
966
976
|
val w = if (orientation == HORIZONTAL) distributedPrimary else crossSize
|
|
967
977
|
val h = if (orientation == HORIZONTAL) crossSize else distributedPrimary
|
|
968
978
|
entry.view.layout(x, y, x + w, y + h)
|
|
969
979
|
if (sharedPosition == null) mainOffset += distributedPrimary + marginStart + marginEnd + gap + between
|
|
970
980
|
}
|
|
971
|
-
if (sharedCross == null) crossOffset +=
|
|
981
|
+
if (sharedCross == null) crossOffset += lineCross + crossBetween
|
|
972
982
|
}
|
|
973
983
|
for (entry in absolute) {
|
|
974
984
|
if (entry.view is CraftNativeModalView && entry.view.visibility == View.VISIBLE) entry.view.bringToFront()
|
|
@@ -981,13 +991,16 @@ private class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
|
|
|
981
991
|
onLayoutChanged?.invoke()
|
|
982
992
|
}
|
|
983
993
|
|
|
984
|
-
private fun distribution(free:
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
994
|
+
private fun distribution(free: Float, count: Int): Pair<Float, Float> {
|
|
995
|
+
val available = free
|
|
996
|
+
return when (justifyContent) {
|
|
997
|
+
"center" -> available / 2f to 0f
|
|
998
|
+
"flex-end" -> available to 0f
|
|
999
|
+
"space-between" -> 0f to if (count > 1) available / (count - 1).toFloat() else 0f
|
|
1000
|
+
"space-around" -> available / (count * 2).toFloat() to available / count.toFloat()
|
|
1001
|
+
"space-evenly" -> available / (count + 1).toFloat() to available / (count + 1).toFloat()
|
|
1002
|
+
else -> 0f to 0f
|
|
1003
|
+
}
|
|
991
1004
|
}
|
|
992
1005
|
}
|
|
993
1006
|
|
|
@@ -2721,12 +2734,24 @@ class MainActivity : AppCompatActivity() {
|
|
|
2721
2734
|
val minimum = props.optDouble("minimumValue", 0.0)
|
|
2722
2735
|
val maximumCandidate = props.optDouble("maximumValue", 1.0)
|
|
2723
2736
|
val maximum = if (maximumCandidate > minimum) maximumCandidate else minimum + Double.MIN_VALUE
|
|
2724
|
-
max = 1000
|
|
2725
2737
|
setOnSeekBarChangeListener(null)
|
|
2726
2738
|
val step = props.optDouble("step", 0.0).takeIf { it > 0 }
|
|
2739
|
+
// A stepped slider needs one native position per authored
|
|
2740
|
+
// step; a fixed 1,000-position SeekBar silently made large
|
|
2741
|
+
// ranges unable to represent most valid values. Continuous
|
|
2742
|
+
// sliders retain the bounded scale to avoid an enormous max.
|
|
2743
|
+
val progressMax = step?.let {
|
|
2744
|
+
ceil((maximum - minimum) / it).toInt().coerceIn(1, 1_000_000)
|
|
2745
|
+
} ?: 1000
|
|
2746
|
+
max = progressMax
|
|
2727
2747
|
val requested = props.optDouble("value", minimum)
|
|
2728
|
-
val value = if (step != null) minimum + ((requested - minimum) / step).roundToInt() * step else requested
|
|
2729
|
-
|
|
2748
|
+
val value = (if (step != null) minimum + ((requested - minimum) / step).roundToInt() * step else requested)
|
|
2749
|
+
.coerceIn(minimum, maximum)
|
|
2750
|
+
progress = if (step != null) {
|
|
2751
|
+
((value - minimum) / step).roundToInt().coerceIn(0, max)
|
|
2752
|
+
} else {
|
|
2753
|
+
(((value - minimum) / (maximum - minimum)) * max).roundToInt().coerceIn(0, max)
|
|
2754
|
+
}
|
|
2730
2755
|
if (step != null) screen.sliderSteps[this] = step else screen.sliderSteps.remove(this)
|
|
2731
2756
|
progressTintList = props.optString("minimumTrackTintColor").takeIf { it.isNotBlank() }
|
|
2732
2757
|
?.let { ColorStateList.valueOf(color(it, Color.WHITE)) }
|
|
@@ -2742,25 +2767,19 @@ class MainActivity : AppCompatActivity() {
|
|
|
2742
2767
|
setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
|
2743
2768
|
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
|
2744
2769
|
val current = screen.handlers[seekBar] ?: return
|
|
2745
|
-
val raw = minimum + (maximum - minimum) * progress.toDouble() / max.toDouble()
|
|
2746
2770
|
val step = screen.sliderSteps[seekBar]
|
|
2747
|
-
val value = if (step != null) minimum +
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
.roundToInt().coerceIn(0, max)
|
|
2751
|
-
if (seekBar.progress != snappedProgress) {
|
|
2752
|
-
seekBar.progress = snappedProgress
|
|
2753
|
-
return
|
|
2754
|
-
}
|
|
2755
|
-
}
|
|
2771
|
+
val value = (if (step != null) minimum + progress * step else
|
|
2772
|
+
minimum + (maximum - minimum) * progress.toDouble() / max.toDouble())
|
|
2773
|
+
.coerceIn(minimum, maximum)
|
|
2756
2774
|
send(screen, "EVENT", JSONObject().put("handlerName", current).put("nativeEvent", JSONObject().put("value", value)))
|
|
2757
2775
|
}
|
|
2758
2776
|
override fun onStartTrackingTouch(seekBar: SeekBar) {}
|
|
2759
2777
|
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
|
2760
2778
|
val current = screen.sliderCompleteHandlers[seekBar] ?: return
|
|
2761
|
-
val raw = minimum + (maximum - minimum) * seekBar.progress.toDouble() / max.toDouble()
|
|
2762
2779
|
val step = screen.sliderSteps[seekBar]
|
|
2763
|
-
val value = if (step != null) minimum +
|
|
2780
|
+
val value = (if (step != null) minimum + seekBar.progress * step else
|
|
2781
|
+
minimum + (maximum - minimum) * seekBar.progress.toDouble() / max.toDouble())
|
|
2782
|
+
.coerceIn(minimum, maximum)
|
|
2764
2783
|
send(screen, "EVENT", JSONObject().put("handlerName", current).put("nativeEvent", JSONObject().put("value", value)))
|
|
2765
2784
|
}
|
|
2766
2785
|
})
|