diff --git a/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js b/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js index 23df229f056a..fd82442f2366 100644 --- a/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js +++ b/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js @@ -372,12 +372,6 @@ export default class InspectorProxy implements InspectorProxyQueries { this.#devices.set(deviceId, newDevice); - this.#logger?.info( - "Connection established to app='%s' on device='%s'.", - appName, - deviceName, - ); - debug( "Got new device connection: name='%s', app=%s, device=%s, via=%s", deviceName, @@ -450,7 +444,7 @@ export default class InspectorProxy implements InspectorProxyQueries { ); socket.on('close', (code: number, reason: string) => { - this.#logger?.info( + debug( "Connection closed to device='%s' for app='%s' with code='%s' and reason='%s'.", deviceName, appName, @@ -526,7 +520,7 @@ export default class InspectorProxy implements InspectorProxyQueries { throw new Error(INTERNAL_ERROR_MESSAGES.UNREGISTERED_DEVICE); } - this.#logger?.info( + debug( "Connection established to DevTools for app='%s' on device='%s'.", device.getApp() || 'unknown', device.getName() || 'unknown', @@ -594,7 +588,7 @@ export default class InspectorProxy implements InspectorProxyQueries { }); socket.on('close', (code: number, reason: string) => { - this.#logger?.info( + debug( "Connection closed to DevTools for app='%s' on device='%s' with code='%s' and reason='%s'.", device.getApp() || 'unknown', device.getName() || 'unknown', diff --git a/packages/react-native/Libraries/Utilities/DevLoadingView.js b/packages/react-native/Libraries/Utilities/DevLoadingView.js index f43bb86b2969..338a5614df35 100644 --- a/packages/react-native/Libraries/Utilities/DevLoadingView.js +++ b/packages/react-native/Libraries/Utilities/DevLoadingView.js @@ -14,29 +14,37 @@ import NativeDevLoadingView from './NativeDevLoadingView'; const COLOR_SCHEME = { dark: { + load: { + backgroundColor: '#fafafa', + textColor: '#242526', + }, refresh: { backgroundColor: '#2584e8', textColor: '#ffffff', }, - load: { - backgroundColor: '#fafafa', - textColor: '#242526', + error: { + backgroundColor: '#1065AF', + textColor: '#ffffff', }, }, default: { + load: { + backgroundColor: '#404040', + textColor: '#ffffff', + }, refresh: { backgroundColor: '#2584e8', textColor: '#ffffff', }, - load: { - backgroundColor: '#404040', + error: { + backgroundColor: '#1065AF', textColor: '#ffffff', }, }, }; export default { - showMessage(message: string, type: 'load' | 'refresh') { + showMessage(message: string, type: 'load' | 'refresh' | 'error') { if (NativeDevLoadingView) { const colorScheme = getColorScheme() === 'dark' ? COLOR_SCHEME.dark : COLOR_SCHEME.default; diff --git a/packages/react-native/Libraries/Utilities/HMRClient.js b/packages/react-native/Libraries/Utilities/HMRClient.js index 6d16b6b973f3..f466f7a7f99a 100644 --- a/packages/react-native/Libraries/Utilities/HMRClient.js +++ b/packages/react-native/Libraries/Utilities/HMRClient.js @@ -232,8 +232,6 @@ Error: ${e.message}`; }); client.on('error', data => { - DevLoadingView.hide(); - if (data.type === 'GraphNotFoundError') { client.close(); setHMRUnavailableReason( @@ -253,8 +251,6 @@ Error: ${e.message}`; }); client.on('close', closeEvent => { - DevLoadingView.hide(); - // https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1 // https://www.rfc-editor.org/rfc/rfc6455.html#section-7.1.5 const isNormalOrUnsetCloseReason = @@ -296,10 +292,17 @@ function setHMRUnavailableReason(reason: string) { } hmrUnavailableReason = reason; + const DevLoadingView = require('./DevLoadingView').default; + DevLoadingView.hide(); + // We only want to show a warning if Fast Refresh is on *and* if we ever // previously managed to connect successfully. We don't want to show // the warning to native engineers who use cached bundles without Metro. if (hmrClient.isEnabled() && didConnect) { + DevLoadingView.showMessage( + 'Fast Refresh disconnected. Reload app to reconnect.', + 'error', + ); console.warn(reason); // (Not using the `warning` module to prevent a Buck cycle.) } diff --git a/packages/react-native/React/CoreModules/RCTDevLoadingView.mm b/packages/react-native/React/CoreModules/RCTDevLoadingView.mm index 3022f42447c0..3d866e91a40d 100644 --- a/packages/react-native/React/CoreModules/RCTDevLoadingView.mm +++ b/packages/react-native/React/CoreModules/RCTDevLoadingView.mm @@ -85,14 +85,6 @@ - (void)showInitialMessageDelayed:(void (^)())initialMessage dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), self->_initialMessageBlock); } -- (void)hideBannerAfter:(CGFloat)delay -{ - // Cancel previous hide call after the delay. - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hide) object:nil]; - // Set new hide call after a delay. - [self performSelector:@selector(hide) withObject:nil afterDelay:delay]; -} - - (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor { if (!RCTDevLoadingViewGetEnabled() || _hiding) { @@ -128,6 +120,9 @@ - (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:( self->_container = [[UIView alloc] init]; self->_container.backgroundColor = backgroundColor; self->_container.translatesAutoresizingMaskIntoConstraints = NO; + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)]; + [self->_container addGestureRecognizer:tapGesture]; + self->_container.userInteractionEnabled = YES; self->_label = [[UILabel alloc] init]; self->_label.translatesAutoresizingMaskIntoConstraints = NO; @@ -158,8 +153,6 @@ - (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:( [self->_label.centerXAnchor constraintEqualToAnchor:self->_container.centerXAnchor], [self->_label.bottomAnchor constraintEqualToAnchor:self->_container.bottomAnchor constant:-5], ]]; - - [self hideBannerAfter:15.0]; }); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DefaultDevLoadingViewImplementation.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DefaultDevLoadingViewImplementation.kt index 7e06ff82c4ce..ff366e685cf8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DefaultDevLoadingViewImplementation.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DefaultDevLoadingViewImplementation.kt @@ -33,10 +33,14 @@ public class DefaultDevLoadingViewImplementation( private var devLoadingPopup: PopupWindow? = null override fun showMessage(message: String) { + showMessage(message, color = null, backgroundColor = null) + } + + override fun showMessage(message: String, color: Double?, backgroundColor: Double?) { if (!isEnabled) { return } - UiThreadUtil.runOnUiThread { showInternal(message) } + UiThreadUtil.runOnUiThread { showInternal(message, color, backgroundColor) } } override fun updateProgress(status: String?, done: Int?, total: Int?) { @@ -59,7 +63,7 @@ public class DefaultDevLoadingViewImplementation( } } - private fun showInternal(message: String) { + private fun showInternal(message: String, color: Double?, backgroundColor: Double?) { if (devLoadingPopup?.isShowing == true) { // already showing return @@ -84,13 +88,19 @@ public class DefaultDevLoadingViewImplementation( currentActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater val view = inflater.inflate(R.layout.dev_loading_view, null) as TextView view.text = message + if (color != null) { + view.setTextColor(color.toInt()) + } + if (backgroundColor != null) { + view.setBackgroundColor(backgroundColor.toInt()) + } + view.setOnClickListener { hideInternal() } val popup = PopupWindow( view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, ) - popup.isTouchable = false popup.showAtLocation(currentActivity.window.decorView, Gravity.NO_GRAVITY, 0, topOffset) devLoadingView = view devLoadingPopup = popup diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevLoadingViewManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevLoadingViewManager.kt index 08d4757a4c5b..9366cfb3b300 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevLoadingViewManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevLoadingViewManager.kt @@ -11,6 +11,8 @@ package com.facebook.react.devsupport.interfaces public interface DevLoadingViewManager { public fun showMessage(message: String) + public fun showMessage(message: String, color: Double?, backgroundColor: Double?) + public fun updateProgress(status: String?, done: Int?, total: Int?) public fun hide() diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/devloading/DevLoadingModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/devloading/DevLoadingModule.kt index 7344fcdad8dd..78a3a84146d9 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/devloading/DevLoadingModule.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/devloading/DevLoadingModule.kt @@ -31,7 +31,9 @@ internal class DevLoadingModule(reactContext: ReactApplicationContext) : } override fun showMessage(message: String, color: Double?, backgroundColor: Double?) { - UiThreadUtil.runOnUiThread { devLoadingViewManager?.showMessage(message) } + UiThreadUtil.runOnUiThread { + devLoadingViewManager?.showMessage(message, color, backgroundColor) + } } override fun hide() {