diff --git a/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/UiDelegate.java b/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/UiDelegate.java new file mode 100644 index 000000000..a655f174b --- /dev/null +++ b/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/UiDelegate.java @@ -0,0 +1,13 @@ +package androidx.constraintlayout.extension.util; + +public interface UiDelegate { + public boolean post(Runnable runnable); + + public boolean postDelayed(Runnable runnable, long delayMillis); + + public void invalidate(); + + public int getWidth(); + + public int getHeight(); +} diff --git a/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/Vp.java b/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/Vp.java new file mode 100644 index 000000000..9b8213f9b --- /dev/null +++ b/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/Vp.java @@ -0,0 +1,328 @@ +package androidx.constraintlayout.extension.util; + +import java.util.HashMap; + +public class Vp { + static HashMap channels = new HashMap<>(); + + static class MSChannel { + int mSize = 32000; + String mName; + int mLast = 0; + int mWritten = 0; + long[] mTime = new long[mSize]; + + private MSChannel() { + + } + + private MSChannel(int size) { + mSize = size; + mTime = new long[mSize]; + } + + int getLatest() { + if (mWritten == 0) { + return -1; + } + return (mLast == 0 ? mSize : mLast) - 1; + } + + long getPos() { + int written; + int last; + synchronized (this) { + written = mWritten; + last = mLast; + } + return ((long) written) << 32 | last; + } + + void increment() { + synchronized (this) { + mLast++; + if (mLast == mSize) { + mLast = 0; + } + mWritten++; + } + } + + synchronized int getLast() { + return mLast; + } + } + + // ======================== Support for float ============================== + static class MSChannelFloat extends MSChannel { + float[] mData = new float[mSize]; + + MSChannelFloat(String name) { + this.mName = name; + } + + MSChannelFloat(String name, int size) { + super(size); + this.mName = name; + mData = new float[size]; + } + + void add(long time, float value) { + int last = getLast(); + mTime[last] = time; + mData[last] = value; + increment(); + } + + + public int get(long start, long[] time, float[] value) { + int count = 0; + + int written; + int last, first; + long firstTime; + long lastTime; + synchronized (this) { + written = mWritten; + last = mLast; + + if (written > mSize) { + firstTime = mTime[(last + 1) % mSize]; + } else { + firstTime = mTime[last - written]; + } + int lt = last - 1; + lastTime = mTime[lt >= 0 ? lt : lt + mSize]; + } + int startIndex = -1; + if (mWritten > mSize && mLast != mSize - 1) { // it has wrapped + if (mTime[mSize - 1] > start) { + startIndex = search(mTime, last, mSize - 1, start); + } else { + startIndex = search(mTime, 0, last, start); + } + } else { + startIndex = search(mTime, 0, last, start); + } + return getIndex(startIndex, time, value); + } + + static int search(long arr[], int low, int high, long key) { + int pos = -1; + while (low <= high) { + pos = low + (high - low) / 2; + if (arr[pos] == key) { + return pos; + } + + if (arr[pos] < key) { + low = pos + 1; + } else { + high = pos - 1; + } + } + return pos; + } + + public void findIndex(long[] time, int start, int end, int key) { + + } + + + public int getIndex(int startIndex, long[] time, float[] value) { + int len = time.length; + if (len + startIndex < mSize) { + System.arraycopy(mTime, startIndex, time, 0, len); + System.arraycopy(mData, startIndex, value, 0, len); + return (len + startIndex > mLast) ? mLast - startIndex : len; + } else { + int block1len = mSize - startIndex; + System.arraycopy(mTime, startIndex, time, 0, block1len); + System.arraycopy(mData, startIndex, value, 0, block1len); + int copyLen = (mLast > len - block1len) ? len - block1len : mLast; + System.arraycopy(mTime, 0, time, block1len, copyLen); + System.arraycopy(mData, 0, value, block1len, copyLen); + return block1len + copyLen; + } + + } + + int getLatest(long[] time, float[] value) { + int written; + int last; + synchronized (this) { + written = mWritten; + last = mLast; + } + int maxLen = time.length; + if (written == 0) return -1; + if (maxLen > written) { + maxLen = (int) mWritten; + } + if (maxLen > mSize) { + maxLen = mSize; + } + if (last - maxLen < 0) { // copy [0....last, size-(maxLen-last)...size-1] + int copy1src = 0; + int copy1Dest = maxLen - last; + int copy1len = last; + + System.arraycopy(mTime, copy1src, time, copy1Dest, copy1len); + System.arraycopy(mData, copy1src, value, copy1Dest, copy1len); + int copy2src = mSize - (maxLen - last); + int copy2Dest = 0; + int copy2len = maxLen - last; + + System.arraycopy(mTime, copy2src, time, copy2Dest, copy2len); + System.arraycopy(mData, copy2src, value, copy2Dest, copy2len); + } else { + int copy1src = last - maxLen; + int copy1Dest = 0; + int copy1len = maxLen; + System.arraycopy(mTime, copy1src, time, copy1Dest, copy1len); + System.arraycopy(mData, copy1src, value, copy1Dest, copy1len); + } + + return maxLen; + } + } + + public static void initChannel(String channel, int size) { + channels.put(channel, new MSChannelFloat(channel, size)); + } + + + public static void send(String channel, float value) { + send(channel, System.nanoTime(), value); + } + + public static void send(String channel, long time, float value) { + MSChannelFloat c = (MSChannelFloat) channels.get(channel); + if (c == null) { + c = new MSChannelFloat(channel); + channels.put(channel, c); + } + c.add(time, value); + } + + public static int getLatest(String channel, long[] times, float[] values) { + MSChannelFloat c = (MSChannelFloat) channels.get(channel); + if (c == null) { + return -1; + } + return c.getLatest(times, values); + } + + public static int totalWritten(String channel) { + MSChannelFloat c = (MSChannelFloat) channels.get(channel); + if (c == null) { + return -1; + } + return c.mWritten; + } + + public static int getAfter(String channel, long time, long[] times, float[] values) { + MSChannelFloat c = (MSChannelFloat) channels.get(channel); + if (c == null) { + return -1; + } + return c.get(time, times, values); + } + + public static void sinWaveGen(String channel) { + System.out.println("================ sinWaveGen ================="); + Thread t = new Thread() { + @Override + public void run() { + + long[] time = new long[100]; + float[] value = new float[100]; + for (int i = 0; i < 100000000; i++) { + long nt = System.nanoTime(); + float v = (float) (Math.sin(nt * 1E-9 * Math.PI) * Math.sin( + nt * 1E-9 * Math.PI / 40)); + Vp.send(channel, nt, v); + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }; + t.setDaemon(false); + t.start(); + } + + private static final HashMap last_fps_time = new HashMap<>(); + + public static void fps(String channel) { + long[] ans = last_fps_time.get(channel); + if (ans == null) { + ans = new long[1]; + last_fps_time.put(channel, ans); + ans[0] = System.nanoTime(); + } + long now = System.nanoTime(); + float duration = (now - ans[0]) * 1E-9f; + + if (duration < 1 / 500f) { + send(channel, now, 0); + } else { + send(channel, now, 1 / duration); + } + ans[0] = now; + + } + + // ======================= END Support for Floats================================== + + public static void main(String[] args) throws InterruptedException { + long last = System.nanoTime(); + Thread t = new Thread() { + @Override + public void run() { + + long[] time = new long[100]; + float[] value = new float[100]; + for (int i = 0; i < 100000000; i++) { + int len = getLatest("bob", time, value); + if (len == -1) { + System.out.println("skip"); + try { + Thread.sleep(0, 100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + continue; + } + long current = System.nanoTime(); + System.out.println(" " + len + " " + + (current - time[len - 1]) * 1E-6f + "ms " + value[len - 1]); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }; + t.setDaemon(false); + t.start(); + int sample = 10000000; + for (long i = 0; i < 100000000000L; i++) { + send("bob", i); + // Thread.sleep(0,100); + if (i % sample == 0) { + long now = System.nanoTime(); + + System.out.println(i + " per sec =" + sample / ((now - last) * 1E-9)); + last = now; + } + + } + + } +} diff --git a/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/VpGraphCompose.kt b/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/VpGraphCompose.kt new file mode 100644 index 000000000..054a17c2f --- /dev/null +++ b/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/VpGraphCompose.kt @@ -0,0 +1,106 @@ +package androidx.constraintlayout.extension.util + +import androidx.compose.foundation.Canvas +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.neverEqualPolicy +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.graphics.nativeCanvas +import androidx.compose.ui.input.pointer.motionEventSpy +import androidx.compose.ui.layout.onPlaced +import androidx.compose.ui.node.Ref +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + + +fun vpSend(channel: String, value: Float) { + Vp.send(channel, value) +} + +fun vpSend(channel: String, time: Long, value: Float) { + Vp.send(channel, time, value) +} + +fun vpFps(channel: String) { + Vp.fps(channel); +} + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun VpGraph( + modifier: Modifier = Modifier, + vararg channels: String, +) { + val width = remember { + Ref().apply { 0 } + } + val height = remember { + Ref().apply { 0 } + } + + val invalidator = remember { mutableStateOf(Unit, neverEqualPolicy()) } + + val scope = rememberCoroutineScope() + + val uiDelegate = remember { + object : UiDelegate { + override fun post(runnable: Runnable?): Boolean { + scope.launch { + runnable?.run() + } + return true + } + + override fun postDelayed(runnable: Runnable?, delayMillis: Long): Boolean { + scope.launch { + delay(delayMillis) + runnable?.run() + } + return true + } + + override fun invalidate() { + invalidator.value = Unit + } + + override fun getWidth(): Int { + return width.value ?: 0 + } + + override fun getHeight(): Int { + return height.value ?: 0 + } + } + } + + val graphCore = remember { + VpGraphCore(uiDelegate) + } + + LaunchedEffect(channels) { + channels.forEach { + graphCore.addChannel(it) + } + } + + Canvas( + modifier = modifier + .clipToBounds() + .onPlaced { + width.value = it.size.width + height.value = it.size.height + } + .motionEventSpy { + graphCore.onTouchEvent(it) + }, + onDraw = { + invalidator.value + graphCore.onDraw(this.drawContext.canvas.nativeCanvas) + } + ) +} diff --git a/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/VpGraphCore.kt b/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/VpGraphCore.kt new file mode 100644 index 000000000..a9c556077 --- /dev/null +++ b/projects/ComposeConstraintLayout/app/src/main/java/androidx/constraintlayout/extension/util/VpGraphCore.kt @@ -0,0 +1,455 @@ +package androidx.constraintlayout.extension.util + +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Path +import android.graphics.Rect +import android.util.Log +import android.view.MotionEvent +import java.text.DecimalFormat +import kotlin.math.floor + +class VpGraphCore(private val mUiDelegate: UiDelegate) { + private var mPlots = ArrayList() + private val mTime = LongArray(MAX_BUFF) + private val mValue = FloatArray(MAX_BUFF) + var duration = 10f // seconds + var mMinY = 0f + var mMaxY = 1f + var mMinX = 0f + var mMaxX = duration + mMinX + var axisLeft = 100f + var axisTop = 100f + var axisRight = 100f + var axisBottom = 100f + var mAxisPaint = Paint() + var mLinePaint = Paint() + var mGridPaint = Paint() + var mBounds = Rect() + var start: Long = -1 // show the latest; + var mGraphSelfFps = false + var sampleDelay = 15 // ms between samples. + private var mLiveSample = true + private var mStartTime: Long = 0 + private var mLineX = Float.NaN + var debug = false + + internal class Data(var mTitle: String) { + var mX = FloatArray(MAX_BUFF) + var mY = FloatArray(MAX_BUFF) + var paint = Paint() + var path = Path() + var mLength: Int + var lastLabelYPos = Float.NaN + + init { + mLength = -1 + paint.style = Paint.Style.STROKE + } + + fun plot(canvas: Canvas, graph: VpGraphCore, w: Int, h: Int) { + path.reset() + val scaleX = graph.getScaleX(w, h) + val scaleY = graph.getScaleY(w, h) + val offX = graph.getOffsetX(w, h) + val offY = graph.getOffsetY(w, h) + var first = true + for (i in 0 until mLength) { + if ((i == mLength - 1 || mX[i + 1] >= graph.mMinX) && mX[i] <= graph.mMaxX) { + val x = mX[i] * scaleX + offX + val y = mY[i] * scaleY + offY + if (first) { + path.moveTo(x, y) + first = false + } else { + path.lineTo(x, y) + } + } + } + canvas.drawPath(path, paint) + } + + fun findClosestX(x: Float): Int { + var low = 0 + var high = mLength - 1 + var pos = -1 + while (low <= high) { + pos = low + (high - low) / 2 + if (mX[pos] == x) return pos + if (mX[pos] < x) low = pos + 1 else high = pos - 1 + } + return pos + } + } + + fun init() { + mUiDelegate.post { listenToChannels() } + mAxisPaint.textSize = 32f + mAxisPaint.strokeWidth = 3f + mAxisPaint.color = Color.BLUE + mGridPaint.textSize = 32f + mGridPaint.strokeWidth = 1f + mLinePaint.color = Color.RED + mLinePaint.strokeWidth = 3f + mLinePaint.textSize = 64f + } + + var mDownX = 0f + fun onTouchEvent(event: MotionEvent): Boolean { + val action = event.action and MotionEvent.ACTION_MASK + val count = event.pointerCount + when (action) { + MotionEvent.ACTION_MOVE -> if (count == 2) { + var drag = event.getX(0) + event.getX(1) + drag = (drag + mDownX) / 2 + mStartTime += (drag / getScaleX(mUiDelegate.width, mUiDelegate.height)).toLong() + listenToChannels() + Log.v("Main", ">>>> drag $drag") + mLineX = Float.NaN + } else { + mLineX = event.x + Log.v("Main", ">>>> ACTION_MOVE " + event.x + " ") + mUiDelegate.invalidate() + } + MotionEvent.ACTION_DOWN -> if (count == 2) { + mLiveSample = false + mDownX = event.getX(0) + event.getX(1) + Log.v("Main", "$count>>>> drag on$mDownX ") + mLineX = Float.NaN + } else { + mLineX = event.x + Log.v("Main", count.toString() + ">>>> ACTION_DOWN " + event.x) + mUiDelegate.invalidate() + } + MotionEvent.ACTION_UP -> { + Log.v("Main", ">>>> ACTION_UP " + event.x) + mLineX = Float.NaN + for (mPlot in mPlots) { + mPlot.lastLabelYPos = Float.NaN + } + mUiDelegate.invalidate() + } + MotionEvent.ACTION_POINTER_DOWN -> if (count == 2) { + mLiveSample = false + mDownX = event.getX(0) + event.getX(1) + Log.v("Main", "$count>>>> ACTION_POINTER_DOWN$mDownX $mLiveSample") + mLineX = Float.NaN + } + MotionEvent.ACTION_POINTER_UP -> { + Log.v("Main", ">>>> ACTION_POINTER_UP" + event.x) + if (event.eventTime - event.downTime < 400) { + Log.v("Main", ">>>> false") + mLiveSample = true + listenToChannels() + } + Log.v("Main", ">>>> def " + event.eventTime) + } + else -> Log.v("Main", ">>>> def " + event.eventTime) + } + return true + //return super.onTouchEvent(event); + } + + fun addChannel(str: String) { + for (plot in mPlots) { + if (plot.mTitle == str) { + return + } + } + mPlots.add(Data(str)) + } + + fun setGraphFPS(on: Boolean) { + mGraphSelfFps = on + if (on) { + mPlots.add(Data(FPS_STRING)) + // mPlots.add(new Data("read")); + } else { + var remove: Data? = null + for (i in mPlots.indices) { + if (mPlots[i].mTitle === FPS_STRING) { + remove = mPlots[i] + break + } + } + if (remove != null) { + mPlots.remove(remove) + } + } + } + + private fun listenToChannels() { + // Vp.fps("read"); + if (mLiveSample) { + listenLive() + return + } + val count = mPlots.size + var minX = Float.MAX_VALUE + var minY = Float.MAX_VALUE + var maxX = -Float.MAX_VALUE + var maxY = -Float.MAX_VALUE + for (i in 0 until count) { + val p = mPlots[i] + val channel = p.mTitle + p.mLength = Vp.getAfter(channel, mStartTime, mTime, mValue) + if (p.mLength == -1) { + continue + } + for (j in 0 until p.mLength) { + val x = (mTime[j] - mStartTime) * 1E-9f + p.mX[j] = x + minX = Math.min(x, minX) + maxX = Math.max(x, maxX) + val y = mValue[j] + minY = Math.min(y, minY) + maxY = Math.max(y, maxY) + p.mY[j] = y + } + Log.v("main", p.mTitle + " " + minX + " -> " + maxX) + } + minX = 0f + maxX = minX + duration + Log.v("main", "Total $minX -> $maxX") + updateDataRange(minX, maxX, minY, maxY) + mUiDelegate.invalidate() + } + + private fun listenLive() { + val count = mPlots.size + mStartTime = System.nanoTime() - (duration.toDouble() * 1000000000L).toLong() + var minX = Float.MAX_VALUE + var minY = Float.MAX_VALUE + var maxX = -Float.MAX_VALUE + var maxY = -Float.MAX_VALUE + for (i in 0 until count) { + val p = mPlots[i] + val channel = p.mTitle + p.mLength = Vp.getLatest(channel, mTime, mValue) + if (p.mLength == -1) { + continue + } + for (j in 0 until p.mLength) { + val x = (mTime[j] - mStartTime) * 1E-9f + p.mX[j] = x + minX = Math.min(x, minX) + maxX = Math.max(x, maxX) + val y = mValue[j] + minY = Math.min(y, minY) + maxY = Math.max(y, maxY) + p.mY[j] = y + } + } + if (minX == Float.MAX_VALUE || java.lang.Float.isNaN(minX)) { + updateDataRange(0f, 10f, -1f, 1f) + } else { + updateDataRange(minX, maxX, minY, maxY) + } + mUiDelegate.invalidate() + mUiDelegate.postDelayed({ listenToChannels() }, sampleDelay.toLong()) + } + + private fun updateDataRange(minX: Float, maxX: Float, minY: Float, maxY: Float) { + var minX = minX + minX = maxX - duration + // fast to expand slow to contract + val factor = 10f + mMaxY = if (mMaxY > maxY) (mMaxY + maxY) / 2 else (mMaxY * factor + maxY) / (factor + 1) + mMinY = if (mMinY < minY) (mMinY + minY) / 2 else (mMinY * factor + minY) / (factor + 1) + mMinX = (mMinX + minX) / 2 + mMaxX = duration + mMinX + } + + fun onDraw(canvas: Canvas) { + val w = mUiDelegate.width + val h = mUiDelegate.height + drawAxis(canvas, w, h) + drawGrid(canvas, w, h) + for (p in mPlots) { + p.plot(canvas, this, w, h) + } + if (mGraphSelfFps || debug) { + Vp.fps(FPS_STRING) + } + drawTouchLine(canvas, w, h) + } + + private fun drawGrid(canvas: Canvas, w: Int, h: Int) { + val ticksX = calcTick(w, (mMaxX - mMinX).toDouble()) + val ticksY = calcTick(h, (mMaxY - mMinY).toDouble()) + val minX = (ticksX * Math.ceil((mMinX + ticksX / 100) / ticksX)).toFloat() + val maxX = (ticksX * Math.floor(mMaxX / ticksX)).toFloat() + val scaleX = getScaleX(w, h) + val offX = getOffsetX(w, h) + var x = minX + var count = 0 + val txtPad = 4 + + while (x <= maxX) { + val xp = scaleX * x + offX + canvas.drawLine(xp, axisTop, xp, h - axisBottom, mGridPaint) + x += ticksX.toFloat() + if (floor(x) == x) { + val str = df.format(x) + mAxisPaint.getTextBounds(str, 0, str.length, mBounds) + canvas.drawText( + str, + xp - mBounds.width() / 2, + h - axisBottom + txtPad + mBounds.height(), + mGridPaint + ) + } + count++ + } + val minY = (ticksY * Math.ceil((mMinY + ticksY / 100) / ticksY)).toFloat() + val maxY = (ticksY * Math.floor(mMaxY / ticksY)).toFloat() + val offY = getOffsetY(w, h) + val scaleY = getScaleY(w, h) + var y = minY + while (y <= maxY) { + val yp = scaleY * y + offY + canvas.drawLine(axisLeft, yp, w - axisRight, yp, mGridPaint) + if (count and 1 == 1 && y + ticksY < maxY) { + val str = df.format(y) + mAxisPaint.getTextBounds(str, 0, str.length, mBounds) + canvas.drawText(str, axisLeft - mBounds.width() - txtPad * 2, yp, mGridPaint) + } + count++ + y += ticksY.toFloat() + } + } + + var df = DecimalFormat("0.0") + + init { + init() + mAxisPaint.color = Color.BLACK + } + + fun drawTouchLine(canvas: Canvas, w: Int, h: Int) { + if (java.lang.Float.isNaN(mLineX)) { + return + } + if (mLineX < axisLeft) { + mLineX = axisLeft + } else if (mLineX > w - axisRight) { + mLineX = w - axisRight + } + val dataPos = (mLineX - getOffsetX(w, h)) / getScaleX(w, h) + val yOffset = getOffsetY(w, h) + val yScale = getScaleY(w, h) + val rad = 10f + canvas.drawLine(mLineX, axisTop, mLineX, h - axisBottom, mLinePaint) + var bottom_count = 0 + var top_count = 0 + val pad = 5 + val right = mLineX < w / 2 + val no_of_plots = mPlots.size + for (i in 0 until no_of_plots) { + val plot = mPlots[i] + val index = plot.findClosestX(dataPos) + if (index == -1) continue + val value = plot.mY[index] + val y = yScale * value + yOffset + canvas.drawRoundRect(mLineX - rad, y - rad, mLineX + rad, y + rad, rad, rad, mLinePaint) + val vString = plot.mTitle + ":" + df.format(value.toDouble()) + mLinePaint.getTextBounds(vString, 0, vString.length, mBounds) + var yPos = (w / 2).toFloat() + val gap = 60 + if (y > h / 2) { + yPos = y - gap + bottom_count++ + } else { + top_count++ + yPos = y + gap + } + val xPos = if (right) mLineX + gap else mLineX - gap + val minVGap = mBounds.height().toFloat() + var force = 0f + for (j in 0 until no_of_plots) { + if (i == j) { + continue + } + val yOther = mPlots[j].lastLabelYPos + val dist = Math.abs(plot.lastLabelYPos - yOther) + if (dist < minVGap * 2) { + val dir = Math.signum(yPos - yOther) + force = (if (dir > 0) minVGap else -minVGap) + minVGap / (0.1f + dist) + } + } + if (java.lang.Float.isNaN(plot.lastLabelYPos)) { + plot.lastLabelYPos = yPos + } else { + plot.lastLabelYPos = (plot.lastLabelYPos * 49 + yPos + force) / 50 + } + canvas.drawLine(mLineX, y, xPos, plot.lastLabelYPos, mLinePaint) + canvas.drawText( + vString, + if (right) xPos else xPos - mBounds.width() - pad, + plot.lastLabelYPos, + mLinePaint + ) + } + } + + fun drawAxis(canvas: Canvas, w: Int, h: Int) { + val txtPad = 4 + canvas.drawRGB(200, 230, 255) + canvas.drawLine(axisLeft, axisTop, axisLeft, h - axisBottom, mAxisPaint) + canvas.drawLine(axisLeft, h - axisBottom, w - axisRight, h - axisBottom, mAxisPaint) + val y0 = getOffsetY(w, h) + canvas.drawLine(axisLeft, y0, w - axisRight, y0, mAxisPaint) + var str = df.format(mMaxY.toDouble()) + mAxisPaint.getTextBounds(str, 0, str.length, mBounds) + canvas.drawText(str, axisLeft - mBounds.width() - txtPad, axisTop, mAxisPaint) + str = df.format(mMinY.toDouble()) + mAxisPaint.getTextBounds(str, 0, str.length, mBounds) + canvas.drawText(str, axisLeft - mBounds.width() - txtPad, h - axisBottom, mAxisPaint) + } + + fun getScaleX(w: Int, h: Int): Float { + val rangeX = mMaxX - mMinX + val graphSpanX = w - axisLeft - axisRight + return graphSpanX / rangeX + } + + fun getScaleY(w: Int, h: Int): Float { + val rangeY = mMaxY - mMinY + val graphSpanY = h - axisTop - axisBottom + return -graphSpanY / rangeY + } + + fun getOffsetX(w: Int, h: Int): Float { + return axisLeft - mMinX * getScaleX(w, h) + } + + fun getOffsetY(w: Int, h: Int): Float { + return h - axisBottom - mMinY * getScaleY(w, h) + } + + companion object { + private const val FPS_STRING = "onDraw" + const val MAX_BUFF = 2000 + fun calcTick(scr: Int, range: Double): Double { + val aprox_x_ticks = scr / 100 + var type = 1 + var best = Math.log10(range / aprox_x_ticks) + var n = Math.log10(range / (aprox_x_ticks * 2)) + if (fraction(n) < fraction(best)) { + best = n + type = 2 + } + n = Math.log10(range / (aprox_x_ticks * 5)) + if (fraction(n) < fraction(best)) { + best = n + type = 5 + } + return type * Math.pow(10.0, Math.floor(best)) + } + + fun fraction(x: Double): Double { + return x - Math.floor(x) + } + } +} \ No newline at end of file diff --git a/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/test.kt b/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/test.kt index a8bf9f3f6..fdf68b3a0 100644 --- a/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/test.kt +++ b/projects/ComposeConstraintLayout/app/src/main/java/com/example/constraintlayout/test.kt @@ -40,13 +40,20 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Matrix import androidx.compose.ui.layout.layoutId +import androidx.compose.ui.layout.onPlaced +import androidx.compose.ui.layout.positionInParent import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.constraintlayout.compose.* +import androidx.constraintlayout.extension.util.VpGraph +import androidx.constraintlayout.extension.util.vpSend import java.util.EnumSet +import kotlin.math.PI +import kotlin.math.atan2 @Preview @Composable @@ -263,21 +270,26 @@ public fun Screen4() { modifier = Modifier .fillMaxSize() ) { - Image(modifier = Modifier.layoutId("image"), + Image( + modifier = Modifier.layoutId("image"), painter = painterResource(id = R.drawable.intercom_snooze), contentDescription = null ) - Text(modifier = Modifier.layoutId("header"), + Text( + modifier = Modifier.layoutId("header"), text = stringResource(id = R.string.welcome_header), style = MaterialTheme.typography.h5, ) - Text(modifier = Modifier.layoutId("tag1"), + Text( + modifier = Modifier.layoutId("tag1"), text = stringResource(id = R.string.welcome_tagline1) ) - Text(modifier = Modifier.layoutId("tag2"), + Text( + modifier = Modifier.layoutId("tag2"), text = stringResource(id = R.string.welcome_tagline2) ) - Text(modifier = Modifier.layoutId("tag3"), + Text( + modifier = Modifier.layoutId("tag3"), text = stringResource(id = R.string.welcome_tagline3) ) Button(modifier = Modifier.layoutId("bSignup"), @@ -285,12 +297,14 @@ public fun Screen4() { ) { Text(text = stringResource(id = R.string.sign_up)) } - Button(modifier = Modifier.layoutId("bLogin"), + Button( + modifier = Modifier.layoutId("bLogin"), onClick = {}, ) { Text(text = stringResource(id = R.string.log_in)) } - Text(modifier = Modifier.layoutId("disclaimer"), + Text( + modifier = Modifier.layoutId("disclaimer"), text = stringResource(id = R.string.trial_disclaimer), style = MaterialTheme.typography.caption, ) @@ -351,21 +365,26 @@ public fun Screen5() { modifier = Modifier .fillMaxSize() ) { - Image(modifier = Modifier.layoutId("image"), + Image( + modifier = Modifier.layoutId("image"), painter = painterResource(id = R.drawable.intercom_snooze), contentDescription = null ) - Text(modifier = Modifier.layoutId("header"), + Text( + modifier = Modifier.layoutId("header"), text = stringResource(id = R.string.welcome_header), style = MaterialTheme.typography.h5, ) - Text(modifier = Modifier.layoutId("tag1"), + Text( + modifier = Modifier.layoutId("tag1"), text = stringResource(id = R.string.welcome_tagline1) ) - Text(modifier = Modifier.layoutId("tag2"), + Text( + modifier = Modifier.layoutId("tag2"), text = stringResource(id = R.string.welcome_tagline2) ) - Text(modifier = Modifier.layoutId("tag3"), + Text( + modifier = Modifier.layoutId("tag3"), text = stringResource(id = R.string.welcome_tagline3) ) Button(modifier = Modifier.layoutId("bSignup"), @@ -373,12 +392,14 @@ public fun Screen5() { ) { Text(text = stringResource(id = R.string.sign_up)) } - Button(modifier = Modifier.layoutId("bLogin"), + Button( + modifier = Modifier.layoutId("bLogin"), onClick = {}, ) { Text(text = stringResource(id = R.string.log_in)) } - Text(modifier = Modifier.layoutId("disclaimer"), + Text( + modifier = Modifier.layoutId("disclaimer"), text = stringResource(id = R.string.trial_disclaimer), style = MaterialTheme.typography.caption, ) @@ -404,10 +425,11 @@ public fun ScreenExample() { ) { Text(text = stringResource(id = R.string.log_in)) } - Text(modifier = Modifier.constrainAs(title) { - centerVerticallyTo(parent) - start.linkTo(g1) - }, + Text( + modifier = Modifier.constrainAs(title) { + centerVerticallyTo(parent) + start.linkTo(g1) + }, text = stringResource(id = R.string.welcome_header), style = MaterialTheme.typography.h2, ) @@ -440,7 +462,8 @@ public fun ScreenExample2() { ) { Text(text = stringResource(id = R.string.log_in)) } - Text(modifier = Modifier.layoutId("title"), + Text( + modifier = Modifier.layoutId("title"), text = stringResource(id = R.string.welcome_header), style = MaterialTheme.typography.h2, ) @@ -451,7 +474,8 @@ public fun ScreenExample2() { @Composable public fun ScreenExample3() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { Header: { exportAs: 'example 3'}, g1: { type: 'vGuideline', start: 80 }, @@ -464,7 +488,8 @@ public fun ScreenExample3() { start: ['g1', 'start'] } } - """), + """ + ), modifier = Modifier.fillMaxSize() ) { Button( @@ -473,7 +498,8 @@ public fun ScreenExample3() { ) { Text(text = stringResource(id = R.string.log_in)) } - Text(modifier = Modifier.layoutId("title"), + Text( + modifier = Modifier.layoutId("title"), text = stringResource(id = R.string.welcome_header), style = MaterialTheme.typography.h2, ) @@ -484,7 +510,8 @@ public fun ScreenExample3() { @Composable public fun ScreenExample4() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { Header: { exportAs: 'example 4'}, g1: { type: 'vGuideline', percent: 0.5 }, @@ -492,7 +519,8 @@ public fun ScreenExample4() { start: ['g1', 'start'] } } - """), + """ + ), modifier = Modifier .fillMaxSize() .background(Color.White) @@ -510,7 +538,8 @@ public fun ScreenExample4() { @Composable public fun ScreenExample5() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { m1 : 100, barrier: { type: 'barrier', direction: 'end', contains: ['a','b'] }, @@ -529,7 +558,8 @@ public fun ScreenExample5() { top : ['b', 'bottom', 'm1' ] } } - """), + """ + ), modifier = Modifier .fillMaxSize() ) { @@ -558,7 +588,8 @@ public fun ScreenExample5() { @Composable public fun ScreenExample6() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { Variables: { bottom: 20 @@ -591,7 +622,8 @@ public fun ScreenExample6() { top: ['b', 'bottom'] } } - """), + """ + ), modifier = Modifier .fillMaxSize() ) { @@ -643,7 +675,7 @@ public fun ScreenExample7() { animationSpec = tween(2000) ) Column { - MotionLayout( + MotionLayout( modifier = Modifier .fillMaxWidth() .height(400.dp), @@ -709,7 +741,8 @@ public fun ScreenExample7() { @Composable public fun ScreenExample8() { - var cs1 = ConstraintSet(""" + var cs1 = ConstraintSet( + """ { a: { rotationZ: -30, @@ -718,8 +751,10 @@ public fun ScreenExample8() { top: ['parent', 'top', 16] } } - """) - var cs2 = ConstraintSet(""" + """ + ) + var cs2 = ConstraintSet( + """ { a: { rotationZ: 30, @@ -727,23 +762,28 @@ public fun ScreenExample8() { top: ['parent', 'top', 16] } } - """) - var cs3 = ConstraintSet(""" + """ + ) + var cs3 = ConstraintSet( + """ { a: { end: ['parent', 'end', 16], bottom: ['parent', 'bottom', 16] } } - """) - var cs4 = ConstraintSet(""" + """ + ) + var cs4 = ConstraintSet( + """ { a: { start: ['parent', 'start', 16], bottom: ['parent', 'bottom', 16] } } - """) + """ + ) var start by remember { mutableStateOf(cs1) } var end by remember { mutableStateOf(cs2) } @@ -826,7 +866,8 @@ public fun ScreenExample8() { @Composable public fun ScreenExample9() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { center: { center: 'parent' @@ -844,7 +885,8 @@ public fun ScreenExample9() { h11: { circular: ['center', 330, 100] }, h12: { circular: ['center', 0, 100] } } - """), + """ + ), modifier = Modifier .fillMaxSize() ) { @@ -868,7 +910,8 @@ public fun ScreenExample9() { @Composable public fun ScreenExample10() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { h1: { circular: ['parent', 0, 100] }, h2: { circular: ['parent', 40, 100], rotationZ: 40 }, @@ -880,55 +923,74 @@ public fun ScreenExample10() { h8: { circular: ['parent', 280, 100], rotationZ: 280 }, h9: { circular: ['parent', 320, 100], rotationZ: 320 } } - """), + """ + ), modifier = Modifier .fillMaxSize() ) { - Box(modifier = Modifier - .layoutId("h1") - .width(100.dp) - .height(60.dp) - .background(Color.Red)) - Box(modifier = Modifier - .layoutId("h2") - .width(100.dp) - .height(60.dp) - .background(Color.Green)) - Box(modifier = Modifier - .layoutId("h3") - .width(100.dp) - .height(60.dp) - .background(Color.Blue)) - Box(modifier = Modifier - .layoutId("h4") - .width(100.dp) - .height(60.dp) - .background(Color.Gray)) - Box(modifier = Modifier - .layoutId("h5") - .width(100.dp) - .height(60.dp) - .background(Color.Yellow)) - Box(modifier = Modifier - .layoutId("h6") - .width(100.dp) - .height(60.dp) - .background(Color.Cyan)) - Box(modifier = Modifier - .layoutId("h7") - .width(100.dp) - .height(60.dp) - .background(Color.Magenta)) - Box(modifier = Modifier - .layoutId("h8") - .width(100.dp) - .height(60.dp) - .background(Color.Red)) - Box(modifier = Modifier - .layoutId("h9") - .width(100.dp) - .height(60.dp) - .background(Color.DarkGray)) + Box( + modifier = Modifier + .layoutId("h1") + .width(100.dp) + .height(60.dp) + .background(Color.Red) + ) + Box( + modifier = Modifier + .layoutId("h2") + .width(100.dp) + .height(60.dp) + .background(Color.Green) + ) + Box( + modifier = Modifier + .layoutId("h3") + .width(100.dp) + .height(60.dp) + .background(Color.Blue) + ) + Box( + modifier = Modifier + .layoutId("h4") + .width(100.dp) + .height(60.dp) + .background(Color.Gray) + ) + Box( + modifier = Modifier + .layoutId("h5") + .width(100.dp) + .height(60.dp) + .background(Color.Yellow) + ) + Box( + modifier = Modifier + .layoutId("h6") + .width(100.dp) + .height(60.dp) + .background(Color.Cyan) + ) + Box( + modifier = Modifier + .layoutId("h7") + .width(100.dp) + .height(60.dp) + .background(Color.Magenta) + ) + Box( + modifier = Modifier + .layoutId("h8") + .width(100.dp) + .height(60.dp) + .background(Color.Red) + ) + Box( + modifier = Modifier + .layoutId("h9") + .width(100.dp) + .height(60.dp) + .background(Color.DarkGray) + ) } } @@ -945,7 +1007,8 @@ public fun ScreenExample11() { Text(text = "Run") } MotionLayout( - ConstraintSet(""" + ConstraintSet( + """ { h1: { circular: ['parent', 0, 100] }, h2: { circular: ['parent', 40, 100], rotationZ: 40 }, @@ -957,8 +1020,10 @@ public fun ScreenExample11() { h8: { circular: ['parent', 280, 100], rotationZ: 280 }, h9: { circular: ['parent', 320, 100], rotationZ: 320 } } - """), - ConstraintSet(""" + """ + ), + ConstraintSet( + """ { h1: { circular: ['parent', 0, 100], rotationZ: 360 }, h2: { circular: ['parent', 40, 100], rotationZ: 400 }, @@ -970,57 +1035,76 @@ public fun ScreenExample11() { h8: { circular: ['parent', 280, 100], rotationZ: 640 }, h9: { circular: ['parent', 320, 100], rotationZ: 680 } } - """), + """ + ), progress = progress, modifier = Modifier .fillMaxSize() .background(Color.White) ) { - Box(modifier = Modifier - .layoutId("h1") - .width(100.dp) - .height(60.dp) - .background(Color.Red)) - Box(modifier = Modifier - .layoutId("h2") - .width(100.dp) - .height(60.dp) - .background(Color.Green)) - Box(modifier = Modifier - .layoutId("h3") - .width(100.dp) - .height(60.dp) - .background(Color.Blue)) - Box(modifier = Modifier - .layoutId("h4") - .width(100.dp) - .height(60.dp) - .background(Color.Gray)) - Box(modifier = Modifier - .layoutId("h5") - .width(100.dp) - .height(60.dp) - .background(Color.Yellow)) - Box(modifier = Modifier - .layoutId("h6") - .width(100.dp) - .height(60.dp) - .background(Color.Cyan)) - Box(modifier = Modifier - .layoutId("h7") - .width(100.dp) - .height(60.dp) - .background(Color.Magenta)) - Box(modifier = Modifier - .layoutId("h8") - .width(100.dp) - .height(60.dp) - .background(Color.Red)) - Box(modifier = Modifier - .layoutId("h9") - .width(100.dp) - .height(60.dp) - .background(Color.DarkGray)) + Box( + modifier = Modifier + .layoutId("h1") + .width(100.dp) + .height(60.dp) + .background(Color.Red) + ) + Box( + modifier = Modifier + .layoutId("h2") + .width(100.dp) + .height(60.dp) + .background(Color.Green) + ) + Box( + modifier = Modifier + .layoutId("h3") + .width(100.dp) + .height(60.dp) + .background(Color.Blue) + ) + Box( + modifier = Modifier + .layoutId("h4") + .width(100.dp) + .height(60.dp) + .background(Color.Gray) + ) + Box( + modifier = Modifier + .layoutId("h5") + .width(100.dp) + .height(60.dp) + .background(Color.Yellow) + ) + Box( + modifier = Modifier + .layoutId("h6") + .width(100.dp) + .height(60.dp) + .background(Color.Cyan) + ) + Box( + modifier = Modifier + .layoutId("h7") + .width(100.dp) + .height(60.dp) + .background(Color.Magenta) + ) + Box( + modifier = Modifier + .layoutId("h8") + .width(100.dp) + .height(60.dp) + .background(Color.Red) + ) + Box( + modifier = Modifier + .layoutId("h9") + .width(100.dp) + .height(60.dp) + .background(Color.DarkGray) + ) } } } @@ -1062,18 +1146,22 @@ public fun ScreenExample12() { Button(onClick = { animateToEnd = !animateToEnd }) { Text(text = "Run ScreenExample12") } - MotionLayout(cs1, cs2, + MotionLayout( + cs1, cs2, progress = progress, modifier = Modifier .fillMaxSize() .background(Color.White) ) { - var colors = arrayListOf(Color.Red, Color.Green, Color.Blue, Color.Cyan, Color.Yellow) + var colors = + arrayListOf(Color.Red, Color.Green, Color.Blue, Color.Cyan, Color.Yellow) for (i in 1..36) { - Box(modifier = Modifier - .layoutId("h$i", "box") - .background(colors[i % colors.size])) + Box( + modifier = Modifier + .layoutId("h$i", "box") + .background(colors[i % colors.size]) + ) } } } @@ -1093,8 +1181,9 @@ public fun ScreenExample13() { modifier = Modifier .fillMaxWidth() .height(400.dp) - .background(Color.White) , - start = ConstraintSet(""" + .background(Color.White), + start = ConstraintSet( + """ { a: { start: ['parent', 'start', 16], @@ -1125,12 +1214,15 @@ public fun ScreenExample13() { """ ), debug = EnumSet.of(MotionLayoutDebugFlags.SHOW_ALL), - progress = cprogress) { + progress = cprogress + ) { var properties = motionProperties("a") - Text(text = "Hello", modifier = Modifier - .layoutId(properties.value.id()) - .background(properties.value.color("background")) - ,color = properties.value.color("textColor") + Text( + text = "Hello", + modifier = Modifier + .layoutId(properties.value.id()) + .background(properties.value.color("background")), + color = properties.value.color("textColor") //,fontSize = properties.value.fontSize("textSize") ) } @@ -1155,8 +1247,9 @@ public fun ScreenExample14() { modifier = Modifier .fillMaxWidth() .height(400.dp) - .background(Color.White) , - start = ConstraintSet(""" + .background(Color.White), + start = ConstraintSet( + """ { a: { width: 40, @@ -1179,7 +1272,8 @@ public fun ScreenExample14() { } """ ), - transition = Transition(""" + transition = Transition( + """ { KeyFrames: { KeyPositions: [ @@ -1192,12 +1286,16 @@ public fun ScreenExample14() { ] } } - """), + """ + ), debug = EnumSet.of(MotionLayoutDebugFlags.SHOW_ALL), - progress = progress) { - Box(modifier = Modifier - .layoutId("a") - .background(Color.Red)) + progress = progress + ) { + Box( + modifier = Modifier + .layoutId("a") + .background(Color.Red) + ) } Button(onClick = { animateToEnd = !animateToEnd }) { @@ -1221,8 +1319,9 @@ public fun ScreenExample15() { modifier = Modifier .fillMaxWidth() .height(400.dp) - .background(Color.White) , - start = ConstraintSet(""" + .background(Color.White), + start = ConstraintSet( + """ { a: { width: 40, @@ -1246,7 +1345,8 @@ public fun ScreenExample15() { } """ ), - transition = Transition(""" + transition = Transition( + """ { KeyFrames: { KeyPositions: [ @@ -1259,10 +1359,23 @@ public fun ScreenExample15() { ] } } - """), + """ + ), debug = EnumSet.of(MotionLayoutDebugFlags.SHOW_ALL), - progress = progress) { + progress = progress + ) { Box(modifier = Modifier + .onPlaced { + vpSend("width", it.size.width.toFloat()) + vpSend("x", it.positionInParent().x) + + val matrix = Matrix() + + it.transformFrom(it.parentCoordinates!!, matrix); + val rot = 180.0f * calculateZRotation(matrix.values) / PI.toFloat() + println(rot) + vpSend("rot", rot) + } .layoutId("a") .background(Color.Red)) } @@ -1270,9 +1383,22 @@ public fun ScreenExample15() { Button(onClick = { animateToEnd = !animateToEnd }) { Text(text = "Run ScreenExample15") } + vpSend("progress", progress * 1000) + VpGraph(modifier = Modifier.fillMaxSize(), "rot", "progress", "x", "width") } } +fun calculateZRotation(matrix: FloatArray): Float { + // Extract the values from the matrix + val m00 = matrix[0] + val m01 = matrix[1] + val m10 = matrix[1 * 3 + 0] + val m11 = matrix[1 * 3 + 1] + + // Calculate the z-rotation angle + return -atan2(m01, m00) +} + @Preview(group = "motion8") @Composable public fun ScreenExample16() { @@ -1288,7 +1414,8 @@ public fun ScreenExample16() { .fillMaxWidth() .height(400.dp) .background(Color.White), - motionScene = MotionScene("""{ + motionScene = MotionScene( + """{ Header: { exportAs: 'motion8' }, @@ -1327,12 +1454,16 @@ public fun ScreenExample16() { } } } - }"""), + }""" + ), debug = EnumSet.of(MotionLayoutDebugFlags.SHOW_ALL), - progress = progress) { - Box(modifier = Modifier - .layoutId("a") - .background(Color.Red)) + progress = progress + ) { + Box( + modifier = Modifier + .layoutId("a") + .background(Color.Red) + ) } Button(onClick = { animateToEnd = !animateToEnd }) { @@ -1355,8 +1486,9 @@ public fun ScreenExample17() { modifier = Modifier .fillMaxWidth() .height(400.dp) - .background(Color.White) , - start = ConstraintSet(""" + .background(Color.White), + start = ConstraintSet( + """ { a: { width: 40, @@ -1393,13 +1525,18 @@ public fun ScreenExample17() { """ ), debug = EnumSet.of(MotionLayoutDebugFlags.SHOW_ALL), - progress = progress) { - Box(modifier = Modifier - .layoutId("a") - .background(Color.Red)) - Box(modifier = Modifier - .layoutId("b") - .background(Color.Blue)) + progress = progress + ) { + Box( + modifier = Modifier + .layoutId("a") + .background(Color.Red) + ) + Box( + modifier = Modifier + .layoutId("b") + .background(Color.Blue) + ) } Button(onClick = { animateToEnd = !animateToEnd }) { @@ -1423,7 +1560,8 @@ public fun ScreenExample18() { .fillMaxWidth() .height(400.dp) .background(Color.White), - motionScene = MotionScene("""{ + motionScene = MotionScene( + """{ Header: { exportAs: 'example 18' }, @@ -1466,15 +1604,21 @@ public fun ScreenExample18() { } } } -"""), +""" + ), debug = EnumSet.of(MotionLayoutDebugFlags.SHOW_ALL), - progress = progress) { - Box(modifier = Modifier - .layoutId("a") - .background(Color.Red)) - Box(modifier = Modifier - .layoutId("b") - .background(Color.Green)) + progress = progress + ) { + Box( + modifier = Modifier + .layoutId("a") + .background(Color.Red) + ) + Box( + modifier = Modifier + .layoutId("b") + .background(Color.Green) + ) } Button(onClick = { animateToEnd = !animateToEnd }) { @@ -1496,7 +1640,9 @@ public fun ScreenExample19() { Button(onClick = { animateToEnd = !animateToEnd }) { Text(text = "Run exemple19") } - MotionLayout(motionScene = MotionScene("""{ + MotionLayout( + motionScene = MotionScene( + """{ Header: { exportAs: 'exemple19' }, @@ -1529,18 +1675,21 @@ public fun ScreenExample19() { } } } - }"""), + }""" + ), progress = progress, modifier = Modifier .fillMaxSize() .background(Color.White) ) { - var colors = arrayListOf(Color.Red, Color.Green, Color.Blue, Color.Cyan, Color.Yellow) + var colors = + arrayListOf(Color.Red, Color.Green, Color.Blue, Color.Cyan, Color.Yellow) for (i in 1..36) { - Box(modifier = Modifier - .layoutId("h$i", "box") - .background(colors[i % colors.size]) + Box( + modifier = Modifier + .layoutId("h$i", "box") + .background(colors[i % colors.size]) ) } } @@ -1594,7 +1743,8 @@ public fun ScreenExample21() { @Composable public fun ScreenExample20() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { Header: { exportAs: 'guidelines' @@ -1633,7 +1783,8 @@ public fun ScreenExample20() { end: ['g5', 'end', 'margin'] } } - """), + """ + ), modifier = Modifier .fillMaxSize() .background(Color.White) @@ -1651,13 +1802,15 @@ public fun ScreenExample20() { @Composable fun Playground() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { Header: { exportAs: 'Playground' } } - """), + """ + ), modifier = Modifier .fillMaxSize() .background(Color.White) @@ -1669,7 +1822,8 @@ fun Playground() { @Composable public fun ChainNew1() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { Variables: { bottom: 20 @@ -1711,7 +1865,8 @@ public fun ChainNew1() { top: ['b', 'bottom'] } } - """), + """ + ), modifier = Modifier .fillMaxSize() ) { @@ -1759,7 +1914,8 @@ public fun ChainNew1() { @Composable public fun ChainNew2() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { Variables: { bottom: 20 @@ -1803,7 +1959,8 @@ public fun ChainNew2() { bottom: ['b', 'bottom' ] } } - """), + """ + ), modifier = Modifier .fillMaxSize() ) { @@ -1852,7 +2009,8 @@ public fun ChainNew2() { @Composable public fun ChainNew3() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { Variables: { bottom: 20 @@ -1926,9 +2084,10 @@ public fun ChainNew3() { } """ - ), + ), modifier = Modifier - .fillMaxSize().background(Color.LightGray) + .fillMaxSize() + .background(Color.LightGray) ) { Text(text = "chain2.3!") for (k in 1..5) { @@ -1950,14 +2109,12 @@ public fun ChainNew3() { } - - - @Preview(group = "new4") @Composable public fun ChainNew4() { ConstraintLayout( - ConstraintSet(""" + ConstraintSet( + """ { Variables: { bottom: 20 @@ -2033,7 +2190,8 @@ public fun ChainNew4() { """ ), modifier = Modifier - .fillMaxSize().background(Color.LightGray) + .fillMaxSize() + .background(Color.LightGray) ) { Text(text = "chain2.3!") for (k in 1..5) {