-
Notifications
You must be signed in to change notification settings - Fork 300
Embedded components #2193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Embedded components #2193
Changes from all commits
db0fa9f
070f198
e4f2e69
c32af78
8f4d601
9f32ca6
5ea7e9b
e62cd98
7d03d7a
29f09f9
e2a597b
c8654e2
f1acd01
91f52cc
8e58819
a6e2c87
146b31c
3120ef3
ef8630a
2001d48
3066e48
f41b48e
6f9688b
c3c69f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package com.reactnativestripesdk | ||
|
|
||
| import com.facebook.react.module.annotations.ReactModule | ||
| import com.facebook.react.uimanager.SimpleViewManager | ||
| import com.facebook.react.uimanager.ThemedReactContext | ||
| import com.facebook.react.uimanager.annotations.ReactProp | ||
| import com.facebook.react.viewmanagers.NavigationBarManagerDelegate | ||
| import com.facebook.react.viewmanagers.NavigationBarManagerInterface | ||
|
|
||
| @ReactModule(name = NavigationBarManager.REACT_CLASS) | ||
| class NavigationBarManager : | ||
| SimpleViewManager<NavigationBarView>(), | ||
| NavigationBarManagerInterface<NavigationBarView> { | ||
| private val delegate = NavigationBarManagerDelegate(this) | ||
|
|
||
| override fun getName() = REACT_CLASS | ||
|
|
||
| override fun getDelegate() = delegate | ||
|
|
||
| override fun getExportedCustomDirectEventTypeConstants() = | ||
| mutableMapOf( | ||
| EVENT_ON_CLOSE_BUTTON_PRESS to mutableMapOf("registrationName" to EVENT_ON_CLOSE_BUTTON_PRESS), | ||
| ) | ||
|
|
||
| @ReactProp(name = "title") | ||
| override fun setTitle( | ||
| view: NavigationBarView, | ||
| title: String?, | ||
| ) { | ||
| view.setTitle(title) | ||
| } | ||
|
|
||
| override fun createViewInstance(reactContext: ThemedReactContext): NavigationBarView = NavigationBarView(reactContext) | ||
|
|
||
| companion object { | ||
| const val REACT_CLASS = "NavigationBar" | ||
| private const val EVENT_ON_CLOSE_BUTTON_PRESS = "onCloseButtonPress" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| package com.reactnativestripesdk | ||
|
|
||
| import android.annotation.SuppressLint | ||
| import android.graphics.Color | ||
| import android.view.Gravity | ||
| import android.widget.FrameLayout | ||
| import android.widget.ImageButton | ||
| import android.widget.TextView | ||
| import androidx.appcompat.widget.Toolbar | ||
| import com.facebook.react.bridge.Arguments | ||
| import com.facebook.react.uimanager.ThemedReactContext | ||
| import com.facebook.react.uimanager.UIManagerHelper | ||
| import com.facebook.react.uimanager.events.Event | ||
|
|
||
| @SuppressLint("ViewConstructor") | ||
| class NavigationBarView( | ||
| context: ThemedReactContext, | ||
| ) : FrameLayout(context) { | ||
| private val toolbar: Toolbar | ||
| private val titleTextView: TextView | ||
| private var titleText: String? = null | ||
|
|
||
| init { | ||
| // Create Toolbar | ||
| toolbar = | ||
| Toolbar(context).apply { | ||
| layoutParams = | ||
| LayoutParams( | ||
| LayoutParams.MATCH_PARENT, | ||
| LayoutParams.WRAP_CONTENT, | ||
| ) | ||
| setBackgroundColor(Color.WHITE) | ||
| elevation = 4f | ||
| } | ||
|
|
||
| // Create title TextView | ||
| titleTextView = | ||
| TextView(context).apply { | ||
| textSize = 17f | ||
| setTextColor(Color.BLACK) | ||
| gravity = Gravity.CENTER | ||
| } | ||
|
|
||
| // Add title to toolbar | ||
| val titleParams = | ||
| Toolbar | ||
| .LayoutParams( | ||
| Toolbar.LayoutParams.WRAP_CONTENT, | ||
| Toolbar.LayoutParams.WRAP_CONTENT, | ||
| ).apply { | ||
| gravity = Gravity.CENTER | ||
| } | ||
| toolbar.addView(titleTextView, titleParams) | ||
|
|
||
| // Create close button | ||
| val closeButton = | ||
| ImageButton(context).apply { | ||
| setImageDrawable( | ||
| context.resources.getDrawable( | ||
| android.R.drawable.ic_menu_close_clear_cancel, | ||
| null, | ||
| ), | ||
| ) | ||
| setBackgroundColor(Color.TRANSPARENT) | ||
| setOnClickListener { | ||
| dispatchCloseButtonPress() | ||
| } | ||
| } | ||
|
|
||
| // Add close button to toolbar | ||
| val buttonParams = | ||
| Toolbar | ||
| .LayoutParams( | ||
| Toolbar.LayoutParams.WRAP_CONTENT, | ||
| Toolbar.LayoutParams.WRAP_CONTENT, | ||
| ).apply { | ||
| gravity = Gravity.END or Gravity.CENTER_VERTICAL | ||
| marginEnd = 16 | ||
| } | ||
| toolbar.addView(closeButton, buttonParams) | ||
|
|
||
| // Add toolbar to this view | ||
| addView(toolbar) | ||
| } | ||
|
|
||
| fun setTitle(title: String?) { | ||
| titleText = title | ||
| titleTextView.text = title | ||
| } | ||
|
|
||
| private fun dispatchCloseButtonPress() { | ||
| val event = | ||
| CloseButtonPressEvent( | ||
| getContext().surfaceId, | ||
| id, | ||
| ) | ||
| UIManagerHelper.getEventDispatcherForReactTag(getContext(), id)?.dispatchEvent(event) | ||
| } | ||
|
|
||
| override fun onMeasure( | ||
| widthMeasureSpec: Int, | ||
| heightMeasureSpec: Int, | ||
| ) { | ||
| super.onMeasure(widthMeasureSpec, heightMeasureSpec) | ||
| // Set a fixed height for the navigation bar | ||
| val desiredHeight = (56 * resources.displayMetrics.density).toInt() | ||
| val newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(desiredHeight, MeasureSpec.EXACTLY) | ||
| super.onMeasure(widthMeasureSpec, newHeightMeasureSpec) | ||
| } | ||
|
|
||
| private class CloseButtonPressEvent( | ||
| surfaceId: Int, | ||
| viewId: Int, | ||
| ) : Event<CloseButtonPressEvent>(surfaceId, viewId) { | ||
| override fun getEventName() = "onCloseButtonPress" | ||
|
|
||
| override fun getEventData() = Arguments.createMap() | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package com.microsoft.reacttestapp | ||
|
|
||
| import android.content.Intent | ||
| import android.os.Bundle | ||
| import android.util.Log | ||
|
|
||
| /** | ||
| * Custom MainActivity that extends RNTA's base to handle deep links with singleTask. | ||
| * This file shadows the one in node_modules/react-native-test-app. | ||
| */ | ||
| class MainActivity : com.facebook.react.ReactActivity() { | ||
|
|
||
| companion object { | ||
| private const val TAG = "MainActivity" | ||
| const val REQUEST_CODE_PERMISSIONS = 42 | ||
| } | ||
|
|
||
| private val testApp: TestApp | ||
| get() = application as TestApp | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| Log.d(TAG, "onCreate with intent: ${intent?.dataString}") | ||
| } | ||
|
|
||
| /** | ||
| * CRITICAL: This method handles deep links when the app is already running. | ||
| * With launchMode="singleTask", this is called instead of onCreate when | ||
| * a deep link brings the app to foreground. | ||
| */ | ||
| override fun onNewIntent(intent: Intent) { | ||
| super.onNewIntent(intent) // ReactActivity handles sending to Linking module | ||
| Log.d(TAG, "onNewIntent with data: ${intent.dataString}") | ||
| setIntent(intent) // Update current intent | ||
| } | ||
|
|
||
| override fun getMainComponentName(): String? { | ||
| return testApp.manifest.singleApp ?: "example" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,3 +42,41 @@ allprojects { | |
| google() | ||
| } | ||
| } | ||
|
|
||
| // Fix MainActivity launchMode and add deep link for stripe-connect | ||
| subprojects { subproject -> | ||
| subproject.afterEvaluate { | ||
| subproject.tasks.matching { task -> | ||
| task.name == 'generateAndroidManifest' | ||
| }.configureEach { task -> | ||
| task.doLast { | ||
| def manifestFile = file("${subproject.buildDir}/generated/rnta/src/main/AndroidManifest.xml") | ||
| if (manifestFile.exists()) { | ||
| def manifest = manifestFile.text | ||
|
|
||
| // Add launchMode="singleTask" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MainActivity with launchMode=singleTask will destroy all activities that previously existed on top of it. Is that what we want? In any case, can't we define a standard AndroidManifest.xml file, instead of doing this?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. launchMode=singleTask is necessary for deep linking with React Navigation: And deep linking is necessary for using "secure webviews" (implemented with chrome tabs on Android) to return back to the app. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And we can't use |
||
| manifest = manifest.replace( | ||
| '<activity android:name="com.microsoft.reacttestapp.MainActivity" android:exported="true">', | ||
| '<activity android:name="com.microsoft.reacttestapp.MainActivity" android:exported="true" android:launchMode="singleTask">' | ||
| ) | ||
|
|
||
| // Add deep link intent filter for stripe-connect | ||
| def intentFilterXml = '''<intent-filter> | ||
| <action android:name="android.intent.action.VIEW"></action> | ||
| <category android:name="android.intent.category.DEFAULT"></category> | ||
| <category android:name="android.intent.category.BROWSABLE"></category> | ||
| <data android:scheme="stripe-connect"></data> | ||
| </intent-filter> | ||
| ''' | ||
| manifest = manifest.replace( | ||
| '</intent-filter>\n </activity>', | ||
| '</intent-filter>\n ' + intentFilterXml + '</activity>' | ||
| ) | ||
|
|
||
| manifestFile.text = manifest | ||
| println "✓ Updated MainActivity: launchMode=singleTask + stripe-connect deep link" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: You can probably move this outside of
runOnUiThread