diff --git a/locales/en-US/app.ftl b/locales/en-US/app.ftl index 9eb89ea769..a570c871a8 100644 --- a/locales/en-US/app.ftl +++ b/locales/en-US/app.ftl @@ -1189,6 +1189,14 @@ BottomBox--assembly-code-not-available-title = Assembly code not available BottomBox--assembly-code-not-available-text = See issue #4520 for supported scenarios and planned improvements. +# The toggle button for making the bottom box fullscreen. +BottomBox--hide-fullscreen = + .title = Exit fullscreen + +# The toggle button for making the bottom box fullscreen. +BottomBox--show-fullscreen = + .title = Show fullscreen + SourceView--close-button = .title = Close the source view diff --git a/res/img/svg/fullscreen-exit.svg b/res/img/svg/fullscreen-exit.svg new file mode 100644 index 0000000000..2843b49fae --- /dev/null +++ b/res/img/svg/fullscreen-exit.svg @@ -0,0 +1,6 @@ + + + + diff --git a/res/img/svg/fullscreen.svg b/res/img/svg/fullscreen.svg new file mode 100644 index 0000000000..ce460de24e --- /dev/null +++ b/res/img/svg/fullscreen.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/actions/profile-view.ts b/src/actions/profile-view.ts index 47c50d4017..da8de19651 100644 --- a/src/actions/profile-view.ts +++ b/src/actions/profile-view.ts @@ -1959,6 +1959,14 @@ export function closeBottomBox(): ThunkAction { }; } +export function toggleBottomBoxFullscreen(): ThunkAction { + return (dispatch) => { + dispatch({ + type: 'TOGGLE_BOTTOM_BOX_FULLSCREEN', + }); + }; +} + export function handleCallNodeTransformShortcut( event: React.KeyboardEvent, threadsKey: ThreadsKey, diff --git a/src/app-logic/url-handling.ts b/src/app-logic/url-handling.ts index de0818abe4..e26d23e208 100644 --- a/src/app-logic/url-handling.ts +++ b/src/app-logic/url-handling.ts @@ -211,6 +211,7 @@ type Query = BaseQuery & { transforms?: string; sourceViewIndex?: number; assemblyView?: string; + bottomFullscreen?: boolean; // StackChart specific showUserTimings?: null | undefined; @@ -346,8 +347,12 @@ export function getQueryStringFromUrlState(urlState: UrlState): string { 'timing' ? undefined : urlState.profileSpecific.lastSelectedCallTreeSummaryStrategy; - const { sourceView, assemblyView, isBottomBoxOpenPerPanel } = - urlState.profileSpecific; + const { + sourceView, + assemblyView, + isBottomBoxOpenPerPanel, + isBottomBoxFullscreen, + } = urlState.profileSpecific; if (isBottomBoxOpenPerPanel[selectedTab]) { if (sourceView.sourceIndex !== null) { @@ -358,6 +363,9 @@ export function getQueryStringFromUrlState(urlState: UrlState): string { assemblyView.nativeSymbol ); } + if (isBottomBoxFullscreen) { + query.bottomFullscreen = true; + } } break; } @@ -564,6 +572,7 @@ export function stateFromLocation( sourceView, assemblyView, isBottomBoxOpenPerPanel, + isBottomBoxFullscreen: query.bottomFullscreen || false, timelineType: validateTimelineType(query.timelineType), showJsTracerSummary: query.summary === undefined ? false : true, globalTrackOrder: convertGlobalTrackOrderFromString( diff --git a/src/components/app/BottomBox.css b/src/components/app/BottomBox.css index 683dce9a99..c56a3b2bc0 100644 --- a/src/components/app/BottomBox.css +++ b/src/components/app/BottomBox.css @@ -2,6 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +.bottom-box-fullscreen { + position: fixed; + z-index: 100; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + .bottom-box-pane { display: flex; height: 100%; /* direct child of SplitterLayout */ @@ -62,7 +71,9 @@ } .bottom-close-button, -.bottom-assembly-button { +.bottom-assembly-button, +.bottom-fullscreen-hide-button, +.bottom-fullscreen-show-button { width: 24px; height: 24px; flex-shrink: 0; @@ -79,6 +90,14 @@ background-image: url(../../../res/img/svg/asm-icon.svg); } +.bottom-fullscreen-show-button { + background-image: url(firefox-profiler-res/img/svg/fullscreen.svg); +} + +.bottom-fullscreen-hide-button { + background-image: url(firefox-profiler-res/img/svg/fullscreen-exit.svg); +} + .codeLoadingOverlay, .sourceCodeErrorOverlay, .assemblyCodeErrorOverlay { diff --git a/src/components/app/BottomBox.tsx b/src/components/app/BottomBox.tsx index c2631c42fb..62808ea37a 100644 --- a/src/components/app/BottomBox.tsx +++ b/src/components/app/BottomBox.tsx @@ -8,6 +8,7 @@ import classNames from 'classnames'; import { SourceView } from '../shared/SourceView'; import { AssemblyView } from '../shared/AssemblyView'; +import { FullscreenToggleButton } from './FullscreenToggleButton'; import { AssemblyViewToggleButton } from './AssemblyViewToggleButton'; import { IonGraphView } from '../shared/IonGraphView'; import { CodeLoadingOverlay } from './CodeLoadingOverlay'; @@ -18,12 +19,16 @@ import { getAssemblyViewIsOpen, getAssemblyViewNativeSymbol, getAssemblyViewScrollGeneration, + getIsBottomBoxFullscreen, } from 'firefox-profiler/selectors/url-state'; import { selectedThreadSelectors, selectedNodeSelectors, } from 'firefox-profiler/selectors/per-thread'; -import { closeBottomBox } from 'firefox-profiler/actions/profile-view'; +import { + closeBottomBox, + toggleBottomBoxFullscreen, +} from 'firefox-profiler/actions/profile-view'; import { parseFileNameFromSymbolication } from 'firefox-profiler/utils/special-paths'; import { getSourceViewCode, @@ -52,6 +57,7 @@ import { Localized } from '@fluent/react'; import './BottomBox.css'; type StateProps = { + readonly isFullscreen: boolean; readonly sourceViewFile: string | null; readonly sourceViewCode: SourceCodeStatus | void; readonly sourceViewScrollGeneration: number; @@ -69,6 +75,7 @@ type StateProps = { type DispatchProps = { readonly closeBottomBox: typeof closeBottomBox; + readonly toggleBottomBoxFullscreen: typeof toggleBottomBoxFullscreen; }; type Props = ConnectedProps<{}, StateProps, DispatchProps>; @@ -151,12 +158,31 @@ class BottomBoxImpl extends React.PureComponent { _sourceView = React.createRef(); _assemblyView = React.createRef(); + override componentDidMount() { + document.addEventListener('keydown', this._onKeyDown); + } + + override componentWillUnmount() { + document.removeEventListener('keydown', this._onKeyDown); + } + + _onKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape' && this.props.isFullscreen) { + this.props.toggleBottomBoxFullscreen(); + } + }; + _onClickCloseButton = () => { this.props.closeBottomBox(); + // Close the fullscreen if we're closing the bottom box + if (this.props.isFullscreen) { + this.props.toggleBottomBoxFullscreen(); + } }; override render() { const { + isFullscreen, sourceViewFile, sourceViewCode, globalLineTimings, @@ -196,6 +222,7 @@ class BottomBoxImpl extends React.PureComponent { const trailingHeaderButtons = (
+