You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-10 22:11:50 +02:00
This commit is contained in:
@@ -4,7 +4,7 @@ import appReducer, { createAppDefaultState } from './app.reducer';
|
|||||||
describe('app.reducer', () => {
|
describe('app.reducer', () => {
|
||||||
|
|
||||||
it('should handle DIALOG_OPEN', async () => {
|
it('should handle DIALOG_OPEN', async () => {
|
||||||
const state: AppState = createAppDefaultState({}, {});
|
const state: AppState = createAppDefaultState({});
|
||||||
|
|
||||||
let newState = appReducer(state, {
|
let newState = appReducer(state, {
|
||||||
type: 'DIALOG_OPEN',
|
type: 'DIALOG_OPEN',
|
||||||
@@ -49,7 +49,7 @@ describe('app.reducer', () => {
|
|||||||
|
|
||||||
it('showing a dialog in one window should hide dialogs with the same ID in background windows', () => {
|
it('showing a dialog in one window should hide dialogs with the same ID in background windows', () => {
|
||||||
const state: AppState = {
|
const state: AppState = {
|
||||||
...createAppDefaultState({}, {}),
|
...createAppDefaultState({}),
|
||||||
backgroundWindows: {
|
backgroundWindows: {
|
||||||
testWindow: {
|
testWindow: {
|
||||||
...createAppDefaultWindowState(),
|
...createAppDefaultWindowState(),
|
||||||
|
@@ -54,8 +54,6 @@ export interface AppState extends State, AppWindowState {
|
|||||||
route: AppStateRoute;
|
route: AppStateRoute;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
navHistory: any[];
|
navHistory: any[];
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
|
||||||
windowContentSize: any;
|
|
||||||
watchedNoteFiles: string[];
|
watchedNoteFiles: string[];
|
||||||
lastEditorScrollPercents: EditorScrollPercents;
|
lastEditorScrollPercents: EditorScrollPercents;
|
||||||
focusedField: string;
|
focusedField: string;
|
||||||
@@ -81,7 +79,7 @@ export const createAppDefaultWindowState = (): AppWindowState => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
export function createAppDefaultState(windowContentSize: any, resourceEditWatcherDefaultState: any): AppState {
|
export function createAppDefaultState(resourceEditWatcherDefaultState: any): AppState {
|
||||||
return {
|
return {
|
||||||
...defaultState,
|
...defaultState,
|
||||||
...createAppDefaultWindowState(),
|
...createAppDefaultWindowState(),
|
||||||
@@ -91,7 +89,6 @@ export function createAppDefaultState(windowContentSize: any, resourceEditWatche
|
|||||||
props: {},
|
props: {},
|
||||||
},
|
},
|
||||||
navHistory: [],
|
navHistory: [],
|
||||||
windowContentSize, // bridge().windowContentSize(),
|
|
||||||
watchedNoteFiles: [],
|
watchedNoteFiles: [],
|
||||||
lastEditorScrollPercents: {},
|
lastEditorScrollPercents: {},
|
||||||
visibleDialogs: {}, // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
|
visibleDialogs: {}, // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
|
||||||
@@ -166,12 +163,6 @@ export default function(state: AppState, action: any) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'WINDOW_CONTENT_SIZE_SET':
|
|
||||||
|
|
||||||
newState = { ...state };
|
|
||||||
newState.windowContentSize = action.size;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'NOTE_VISIBLE_PANES_TOGGLE':
|
case 'NOTE_VISIBLE_PANES_TOGGLE':
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@@ -65,10 +65,7 @@ const pluginClasses = [
|
|||||||
require('./plugins/GotoAnything').default,
|
require('./plugins/GotoAnything').default,
|
||||||
];
|
];
|
||||||
|
|
||||||
const appDefaultState = createAppDefaultState(
|
const appDefaultState = createAppDefaultState(resourceEditWatcherDefaultState);
|
||||||
bridge().windowContentSize(),
|
|
||||||
resourceEditWatcherDefaultState,
|
|
||||||
);
|
|
||||||
|
|
||||||
class Application extends BaseApplication {
|
class Application extends BaseApplication {
|
||||||
|
|
||||||
|
@@ -313,13 +313,6 @@ export class Bridge {
|
|||||||
return new BrowserWindow(options);
|
return new BrowserWindow(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: This provides the size of the main window. Prefer CSS where possible.
|
|
||||||
public windowContentSize() {
|
|
||||||
if (!this.mainWindow()) return { width: 0, height: 0 };
|
|
||||||
const s = this.mainWindow().getContentSize();
|
|
||||||
return { width: s[0], height: s[1] };
|
|
||||||
}
|
|
||||||
|
|
||||||
public windowSetSize(width: number, height: number) {
|
public windowSetSize(width: number, height: number) {
|
||||||
if (!this.mainWindow()) return;
|
if (!this.mainWindow()) return;
|
||||||
return this.mainWindow().setSize(width, height);
|
return this.mainWindow().setSize(width, height);
|
||||||
|
@@ -38,7 +38,7 @@ describe('exportDeletionLog', () => {
|
|||||||
let state: AppState = undefined;
|
let state: AppState = undefined;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
state = createAppDefaultState({}, {});
|
state = createAppDefaultState({});
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
jest.setSystemTime(new Date('2024-09-18T12:00:00Z').getTime());
|
jest.setSystemTime(new Date('2024-09-18T12:00:00Z').getTime());
|
||||||
});
|
});
|
||||||
|
@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
|
|||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
import { AppState, AppStateRoute } from '../app.reducer';
|
import { AppState, AppStateRoute } from '../app.reducer';
|
||||||
import bridge from '../services/bridge';
|
import bridge from '../services/bridge';
|
||||||
import { useContext, useEffect, useMemo, useRef } from 'react';
|
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { WindowIdContext } from './NewWindowOrIFrame';
|
import { WindowIdContext } from './NewWindowOrIFrame';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of code from before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of code from before rule was applied
|
||||||
@@ -55,26 +55,44 @@ const useWindowRefocusManager = (route: AppStateRoute) => {
|
|||||||
}, [routeName, windowId]);
|
}, [routeName, windowId]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useContainerSize = (container: HTMLElement|null) => {
|
||||||
|
const [size, setSize] = useState({ width: container?.clientWidth, height: container?.clientHeight });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!container) return () => {};
|
||||||
|
|
||||||
|
const observer = new ResizeObserver(() => {
|
||||||
|
setSize({
|
||||||
|
width: container.clientWidth,
|
||||||
|
height: container.clientHeight,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
observer.observe(container);
|
||||||
|
return () => {
|
||||||
|
observer.disconnect();
|
||||||
|
};
|
||||||
|
}, [container]);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
};
|
||||||
|
|
||||||
const NavigatorComponent: React.FC<Props> = props => {
|
const NavigatorComponent: React.FC<Props> = props => {
|
||||||
const route = props.route;
|
const route = props.route;
|
||||||
const screenInfo = props.screens[route?.routeName];
|
const screenInfo = props.screens[route?.routeName];
|
||||||
|
const [container, setContainer] = useState<HTMLElement|null>(null);
|
||||||
|
|
||||||
useWindowTitleManager(screenInfo);
|
useWindowTitleManager(screenInfo);
|
||||||
useWindowRefocusManager(route);
|
useWindowRefocusManager(route);
|
||||||
|
const size = useContainerSize(container);
|
||||||
|
|
||||||
if (!route) throw new Error('Route must not be null');
|
if (!route) throw new Error('Route must not be null');
|
||||||
|
|
||||||
const screenProps = route.props ? route.props : {};
|
const screenProps = route.props ? route.props : {};
|
||||||
const Screen = screenInfo.screen;
|
const Screen = screenInfo.screen;
|
||||||
|
|
||||||
const screenStyle = {
|
|
||||||
width: props.style.width,
|
|
||||||
height: props.style.height,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={props.style} className={props.className}>
|
<div ref={setContainer} style={props.style} className={props.className}>
|
||||||
<Screen style={screenStyle} {...screenProps} />
|
<Screen style={size} {...screenProps} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -8,13 +8,11 @@ import OneDriveLoginScreen from './OneDriveLoginScreen';
|
|||||||
import DropboxLoginScreen from './DropboxLoginScreen';
|
import DropboxLoginScreen from './DropboxLoginScreen';
|
||||||
import ErrorBoundary from './ErrorBoundary';
|
import ErrorBoundary from './ErrorBoundary';
|
||||||
import { themeStyle } from '@joplin/lib/theme';
|
import { themeStyle } from '@joplin/lib/theme';
|
||||||
import { Size } from './ResizableLayout/utils/types';
|
|
||||||
import MenuBar from './MenuBar';
|
import MenuBar from './MenuBar';
|
||||||
import { _ } from '@joplin/lib/locale';
|
import { _ } from '@joplin/lib/locale';
|
||||||
const { createRoot } = require('react-dom/client');
|
const { createRoot } = require('react-dom/client');
|
||||||
const { connect, Provider } = require('react-redux');
|
const { connect, Provider } = require('react-redux');
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
import shim from '@joplin/lib/shim';
|
|
||||||
import ClipperServer from '@joplin/lib/ClipperServer';
|
import ClipperServer from '@joplin/lib/ClipperServer';
|
||||||
import DialogTitle from './DialogTitle';
|
import DialogTitle from './DialogTitle';
|
||||||
import DialogButtonRow, { ButtonSpec, ClickEvent, ClickEventHandler } from './DialogButtonRow';
|
import DialogButtonRow, { ButtonSpec, ClickEvent, ClickEventHandler } from './DialogButtonRow';
|
||||||
@@ -28,7 +26,6 @@ import JoplinCloudLoginScreen from './JoplinCloudLoginScreen';
|
|||||||
import InteropService from '@joplin/lib/services/interop/InteropService';
|
import InteropService from '@joplin/lib/services/interop/InteropService';
|
||||||
import WindowCommandsAndDialogs from './WindowCommandsAndDialogs/WindowCommandsAndDialogs';
|
import WindowCommandsAndDialogs from './WindowCommandsAndDialogs/WindowCommandsAndDialogs';
|
||||||
import { defaultWindowId, stateUtils, WindowState } from '@joplin/lib/reducer';
|
import { defaultWindowId, stateUtils, WindowState } from '@joplin/lib/reducer';
|
||||||
import bridge from '../services/bridge';
|
|
||||||
import EditorWindow from './NoteEditor/EditorWindow';
|
import EditorWindow from './NoteEditor/EditorWindow';
|
||||||
import SsoLoginScreen from './SsoLoginScreen/SsoLoginScreen';
|
import SsoLoginScreen from './SsoLoginScreen/SsoLoginScreen';
|
||||||
import SamlShared from '@joplin/lib/components/shared/SamlShared';
|
import SamlShared from '@joplin/lib/components/shared/SamlShared';
|
||||||
@@ -41,7 +38,6 @@ interface Props {
|
|||||||
profileConfigCurrentProfileId: string;
|
profileConfigCurrentProfileId: string;
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||||
dispatch: Function;
|
dispatch: Function;
|
||||||
size: Size;
|
|
||||||
zoomFactor: number;
|
zoomFactor: number;
|
||||||
needApiAuth: boolean;
|
needApiAuth: boolean;
|
||||||
dialogs: AppStateDialog[];
|
dialogs: AppStateDialog[];
|
||||||
@@ -62,31 +58,9 @@ const GlobalStyle = createGlobalStyle`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
const navigatorStyle = { width: '100vw', height: '100vh' };
|
||||||
let wcsTimeoutId_: any = null;
|
|
||||||
|
|
||||||
async function initialize() {
|
async function initialize() {
|
||||||
bridge().activeWindow().on('resize', () => {
|
|
||||||
if (wcsTimeoutId_) shim.clearTimeout(wcsTimeoutId_);
|
|
||||||
|
|
||||||
wcsTimeoutId_ = shim.setTimeout(() => {
|
|
||||||
store.dispatch({
|
|
||||||
type: 'WINDOW_CONTENT_SIZE_SET',
|
|
||||||
size: bridge().windowContentSize(),
|
|
||||||
});
|
|
||||||
wcsTimeoutId_ = null;
|
|
||||||
}, 10);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Need to dispatch this to make sure the components are
|
|
||||||
// displayed at the right size. The windowContentSize is
|
|
||||||
// also set in the store default state, but at that point
|
|
||||||
// the window might not be at its final size.
|
|
||||||
store.dispatch({
|
|
||||||
type: 'WINDOW_CONTENT_SIZE_SET',
|
|
||||||
size: bridge().windowContentSize(),
|
|
||||||
});
|
|
||||||
|
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
type: 'EDITOR_CODE_VIEW_CHANGE',
|
type: 'EDITOR_CODE_VIEW_CHANGE',
|
||||||
value: Setting.value('editor.codeView'),
|
value: Setting.value('editor.codeView'),
|
||||||
@@ -180,11 +154,6 @@ class RootComponent extends React.Component<Props, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const navigatorStyle = {
|
|
||||||
width: this.props.size.width / this.props.zoomFactor,
|
|
||||||
height: this.props.size.height / this.props.zoomFactor,
|
|
||||||
};
|
|
||||||
|
|
||||||
const theme = themeStyle(this.props.themeId);
|
const theme = themeStyle(this.props.themeId);
|
||||||
|
|
||||||
const screens = {
|
const screens = {
|
||||||
@@ -219,7 +188,6 @@ class RootComponent extends React.Component<Props, any> {
|
|||||||
|
|
||||||
const mapStateToProps = (state: AppState) => {
|
const mapStateToProps = (state: AppState) => {
|
||||||
return {
|
return {
|
||||||
size: state.windowContentSize,
|
|
||||||
zoomFactor: state.settings.windowContentZoomFactor / 100,
|
zoomFactor: state.settings.windowContentZoomFactor / 100,
|
||||||
appState: state.appState,
|
appState: state.appState,
|
||||||
themeId: state.settings.theme,
|
themeId: state.settings.theme,
|
||||||
|
@@ -39,7 +39,7 @@ describe('PerFolderSortOrderService', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
PerFolderSortOrderService.initialize();
|
PerFolderSortOrderService.initialize();
|
||||||
Setting.setValue('notes.perFolderSortOrderEnabled', true);
|
Setting.setValue('notes.perFolderSortOrderEnabled', true);
|
||||||
updateAppState(createAppDefaultState({}, {}));
|
updateAppState(createAppDefaultState({}));
|
||||||
switchToFolder(folderId1);
|
switchToFolder(folderId1);
|
||||||
});
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
Reference in New Issue
Block a user