move docs toggle to settings

This commit is contained in:
David Lechner
2021-01-14 10:55:00 -06:00
parent b6bda26484
commit b15b2e1dea
16 changed files with 93 additions and 257 deletions
-30
View File
@@ -1,30 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// File: sagas/app.ts
// Manages the application lifecycle.
import { put, select, takeEvery } from 'redux-saga/effects';
import {
AppActionType,
AppStartupAction,
AppToggleDocsAction,
toggleDocs,
} from '../actions/app';
import { RootState } from '../reducers';
function* handleStartup(_action: AppStartupAction): Generator {
const showDocs = localStorage.getItem('showDocs');
if (showDocs === null ? window.innerWidth >= 1024 : showDocs === 'true') {
yield put(toggleDocs());
}
}
function* storeDocsState(_action: AppToggleDocsAction): Generator {
const showDocs = (yield select((s: RootState) => s.app.showDocs)) as boolean;
localStorage.setItem('showDocs', String(showDocs));
}
export default function* (): Generator {
yield takeEvery(AppActionType.Startup, handleStartup);
yield takeEvery(AppActionType.ToggleDocs, storeDocsState);
}
-2
View File
@@ -3,7 +3,6 @@
import { all, put } from 'redux-saga/effects';
import { startup } from '../actions/app';
import app from './app';
import bleUart from './ble-uart';
import editor from './editor';
import errorLog from './error-log';
@@ -18,7 +17,6 @@ import terminal from './terminal';
/* istanbul ignore next */
export default function* (): Generator {
yield all([
app(),
bleUart(),
lwp3BootloaderBle(),
lwp3BootloaderProtocol(),
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// Copyright (c) 2020-2021 The Pybricks Authors
// File: sagas/app.test.ts
// Tests for app sagas.
import { AsyncSaga } from '../../test';
import { AppActionType, startup, toggleDocs } from '../actions/app';
import app from './app';
import { startup } from '../actions/app';
import { SettingsActionType, toggleDarkMode, toggleDocs } from '../actions/settings';
import settings from './settings';
afterAll(() => {
jest.restoreAllMocks();
@@ -13,7 +14,7 @@ afterAll(() => {
describe('startup', () => {
test('with large screen', async () => {
const saga = new AsyncSaga(app);
const saga = new AsyncSaga(settings);
jest.spyOn(
Object.getPrototypeOf(window.localStorage),
@@ -25,13 +26,13 @@ describe('startup', () => {
// toggles documentation to be visible
const toggleDocsAction = await saga.take();
expect(toggleDocsAction.type).toBe(AppActionType.ToggleDocs);
expect(toggleDocsAction.type).toBe(SettingsActionType.ToggleDocs);
await saga.end();
});
test('with small screen', async () => {
const saga = new AsyncSaga(app);
const saga = new AsyncSaga(settings);
jest.spyOn(
Object.getPrototypeOf(window.localStorage),
@@ -47,30 +48,30 @@ describe('startup', () => {
});
test('with stored value "true"', async () => {
const saga = new AsyncSaga(app);
const saga = new AsyncSaga(settings);
jest.spyOn(
Object.getPrototypeOf(window.localStorage),
'getItem',
).mockReturnValue('true');
).mockReturnValue('{"showDocs":true}');
innerWidth = 800;
saga.put(startup());
// toggles documentation to be visible
const toggleDocsAction = await saga.take();
expect(toggleDocsAction.type).toBe(AppActionType.ToggleDocs);
expect(toggleDocsAction.type).toBe(SettingsActionType.ToggleDocs);
await saga.end();
});
test('with stored value "false"', async () => {
const saga = new AsyncSaga(app);
const saga = new AsyncSaga(settings);
jest.spyOn(
Object.getPrototypeOf(window.localStorage),
'getItem',
).mockReturnValue('false');
).mockReturnValue('{"showDocs":false}');
innerWidth = 1024;
saga.put(startup());
@@ -81,28 +82,36 @@ describe('startup', () => {
});
});
describe('storeDocsState', () => {
test('showing', async () => {
const saga = new AsyncSaga(app);
describe('store settings to local storage', () => {
test('showDocs', async () => {
const saga = new AsyncSaga(settings);
// NOTE: we aren't testing reducers here, so value doesn't change
// even though we call the toggle function
const mockSetItem = jest
.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem')
.mockImplementation((_key, value) => expect(value).toBe('true'));
saga.setState({ app: { showSettings: false, showDocs: true } });
.mockImplementation((_key, value) =>
expect(value).toBe('{"darkMode":false,"showDocs":true}'),
);
saga.setState({ settings: { darkMode: false, showDocs: true } });
saga.put(toggleDocs());
expect(mockSetItem).toHaveBeenCalled();
await saga.end();
});
test('hidden', async () => {
const saga = new AsyncSaga(app);
test('darkMode', async () => {
const saga = new AsyncSaga(settings);
// NOTE: we aren't testing reducers here, so value doesn't change
// even though we call the toggle function
const mockSetItem = jest
.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem')
.mockImplementation((_key, value) => expect(value).toBe('false'));
saga.setState({ app: { showSettings: false, showDocs: false } });
saga.put(toggleDocs());
.mockImplementation((_key, value) =>
expect(value).toBe('{"darkMode":true,"showDocs":false}'),
);
saga.setState({ settings: { darkMode: true, showDocs: false } });
saga.put(toggleDarkMode());
expect(mockSetItem).toHaveBeenCalled();
await saga.end();
+12 -5
View File
@@ -1,17 +1,23 @@
import { put, select, takeEvery } from 'redux-saga/effects';
import { AppActionType } from '../actions/app';
import { SettingsActionType, toggleDarkMode } from '../actions/settings';
import { SettingsActionType, toggleDarkMode, toggleDocs } from '../actions/settings';
import { RootState } from '../reducers';
import { SettingsState } from '../reducers/settings';
function* loadSettings(): Generator {
const settingsString = localStorage.getItem('settings');
if (!settingsString) {
return;
}
const settingsString = localStorage.getItem('settings') || '{}';
const settings = JSON.parse(settingsString) as SettingsState;
// TODO: there has to be a better way to initialize app state from settings
if (
settings.showDocs === undefined
? window.innerWidth >= 1024
: settings.showDocs === true
) {
yield put(toggleDocs());
}
if (settings.darkMode) {
yield put(toggleDarkMode());
}
@@ -22,6 +28,7 @@ function* saveSettings(): Generator {
localStorage.setItem('settings', JSON.stringify(settings));
}
// TODO: this should really be part of component, not saga
function* updateDarkModeClass(): Generator {
const darkMode = (yield select((s: RootState) => s.settings.darkMode)) as boolean;
if (darkMode) {