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
29 changes: 26 additions & 3 deletions packages/react-native/React/Base/RCTBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#import "RCTJSThread.h"
#import "RCTLog.h"
#import "RCTModuleData.h"
#import "RCTPausedInDebuggerOverlayController.h"
#import "RCTPerformanceLogger.h"
#import "RCTProfile.h"
#import "RCTReloadCommand.h"
Expand Down Expand Up @@ -191,21 +192,43 @@ void RCTUIManagerSetDispatchAccessibilityManagerInitOntoMain(BOOL enabled)

class RCTBridgeHostTargetDelegate : public facebook::react::jsinspector_modern::HostTargetDelegate {
public:
RCTBridgeHostTargetDelegate(RCTBridge *bridge) : bridge_(bridge) {}
RCTBridgeHostTargetDelegate(RCTBridge *bridge)
: bridge_(bridge), pauseOverlayController_([[RCTPausedInDebuggerOverlayController alloc] init])
{
}

void onReload(const PageReloadRequest &request) override
{
RCTAssertMainQueue();
[bridge_ reload];
}

void onSetPausedInDebuggerMessage(const OverlaySetPausedInDebuggerMessageRequest &) override
void onSetPausedInDebuggerMessage(const OverlaySetPausedInDebuggerMessageRequest &request) override
{
// TODO(moti): Implement this
RCTAssertMainQueue();
if (!request.message.has_value()) {
[pauseOverlayController_ hide];
} else {
__weak RCTBridge *bridgeWeak = bridge_;
[pauseOverlayController_ showWithMessage:@(request.message.value().c_str())
onResume:^{
RCTAssertMainQueue();
RCTBridge *bridgeStrong = bridgeWeak;
if (!bridgeStrong) {
return;
}
if (!bridgeStrong.inspectorTarget) {
return;
}
bridgeStrong.inspectorTarget->sendCommand(
facebook::react::jsinspector_modern::HostCommand::DebuggerResume);
}];
}
}

private:
__weak RCTBridge *bridge_;
RCTPausedInDebuggerOverlayController *pauseOverlayController_;
};

@interface RCTBridge () <RCTReloadListener>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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.
*/

#import <Foundation/Foundation.h>

@interface RCTPausedInDebuggerOverlayController : NSObject

- (void)showWithMessage:(NSString *)message onResume:(void (^)(void))onResume;
- (void)hide;

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* 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.
*/

#import <React/RCTUtils.h>

#import "RCTPausedInDebuggerOverlayController.h"

@interface RCTPausedInDebuggerViewController : UIViewController
@property (nonatomic, copy) void (^onResume)(void);
@property (nonatomic, strong) NSString *message;
@end

@interface RCTPausedInDebuggerOverlayController ()

@property (nonatomic, strong) UIWindow *alertWindow;

@end

@implementation RCTPausedInDebuggerViewController
- (void)viewDidLoad
{
[super viewDidLoad];

UIView *dimmingView = [[UIView alloc] init];
dimmingView.translatesAutoresizingMaskIntoConstraints = NO;
dimmingView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
[self.view addSubview:dimmingView];
[NSLayoutConstraint activateConstraints:@[
[dimmingView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[dimmingView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
[dimmingView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[dimmingView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor]
]];

UILabel *messageLabel = [[UILabel alloc] init];
messageLabel.text = self.message;
messageLabel.textAlignment = NSTextAlignmentCenter;
messageLabel.numberOfLines = 0;
messageLabel.font = [UIFont boldSystemFontOfSize:16];
messageLabel.textColor = [UIColor blackColor];
messageLabel.translatesAutoresizingMaskIntoConstraints = NO;
UIView *messageContainer = [[UIView alloc] init];
[messageContainer addSubview:messageLabel];
[NSLayoutConstraint activateConstraints:@[
[messageLabel.topAnchor constraintEqualToAnchor:messageContainer.topAnchor],
[messageLabel.bottomAnchor constraintEqualToAnchor:messageContainer.bottomAnchor],
[messageLabel.leadingAnchor constraintEqualToAnchor:messageContainer.leadingAnchor constant:14],
[messageLabel.trailingAnchor constraintEqualToAnchor:messageContainer.trailingAnchor],
]];

UIButton *resumeButton = [UIButton buttonWithType:UIButtonTypeCustom];
[resumeButton setImage:[UIImage systemImageNamed:@"forward.frame.fill"] forState:UIControlStateNormal];
[resumeButton addTarget:self action:@selector(resumeButtonTapped) forControlEvents:UIControlEventTouchUpInside];
resumeButton.tintColor = [UIColor colorWithRed:0.26 green:0.5 blue:0.92 alpha:1];
[NSLayoutConstraint activateConstraints:@[
[resumeButton.widthAnchor constraintEqualToConstant:48],
[resumeButton.heightAnchor constraintEqualToConstant:48],
]];

UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:@[ messageContainer, resumeButton ]];
stackView.backgroundColor = [UIColor colorWithRed:1 green:1 blue:0.757 alpha:1];
stackView.layer.cornerRadius = 12;
stackView.layer.borderWidth = 2;
stackView.layer.borderColor = [UIColor colorWithRed:0.816 green:0.816 blue:0.723 alpha:1].CGColor;
stackView.translatesAutoresizingMaskIntoConstraints = NO;
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.distribution = UIStackViewDistributionFill;
stackView.alignment = UIStackViewAlignmentCenter;

[self.view addSubview:stackView];

[NSLayoutConstraint activateConstraints:@[
[stackView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:12],
[stackView.centerXAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.centerXAnchor],
]];

stackView.semanticContentAttribute = UISemanticContentAttributeForceLeftToRight;
}

- (void)resumeButtonTapped
{
self.onResume();
}
@end

@implementation RCTPausedInDebuggerOverlayController

- (UIWindow *)alertWindow
{
if (_alertWindow == nil) {
_alertWindow = [[UIWindow alloc] initWithWindowScene:RCTKeyWindow().windowScene];

if (_alertWindow) {
_alertWindow.rootViewController = [UIViewController new];
_alertWindow.windowLevel = UIWindowLevelAlert + 1;
}
}

return _alertWindow;
}

- (void)showWithMessage:(NSString *)message onResume:(void (^)(void))onResume
{
[self hide];

RCTPausedInDebuggerViewController *view = [[RCTPausedInDebuggerViewController alloc] init];
view.modalPresentationStyle = UIModalPresentationOverFullScreen;
view.message = message;
view.onResume = onResume;
[self.alertWindow makeKeyAndVisible];
[self.alertWindow.rootViewController presentViewController:view animated:NO completion:nil];
}

- (void)hide
{
[_alertWindow setHidden:YES];

_alertWindow.windowScene = nil;

_alertWindow = nil;
}

@end
13 changes: 13 additions & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,8 @@ public class com/facebook/react/bridge/ReactIgnorableMountingException : java/la
public class com/facebook/react/bridge/ReactInstanceManagerInspectorTarget : java/lang/AutoCloseable {
public fun <init> (Lcom/facebook/react/bridge/ReactInstanceManagerInspectorTarget$TargetDelegate;)V
public fun close ()V
public fun sendDebuggerResumeCommand ()V
public fun sendDebuggerStepOverCommand ()V
}

public abstract interface class com/facebook/react/bridge/ReactInstanceManagerInspectorTarget$TargetDelegate {
Expand Down Expand Up @@ -2127,6 +2129,7 @@ public abstract class com/facebook/react/devsupport/DevSupportManagerBase : com/
public fun handleException (Ljava/lang/Exception;)V
public fun hasUpToDateJSBundleInCache ()Z
protected fun hideDevLoadingView ()V
public fun hidePausedInDebuggerOverlay ()V
public fun hideRedboxDialog ()V
public fun isPackagerRunning (Lcom/facebook/react/devsupport/interfaces/PackagerStatusCallback;)V
public fun onNewReactContextCreated (Lcom/facebook/react/bridge/ReactContext;)V
Expand All @@ -2146,6 +2149,7 @@ public abstract class com/facebook/react/devsupport/DevSupportManagerBase : com/
public fun showDevOptionsDialog ()V
public fun showNewJSError (Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;I)V
public fun showNewJavaError (Ljava/lang/String;Ljava/lang/Throwable;)V
public fun showPausedInDebuggerOverlay (Ljava/lang/String;Lcom/facebook/react/devsupport/interfaces/DevSupportManager$PausedInDebuggerOverlayCommandListener;)V
public fun startInspector ()V
public fun stopInspector ()V
public fun toggleElementInspector ()V
Expand Down Expand Up @@ -2291,6 +2295,7 @@ public class com/facebook/react/devsupport/ReleaseDevSupportManager : com/facebo
public fun handleException (Ljava/lang/Exception;)V
public fun handleReloadJS ()V
public fun hasUpToDateJSBundleInCache ()Z
public fun hidePausedInDebuggerOverlay ()V
public fun hideRedboxDialog ()V
public fun isPackagerRunning (Lcom/facebook/react/devsupport/interfaces/PackagerStatusCallback;)V
public fun loadSplitBundleFromServer (Ljava/lang/String;Lcom/facebook/react/devsupport/interfaces/DevSplitBundleCallback;)V
Expand All @@ -2310,6 +2315,7 @@ public class com/facebook/react/devsupport/ReleaseDevSupportManager : com/facebo
public fun showDevOptionsDialog ()V
public fun showNewJSError (Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;I)V
public fun showNewJavaError (Ljava/lang/String;Ljava/lang/Throwable;)V
public fun showPausedInDebuggerOverlay (Ljava/lang/String;Lcom/facebook/react/devsupport/interfaces/DevSupportManager$PausedInDebuggerOverlayCommandListener;)V
public fun startInspector ()V
public fun stopInspector ()V
public fun toggleElementInspector ()V
Expand Down Expand Up @@ -2401,6 +2407,7 @@ public abstract interface class com/facebook/react/devsupport/interfaces/DevSupp
public abstract fun getSourceUrl ()Ljava/lang/String;
public abstract fun handleReloadJS ()V
public abstract fun hasUpToDateJSBundleInCache ()Z
public abstract fun hidePausedInDebuggerOverlay ()V
public abstract fun hideRedboxDialog ()V
public abstract fun isPackagerRunning (Lcom/facebook/react/devsupport/interfaces/PackagerStatusCallback;)V
public abstract fun loadSplitBundleFromServer (Ljava/lang/String;Lcom/facebook/react/devsupport/interfaces/DevSplitBundleCallback;)V
Expand All @@ -2420,6 +2427,7 @@ public abstract interface class com/facebook/react/devsupport/interfaces/DevSupp
public abstract fun showDevOptionsDialog ()V
public abstract fun showNewJSError (Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;I)V
public abstract fun showNewJavaError (Ljava/lang/String;Ljava/lang/Throwable;)V
public abstract fun showPausedInDebuggerOverlay (Ljava/lang/String;Lcom/facebook/react/devsupport/interfaces/DevSupportManager$PausedInDebuggerOverlayCommandListener;)V
public abstract fun startInspector ()V
public abstract fun stopInspector ()V
public abstract fun toggleElementInspector ()V
Expand All @@ -2430,6 +2438,11 @@ public abstract interface class com/facebook/react/devsupport/interfaces/DevSupp
public abstract fun run (Ljava/lang/Runnable;)V
}

public abstract interface class com/facebook/react/devsupport/interfaces/DevSupportManager$PausedInDebuggerOverlayCommandListener {
public abstract fun onResume ()V
public abstract fun onStepOver ()V
}

public abstract interface class com/facebook/react/devsupport/interfaces/ErrorCustomizer {
public abstract fun customizeErrorInfo (Landroid/util/Pair;)Landroid/util/Pair;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
import com.facebook.react.devsupport.interfaces.DevLoadingViewManager;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
import com.facebook.react.devsupport.interfaces.DevSupportManager.PausedInDebuggerOverlayCommandListener;
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
import com.facebook.react.devsupport.interfaces.RedBoxHandler;
import com.facebook.react.internal.AndroidChoreographerProvider;
Expand Down Expand Up @@ -1497,7 +1498,29 @@ public void onReload() {

@Override
public void onSetPausedInDebuggerMessage(@Nullable String message) {
// TODO(moti): Implement this
if (message == null) {
mDevSupportManager.hidePausedInDebuggerOverlay();
} else {
mDevSupportManager.showPausedInDebuggerOverlay(
message,
new PausedInDebuggerOverlayCommandListener() {
@Override
public void onResume() {
UiThreadUtil.assertOnUiThread();
if (mInspectorTarget != null) {
mInspectorTarget.sendDebuggerResumeCommand();
}
}

@Override
public void onStepOver() {
UiThreadUtil.assertOnUiThread();
if (mInspectorTarget != null) {
mInspectorTarget.sendDebuggerStepOverCommand();
}
}
});
}
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ public void execute(Runnable command) {

private native HybridData initHybrid(Executor executor, TargetDelegate delegate);

public native void sendDebuggerResumeCommand();

public native void sendDebuggerStepOverCommand();

public void close() {
mHybridData.resetNative();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
Expand All @@ -22,8 +23,10 @@
import android.os.Build;
import android.util.Pair;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
Expand Down Expand Up @@ -1164,4 +1167,48 @@ public void openDebugger() {
mDevServerHelper.openDebugger(
mCurrentContext, mApplicationContext.getString(R.string.catalyst_open_debugger_error));
}

private @Nullable Dialog mPausedInDebuggerDialog;

@Override
public void showPausedInDebuggerOverlay(
String message, PausedInDebuggerOverlayCommandListener listener) {
UiThreadUtil.runOnUiThread(
() -> {
if (mPausedInDebuggerDialog != null) {
mPausedInDebuggerDialog.dismiss();
}
Activity context = mReactInstanceDevHelper.getCurrentActivity();
if (context == null || context.isFinishing()) {
return;
}
View dialogView =
LayoutInflater.from(context).inflate(R.layout.paused_in_debugger_view, null);
mPausedInDebuggerDialog = new Dialog(context);
mPausedInDebuggerDialog.setContentView(dialogView);
mPausedInDebuggerDialog.setCancelable(false);
TextView pausedText = dialogView.findViewById(R.id.paused_text);
pausedText.setText(message);
View resumeButton = dialogView.findViewById(R.id.resume_button);
resumeButton.setOnClickListener((v) -> listener.onResume());
View stepOverButton = dialogView.findViewById(R.id.step_over_button);
stepOverButton.setOnClickListener((v) -> listener.onStepOver());
Window dialogWindow = mPausedInDebuggerDialog.getWindow();
if (dialogWindow != null) {
dialogWindow.setGravity(Gravity.TOP);
}
mPausedInDebuggerDialog.show();
});
}

@Override
public void hidePausedInDebuggerOverlay() {
UiThreadUtil.runOnUiThread(
() -> {
if (mPausedInDebuggerDialog != null) {
mPausedInDebuggerDialog.dismiss();
mPausedInDebuggerDialog = null;
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,11 @@ public void handleException(Exception e) {

@Override
public void openDebugger() {}

@Override
public void showPausedInDebuggerOverlay(
String message, PausedInDebuggerOverlayCommandListener listener) {}

@Override
public void hidePausedInDebuggerOverlay() {}
}
Loading