Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions ReactAndroid/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ plugins {
id("com.facebook.react")
id("maven-publish")
id("de.undercouch.download")
id("kotlin-android")
}

import com.facebook.react.tasks.internal.*
Expand Down Expand Up @@ -336,6 +337,7 @@ android {
exclude("com/facebook/react/processing")
exclude("com/facebook/react/module/processing")
}
// kotlin.srcDirs += 'src/main/java/com/facebook/react/kotlin'
}

lintOptions {
Expand All @@ -352,6 +354,24 @@ android {
extractJNI
javadocDeps.extendsFrom api
}

buildFeatures {
compose true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

composeOptions {
kotlinCompilerExtensionVersion '1.0.1'
kotlinCompilerVersion "1.5.10"
kotlinCompilerExtensionVersion "1.0.0-beta08"
}

kotlinOptions {
jvmTarget = "1.8"
}
}

dependencies {
Expand Down Expand Up @@ -387,6 +407,24 @@ dependencies {
androidTestImplementation("androidx.test:runner:${ANDROIDX_TEST_VERSION}")
androidTestImplementation("androidx.test:rules:${ANDROIDX_TEST_VERSION}")
androidTestImplementation("org.mockito:mockito-core:${MOCKITO_CORE_VERSION}")

implementation("androidx.core:core-ktx:1.3.2")
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.5.21")

implementation "androidx.compose.compiler:compiler:1.0.0-beta08"

// Integration with activities
implementation 'androidx.activity:activity-compose:1.3.1'
// Compose Material Design
implementation 'androidx.compose.material:material:1.0.1'
// Animations
implementation 'androidx.compose.animation:animation:1.0.1'
// Tooling support (Previews, etc.)
implementation 'androidx.compose.ui:ui-tooling:1.0.1'
// Integration with ViewModels
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07'
// UI Tests
androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.0.1'
}

react {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
import android.os.Build;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.Callback;
Expand Down Expand Up @@ -89,7 +93,22 @@ protected ReactRootView createRootView() {

protected void loadApp(String appKey) {
mReactDelegate.loadApp(appKey);
getPlainActivity().setContentView(mReactDelegate.getReactRootView());
Context context = getContext();
LinearLayout linearLayout = new LinearLayout(context);
linearLayout.setLayoutParams(
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));

linearLayout.setOrientation(LinearLayout.VERTICAL);
View composeView = com.facebook.react.kotlin.TestComposableKt.getComposeView(context);

TextView text = new TextView(context);
text.setText("This is a text");
linearLayout.addView(text);
linearLayout.addView(composeView);
linearLayout.addView(mReactDelegate.getReactRootView());

getPlainActivity().setContentView(linearLayout);
}

protected void onPause() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.kotlin

import android.content.Context
import android.widget.FrameLayout
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composition
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.MonotonicFrameClock
import androidx.compose.runtime.Recomposer
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFontLoader
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class BackgroundMeasure(private val context: Context) {
private val view = FrameLayout(context)
private val owner =
object : ComposeShims.BackgroundMeasureOwner(context) {
// These methods use inline classes, so we have to override them here
override fun calculateLocalPosition(positionInWindow: Offset): Offset = positionInWindow
override fun calculatePositionInWindow(localPosition: Offset): Offset = localPosition
override fun getFocusDirection(keyEvent: KeyEvent): FocusDirection? = null
override fun requestRectangleOnScreen(rect: Rect) {}
}
private val root = owner.root
private val applier = ComposeShims.createApplier(root)

val clock =
object : MonotonicFrameClock {
override suspend fun <R> withFrameNanos(onFrame: (frameTimeNanos: Long) -> R): R =
onFrame(System.nanoTime())
}
val coroutineContext = Dispatchers.Unconfined + clock
val recomposer = Recomposer(coroutineContext)
val composition = Composition(applier, recomposer)

/** Synchronously (I hope?) measures Composable on a current thread (at least seems like so?) */
fun measureComposable(constraints: Constraints, content: @Composable () -> Unit): IntSize {
composition.setContent {
CompositionLocalProvider(
// See ProvideCommonCompositionLocals or ProvideAndroidCompositionLocals for a full list
// Here I only added things until Text composable stopped crashing
LocalDensity.provides(owner.density),
LocalFontLoader.provides(owner.fontLoader),
LocalContext.provides(context),
LocalLayoutDirection.provides(owner.layoutDirection),
LocalViewConfiguration.provides(owner.viewConfiguration),
LocalView.provides(view),
content = content)
}

val runRecomposeJob =
CoroutineScope(coroutineContext).launch(start = CoroutineStart.UNDISPATCHED) {
recomposer.runRecomposeAndApplyChanges()
}

ComposeShims.attachOwner(root, owner)
owner.nodes.forEach { ComposeShims.setLayoutRequired(it) }
(root as Measurable).measure(constraints)

runRecomposeJob.cancel()

return IntSize(ComposeShims.getNodeWidth(root), ComposeShims.getNodeHeight(root))
}
}
Loading