Skip to content
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

Support changing position of LogBox #28795

Closed
wants to merge 4 commits into from
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
143 changes: 95 additions & 48 deletions Libraries/LogBox/LogBoxNotificationContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import * as React from 'react';
import StyleSheet from '../StyleSheet/StyleSheet';
import SafeAreaView from '../Components/SafeAreaView/SafeAreaView';
import View from '../Components/View/View';
import * as LogBoxData from './Data/LogBoxData';
import LogBoxLog from './Data/LogBoxLog';
Expand All @@ -23,71 +24,117 @@ type Props = $ReadOnly<{|
isDisabled?: ?boolean,
|}>;

const onDismissWarns = () => {
LogBoxData.clearWarnings();
};
const onDismissErrors = () => {
LogBoxData.clearErrors();
};

const setSelectedLog = (index: number): void => {
LogBoxData.setSelectedLog(index);
};

export function _LogBoxNotificationContainer(props: Props): React.Node {
const {logs} = props;

const onDismissWarns = () => {
LogBoxData.clearWarnings();
};
const onDismissErrors = () => {
LogBoxData.clearErrors();
};

const setSelectedLog = (index: number): void => {
LogBoxData.setSelectedLog(index);
};

function openLog(log: LogBoxLog) {
let index = logs.length - 1;

// Stop at zero because if we don't find any log, we'll open the first log.
while (index > 0 && logs[index] !== log) {
index -= 1;
}
setSelectedLog(index);
}
const [isWarnOnBottom, setIsWarnOnBottom] = React.useState(true);

if (logs.length === 0 || props.isDisabled === true) {
return null;
}
const toggleWarnPosition = React.useCallback((): void => {
setIsWarnOnBottom(!isWarnOnBottom);
}, [setIsWarnOnBottom, isWarnOnBottom]);

const [isErrorOnBottom, setIsErrorOnBottom] = React.useState(true);

const warnings = logs.filter(log => log.level === 'warn');
const errors = logs.filter(
log => log.level === 'error' || log.level === 'fatal',
const toggleErrorPosition = React.useCallback((): void => {
setIsErrorOnBottom(!isErrorOnBottom);
}, [setIsErrorOnBottom, isErrorOnBottom]);

const openLog = React.useCallback(
(log: LogBoxLog) => {
let index = logs.length - 1;

// Stop at zero because if we don't find any log, we'll open the first log.
while (index > 0 && logs[index] !== log) {
index -= 1;
}
setSelectedLog(index);
},
[logs],
);
return (
<View style={styles.list}>
{warnings.length > 0 && (
<View style={styles.toast}>
<LogBoxLogNotification
log={warnings[warnings.length - 1]}
level="warn"
totalLogCount={warnings.length}
onPressOpen={() => openLog(warnings[warnings.length - 1])}
onPressDismiss={onDismissWarns}
/>
</View>
)}
{errors.length > 0 && (

const renderLogBoxLogNotifications = React.useCallback(
(level, onDismiss, togglePosition, isOnBottom) => {
const filteredLogs = logs.filter(log => log.level === level);
if (filteredLogs.length === 0) {
return null;
}

return (
<View style={styles.toast}>
<LogBoxLogNotification
log={errors[errors.length - 1]}
level="error"
totalLogCount={errors.length}
onPressOpen={() => openLog(errors[errors.length - 1])}
onPressDismiss={onDismissErrors}
togglePosition={togglePosition}
isOnBottom={isOnBottom}
log={filteredLogs[filteredLogs.length - 1]}
level={level}
totalLogCount={filteredLogs.length}
onPressOpen={() => openLog(filteredLogs[filteredLogs.length - 1])}
onPressDismiss={onDismiss}
/>
</View>
)}
</View>
);
},
[logs, openLog],
);

const renderWarns = React.useCallback(
() =>
renderLogBoxLogNotifications(
'warn',
onDismissWarns,
toggleWarnPosition,
isWarnOnBottom,
),
[renderLogBoxLogNotifications, toggleWarnPosition, isWarnOnBottom],
);

const renderErrors = React.useCallback(
() =>
renderLogBoxLogNotifications(
'error',
onDismissErrors,
toggleErrorPosition,
isErrorOnBottom,
),
[renderLogBoxLogNotifications, toggleErrorPosition, isErrorOnBottom],
);

if (logs.length === 0 || props.isDisabled === true) {
return null;
}

return (
<SafeAreaView style={styles.list} pointerEvents="box-none">
<View>
{isWarnOnBottom || renderWarns()}
{isErrorOnBottom || renderErrors()}
</View>
<View>
{isWarnOnBottom && renderWarns()}
{isErrorOnBottom && renderErrors()}
</View>
</SafeAreaView>
);
}

const styles = StyleSheet.create({
list: {
bottom: 20,
left: 10,
flex: 1,
justifyContent: 'space-between',
right: 10,
top: 40,
bottom: 0,
position: 'absolute',
},
toast: {
Expand Down
Binary file added Libraries/LogBox/UI/LogBoxImages/chevron-bottom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Libraries/LogBox/UI/LogBoxImages/chevron-top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 39 additions & 4 deletions Libraries/LogBox/UI/LogBoxNotification.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type Props = $ReadOnly<{|
level: 'warn' | 'error',
onPressOpen: () => void,
onPressDismiss: () => void,
togglePosition: () => void,
isOnBottom: boolean,
|}>;

function LogBoxLogNotification(props: Props): React.Node {
Expand All @@ -49,6 +51,10 @@ function LogBoxLogNotification(props: Props): React.Node {
<View style={toastStyles.content}>
<CountBadge count={totalLogCount} level={level} />
<Message message={log.message} />
<ChangeLocationButton
onPress={props.togglePosition}
isOnBottom={props.isOnBottom}
/>
<DismissButton onPress={props.onPressDismiss} />
</View>
</LogBoxButton>
Expand Down Expand Up @@ -88,7 +94,7 @@ function Message(props) {

function DismissButton(props) {
return (
<View style={dismissStyles.container}>
<View style={buttonStyle.container}>
<LogBoxButton
backgroundColor={{
default: LogBoxStyle.getTextColor(0.3),
Expand All @@ -101,10 +107,39 @@ function DismissButton(props) {
left: 10,
}}
onPress={props.onPress}
style={dismissStyles.press}>
style={buttonStyle.press}>
<Image
source={require('./LogBoxImages/close.png')}
style={dismissStyles.image}
style={buttonStyle.image}
/>
</LogBoxButton>
</View>
);
}

const chevronTop = require('./LogBoxImages/chevron-top.png');
const chevronBottom = require('./LogBoxImages/chevron-bottom.png');

function ChangeLocationButton(props) {
const {isOnBottom} = props;
return (
<View style={buttonStyle.container}>
<LogBoxButton
backgroundColor={{
default: LogBoxStyle.getTextColor(0.3),
pressed: LogBoxStyle.getTextColor(0.5),
}}
hitSlop={{
top: 12,
right: 10,
bottom: 12,
left: 10,
}}
onPress={props.onPress}
style={buttonStyle.press}>
<Image
source={isOnBottom ? chevronTop : chevronBottom}
style={buttonStyle.image}
/>
</LogBoxButton>
</View>
Expand Down Expand Up @@ -167,7 +202,7 @@ const messageStyles = StyleSheet.create({
},
});

const dismissStyles = StyleSheet.create({
const buttonStyle = StyleSheet.create({
container: {
alignSelf: 'center',
flexDirection: 'row',
Expand Down
2 changes: 2 additions & 0 deletions Libraries/LogBox/UI/__tests__/LogBoxNotification-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ describe('LogBoxNotification', () => {
it('should render log', () => {
const output = render.shallowRender(
<LogBoxNotification
isOnBottom
togglePosition={() => {}}
log={log}
totalLogCount={1}
level="warn"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ exports[`LogBoxNotification should render log 1`] = `
}
}
/>
<ChangeLocationButton
isOnBottom={true}
onPress={[Function]}
/>
<DismissButton
onPress={[Function]}
/>
Expand Down
Loading