diff --git a/lib/gui/app/components/progress-button/progress-button.tsx b/lib/gui/app/components/progress-button/progress-button.tsx index 97d9d2a2..541e98f3 100644 --- a/lib/gui/app/components/progress-button/progress-button.tsx +++ b/lib/gui/app/components/progress-button/progress-button.tsx @@ -15,15 +15,16 @@ */ import * as React from 'react'; -import { ProgressBar } from 'rendition'; +import { Button, Flex, ProgressBar, Txt } from 'rendition'; import { default as styled } from 'styled-components'; +import { fromFlashState } from '../../modules/progress-status'; import { StepButton } from '../../styled-components'; const FlashProgressBar = styled(ProgressBar)` > div { - width: 200px; - height: 48px; + width: 220px; + height: 12px; color: white !important; text-shadow: none !important; transition-duration: 0s; @@ -32,8 +33,9 @@ const FlashProgressBar = styled(ProgressBar)` } } - width: 200px; - height: 48px; + width: 220px; + height: 12px; + border-radius: 14px; font-size: 16px; line-height: 48px; @@ -44,8 +46,9 @@ interface ProgressButtonProps { type: 'decompressing' | 'flashing' | 'verifying'; active: boolean; percentage: number; - label: string; + position: number; disabled: boolean; + cancel: () => void; callback: () => void; } @@ -55,16 +58,41 @@ const colors = { verifying: '#1ac135', } as const; +const CancelButton = styled((props) => ( + +))` + font-weight: 600; + &&& { + width: auto; + height: auto; + font-size: 14px; + } +`; + export class ProgressButton extends React.PureComponent { public render() { + const { status, position } = fromFlashState({ + type: this.props.type, + position: this.props.position, + percentage: this.props.percentage, + }); if (this.props.active) { return ( - - {this.props.label} - +
+ + + {status}  + {position} + + + + +
); } return ( @@ -73,7 +101,7 @@ export class ProgressButton extends React.PureComponent { onClick={this.props.callback} disabled={this.props.disabled} > - {this.props.label} + Flash! ); } diff --git a/lib/gui/app/modules/progress-status.ts b/lib/gui/app/modules/progress-status.ts index 5120c692..4dcf9780 100644 --- a/lib/gui/app/modules/progress-status.ts +++ b/lib/gui/app/modules/progress-status.ts @@ -25,56 +25,53 @@ export interface FlashState { type?: 'decompressing' | 'flashing' | 'verifying'; } -/** - * @summary Make the progress status subtitle string - * - * @param {Object} state - flashing metadata - * - * @returns {String} - * - * @example - * const status = progressStatus.fromFlashState({ - * type: 'flashing' - * active: 1, - * failed: 0, - * percentage: 55, - * speed: 2049, - * }) - * - * console.log(status) - * // '55% Flashing' - */ export function fromFlashState({ type, percentage, position, -}: Pick): string { +}: Pick): { + status: string; + position?: string; +} { if (type === undefined) { - return 'Starting...'; + return { status: 'Starting...' }; } else if (type === 'decompressing') { if (percentage == null) { - return 'Decompressing...'; + return { status: 'Decompressing...' }; } else { - return `${percentage}% Decompressing`; + return { position: `${percentage}%`, status: 'Decompressing...' }; } } else if (type === 'flashing') { if (percentage != null) { if (percentage < 100) { - return `${percentage}% Flashing`; + return { position: `${percentage}%`, status: 'Flashing...' }; } else { - return 'Finishing...'; + return { status: 'Finishing...' }; } } else { - return `${bytesToClosestUnit(position)} flashed`; + return { + status: 'Flashing...', + position: `${bytesToClosestUnit(position)}`, + }; } } else if (type === 'verifying') { if (percentage == null) { - return 'Validating...'; + return { status: 'Validating...' }; } else if (percentage < 100) { - return `${percentage}% Validating`; + return { position: `${percentage}%`, status: 'Validating...' }; } else { - return 'Finishing...'; + return { status: 'Finishing...' }; } } - return 'Failed'; + return { status: 'Failed' }; +} + +export function titleFromFlashState( + state: Pick, +): string { + const { status, position } = fromFlashState(state); + if (position !== undefined) { + return `${position} ${status}`; + } + return status; } diff --git a/lib/gui/app/os/window-progress.ts b/lib/gui/app/os/window-progress.ts index 443fee7e..bd64bf63 100644 --- a/lib/gui/app/os/window-progress.ts +++ b/lib/gui/app/os/window-progress.ts @@ -17,7 +17,7 @@ import * as electron from 'electron'; import { percentageToFloat } from '../../../shared/utils'; -import { FlashState, fromFlashState } from '../modules/progress-status'; +import { FlashState, titleFromFlashState } from '../modules/progress-status'; /** * @summary The title of the main window upon program launch @@ -29,7 +29,7 @@ const INITIAL_TITLE = document.title; */ function getWindowTitle(state?: FlashState) { if (state) { - return `${INITIAL_TITLE} – ${fromFlashState(state)}`; + return `${INITIAL_TITLE} – ${titleFromFlashState(state)}`; } return INITIAL_TITLE; } diff --git a/lib/gui/app/pages/main/Flash.tsx b/lib/gui/app/pages/main/Flash.tsx index d88024aa..3dee4137 100644 --- a/lib/gui/app/pages/main/Flash.tsx +++ b/lib/gui/app/pages/main/Flash.tsx @@ -14,13 +14,10 @@ * limitations under the License. */ -import { faTimes } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import * as _ from 'lodash'; import * as path from 'path'; import * as React from 'react'; -import { Button, Modal, Txt } from 'rendition'; -import styled from 'styled-components'; +import { Flex, Modal, Txt } from 'rendition'; import * as constraints from '../../../../shared/drive-constraints'; import * as messages from '../../../../shared/messages'; @@ -34,7 +31,6 @@ import * as selection from '../../models/selection-state'; import * as analytics from '../../modules/analytics'; import { scanner as driveScanner } from '../../modules/drive-scanner'; import * as imageWriter from '../../modules/image-writer'; -import * as progressStatus from '../../modules/progress-status'; import * as notification from '../../os/notification'; const COMPLETED_PERCENTAGE = 100; @@ -132,20 +128,6 @@ async function flashImageToDrive( return ''; } -const getProgressButtonLabel = ( - isFlashing: boolean, - // TODO: factorize - type: 'decompressing' | 'flashing' | 'verifying', - position: number, - percentage?: number, -) => { - // TODO - if (!isFlashing) { - return 'Flash!'; - } - return progressStatus.fromFlashState({ type, position, percentage }); -}; - const formatSeconds = (totalSeconds: number) => { if (!totalSeconds && !_.isNumber(totalSeconds)) { return ''; @@ -156,12 +138,6 @@ const formatSeconds = (totalSeconds: number) => { return `${minutes}m${seconds}s`; }; -const IconButton = styled(Button)` - && { - width: 20px; - } -`; - interface FlashStepProps { shouldFlashStepBeDisabled: boolean; goToSuccess: () => void; @@ -260,44 +236,33 @@ export class FlashStep extends React.PureComponent< /> -
+
{ this.tryFlash(); }} /> - {this.props.isFlashing && ( - } - plain - onClick={imageWriter.cancel} - color="#fff" - hoverIndicator={{ dark: true }} - /> - )} {!_.isNil(this.props.speed) && this.props.percentage !== COMPLETED_PERCENTAGE && ( -

- {Boolean(this.props.speed) && ( - {`${this.props.speed.toFixed( - SPEED_PRECISION, - )} MB/s`} + + {!_.isNil(this.props.speed) && ( + {this.props.speed.toFixed(SPEED_PRECISION)} MB/s )} {!_.isNil(this.props.eta) && ( - {`ETA: ${formatSeconds(this.props.eta)}`} + ETA: {formatSeconds(this.props.eta)} )} -

+ )} {Boolean(this.props.failed) && ( diff --git a/lib/gui/app/pages/main/styles/_main.scss b/lib/gui/app/pages/main/styles/_main.scss index b4fffc1f..4de0fce8 100644 --- a/lib/gui/app/pages/main/styles/_main.scss +++ b/lib/gui/app/pages/main/styles/_main.scss @@ -28,101 +28,10 @@ img[disabled] { height: 165px; } -.page-main .step-selection-text { - display: flex; - flex-wrap: wrap; - justify-content: center; - color: $palette-theme-dark-foreground; -} - -.page-main .text-disabled > span { - color: $palette-theme-dark-disabled-foreground; -} - -.page-main .step-drive.text-warning { - color: $palette-theme-warning-background; -} - .page-main .relative { position: relative; } -.page-main .button-abort-write { - width: 20px; - height: 20px; - margin: 0; - padding: 0; - font-size: 16px; - position: absolute; - right: -17px; - top: 30%; -} - -.button-brick { - width: 200px; - height: 48px; - font-size: 16px; - font-weight: 300; -} - -.page-main .step-tooltip { - display: block; - margin: -5px auto -20px; - color: $palette-theme-dark-disabled-foreground; - font-size: 10px; -} - -.page-main .step-footer { - width: 100%; - color: $palette-theme-dark-disabled-foreground; - font-size: 10px; -} - -.page-main p.step-footer { - margin-top: 9px; -} - -.page-main .step-footer-split { - position: absolute; - top: 39px; - left: 28px; - margin-left: auto; - margin-right: auto; - display: flex; - justify-content: space-between; - width: $btn-min-width; -} - -.page-main .button.step-footer { - font-size: 16px; - color: $palette-theme-primary-background; - border-radius: 0; - padding: 0; - width: 100%; - font-weight: 300; - height: 21px; -} - -.page-main .step-drive.glyphicon { - margin-top: 1px; -} - -.page-main div.step-fill, -.page-main span.step-fill { - margin-top: 25px; -} - -.page-main .step-drive.step-list { - &::-webkit-scrollbar { - width: 4px; - } - - &::-webkit-scrollbar-thumb { - background-color: $palette-theme-dark-disabled-foreground; - border-radius: 4px; - } -} - .page-main .glyphicon { vertical-align: text-top; } @@ -137,22 +46,6 @@ img[disabled] { color: $palette-theme-primary-foreground; } -.page-main .step-size { - color: $palette-theme-dark-disabled-foreground; - margin: 0 0 8px 0; - font-size: 16px; - line-height: normal; - height: 21px; - width: 100%; -} - -.page-main .step-list { - height: 80px; - margin: 15px; - overflow-y: auto; - color: $palette-theme-dark-disabled-foreground; -} - .target-status-wrap { display: flex; position: absolute; @@ -191,10 +84,6 @@ img[disabled] { } } -.tooltip-inner { - white-space: pre-line; -} - .space-vertical-large { position: relative; } diff --git a/tests/gui/modules/progress-status.spec.ts b/tests/gui/modules/progress-status.spec.ts index f91509d9..c337d82c 100644 --- a/tests/gui/modules/progress-status.spec.ts +++ b/tests/gui/modules/progress-status.spec.ts @@ -20,7 +20,7 @@ import * as settings from '../../../lib/gui/app/models/settings'; import * as progressStatus from '../../../lib/gui/app/modules/progress-status'; describe('Browser: progressStatus', function () { - describe('.fromFlashState()', function () { + describe('.titleFromFlashState()', function () { beforeEach(function () { this.state = { active: 1, @@ -36,25 +36,31 @@ describe('Browser: progressStatus', function () { }); it('should report 0% if percentage == 0 but speed != 0', function () { - expect(progressStatus.fromFlashState(this.state)).to.equal('0% Flashing'); + expect(progressStatus.titleFromFlashState(this.state)).to.equal( + '0% Flashing...', + ); }); it('should handle percentage == 0, flashing, unmountOnSuccess', function () { this.state.speed = 0; - expect(progressStatus.fromFlashState(this.state)).to.equal('0% Flashing'); + expect(progressStatus.titleFromFlashState(this.state)).to.equal( + '0% Flashing...', + ); }); it('should handle percentage == 0, flashing, !unmountOnSuccess', function () { this.state.speed = 0; settings.set('unmountOnSuccess', false); - expect(progressStatus.fromFlashState(this.state)).to.equal('0% Flashing'); + expect(progressStatus.titleFromFlashState(this.state)).to.equal( + '0% Flashing...', + ); }); it('should handle percentage == 0, verifying, unmountOnSuccess', function () { this.state.speed = 0; this.state.type = 'verifying'; - expect(progressStatus.fromFlashState(this.state)).to.equal( - '0% Validating', + expect(progressStatus.titleFromFlashState(this.state)).to.equal( + '0% Validating...', ); }); @@ -62,31 +68,31 @@ describe('Browser: progressStatus', function () { this.state.speed = 0; this.state.type = 'verifying'; settings.set('unmountOnSuccess', false); - expect(progressStatus.fromFlashState(this.state)).to.equal( - '0% Validating', + expect(progressStatus.titleFromFlashState(this.state)).to.equal( + '0% Validating...', ); }); it('should handle percentage == 50, flashing, unmountOnSuccess', function () { this.state.percentage = 50; - expect(progressStatus.fromFlashState(this.state)).to.equal( - '50% Flashing', + expect(progressStatus.titleFromFlashState(this.state)).to.equal( + '50% Flashing...', ); }); it('should handle percentage == 50, flashing, !unmountOnSuccess', function () { this.state.percentage = 50; settings.set('unmountOnSuccess', false); - expect(progressStatus.fromFlashState(this.state)).to.equal( - '50% Flashing', + expect(progressStatus.titleFromFlashState(this.state)).to.equal( + '50% Flashing...', ); }); it('should handle percentage == 50, verifying, unmountOnSuccess', function () { this.state.percentage = 50; this.state.type = 'verifying'; - expect(progressStatus.fromFlashState(this.state)).to.equal( - '50% Validating', + expect(progressStatus.titleFromFlashState(this.state)).to.equal( + '50% Validating...', ); }); @@ -94,14 +100,14 @@ describe('Browser: progressStatus', function () { this.state.percentage = 50; this.state.type = 'verifying'; settings.set('unmountOnSuccess', false); - expect(progressStatus.fromFlashState(this.state)).to.equal( - '50% Validating', + expect(progressStatus.titleFromFlashState(this.state)).to.equal( + '50% Validating...', ); }); it('should handle percentage == 100, flashing, unmountOnSuccess, validateWriteOnSuccess', function () { this.state.percentage = 100; - expect(progressStatus.fromFlashState(this.state)).to.equal( + expect(progressStatus.titleFromFlashState(this.state)).to.equal( 'Finishing...', ); }); @@ -109,7 +115,7 @@ describe('Browser: progressStatus', function () { it('should handle percentage == 100, flashing, unmountOnSuccess, !validateWriteOnSuccess', function () { this.state.percentage = 100; settings.set('validateWriteOnSuccess', false); - expect(progressStatus.fromFlashState(this.state)).to.equal( + expect(progressStatus.titleFromFlashState(this.state)).to.equal( 'Finishing...', ); }); @@ -118,7 +124,7 @@ describe('Browser: progressStatus', function () { this.state.percentage = 100; settings.set('unmountOnSuccess', false); settings.set('validateWriteOnSuccess', false); - expect(progressStatus.fromFlashState(this.state)).to.equal( + expect(progressStatus.titleFromFlashState(this.state)).to.equal( 'Finishing...', ); }); @@ -126,7 +132,7 @@ describe('Browser: progressStatus', function () { it('should handle percentage == 100, verifying, unmountOnSuccess', function () { this.state.percentage = 100; this.state.type = 'verifying'; - expect(progressStatus.fromFlashState(this.state)).to.equal( + expect(progressStatus.titleFromFlashState(this.state)).to.equal( 'Finishing...', ); }); @@ -134,7 +140,7 @@ describe('Browser: progressStatus', function () { it('should handle percentage == 100, validatinf, !unmountOnSuccess', function () { this.state.percentage = 100; settings.set('unmountOnSuccess', false); - expect(progressStatus.fromFlashState(this.state)).to.equal( + expect(progressStatus.titleFromFlashState(this.state)).to.equal( 'Finishing...', ); }); diff --git a/tests/gui/os/window-progress.spec.ts b/tests/gui/os/window-progress.spec.ts index bff8b1b3..4f011cb4 100644 --- a/tests/gui/os/window-progress.spec.ts +++ b/tests/gui/os/window-progress.spec.ts @@ -74,20 +74,20 @@ describe('Browser: WindowProgress', function () { it('should set the flashing title', function () { windowProgress.set(this.state); - assert.calledWith(this.setTitleSpy, ' – 85% Flashing'); + assert.calledWith(this.setTitleSpy, ' – 85% Flashing...'); }); it('should set the verifying title', function () { this.state.type = 'verifying'; windowProgress.set(this.state); - assert.calledWith(this.setTitleSpy, ' – 85% Validating'); + assert.calledWith(this.setTitleSpy, ' – 85% Validating...'); }); it('should set the starting title', function () { this.state.percentage = 0; this.state.speed = 0; windowProgress.set(this.state); - assert.calledWith(this.setTitleSpy, ' – 0% Flashing'); + assert.calledWith(this.setTitleSpy, ' – 0% Flashing...'); }); it('should set the finishing title', function () {