2020-09-15 15:01:07 +02:00
import * as React from 'react' ;
2020-10-09 19:35:46 +02:00
import ResizableLayout , { findItemByKey , LayoutItem , LayoutItemDirection , allDynamicSizes } from '../ResizableLayout/ResizableLayout' ;
import NoteList from '../NoteList/NoteList' ;
import NoteEditor from '../NoteEditor/NoteEditor' ;
import NoteContentPropertiesDialog from '../NoteContentPropertiesDialog' ;
import ShareNoteDialog from '../ShareNoteDialog' ;
import NoteListControls from '../NoteListControls/NoteListControls' ;
2020-11-07 17:59:37 +02:00
import CommandService from '@joplin/lib/services/CommandService' ;
import PluginService from '@joplin/lib/services/plugins/PluginService' ;
import { utils as pluginUtils } from '@joplin/lib/services/plugins/reducer' ;
2020-10-09 19:35:46 +02:00
import SideBar from '../SideBar/SideBar' ;
import UserWebview from '../../services/plugins/UserWebview' ;
import UserWebviewDialog from '../../services/plugins/UserWebviewDialog' ;
2020-11-07 17:59:37 +02:00
import { ContainerType } from '@joplin/lib/services/plugins/WebviewController' ;
import { stateUtils } from '@joplin/lib/reducer' ;
2020-10-09 19:35:46 +02:00
import InteropServiceHelper from '../../InteropServiceHelper' ;
2020-11-07 17:59:37 +02:00
import { _ } from '@joplin/lib/locale' ;
2020-09-15 15:01:07 +02:00
const produce = require ( 'immer' ) . default ;
2017-11-06 20:35:04 +02:00
const { connect } = require ( 'react-redux' ) ;
2020-07-03 23:32:39 +02:00
const { PromptDialog } = require ( '../PromptDialog.min.js' ) ;
const NotePropertiesDialog = require ( '../NotePropertiesDialog.min.js' ) ;
2020-11-07 17:59:37 +02:00
const Setting = require ( '@joplin/lib/models/Setting' ) . default ;
const shim = require ( '@joplin/lib/shim' ) . default ;
const { themeStyle } = require ( '@joplin/lib/theme.js' ) ;
2020-10-09 19:35:46 +02:00
const bridge = require ( 'electron' ) . remote . require ( './bridge' ) . default ;
2020-11-07 17:59:37 +02:00
const PluginManager = require ( '@joplin/lib/services/PluginManager' ) ;
const EncryptionService = require ( '@joplin/lib/services/EncryptionService' ) ;
2020-04-09 19:57:20 +02:00
const ipcRenderer = require ( 'electron' ) . ipcRenderer ;
2020-11-07 17:59:37 +02:00
const time = require ( '@joplin/lib/time' ) . default ;
2020-10-09 19:35:46 +02:00
const styled = require ( 'styled-components' ) . default ;
const StyledUserWebviewDialogContainer = styled . div `
display : flex ;
position : absolute ;
top : 0 ;
left : 0 ;
width : 100 % ;
height : 100 % ;
z - index : 1000 ;
box - sizing : border - box ;
` ;
2017-11-06 20:35:04 +02:00
2020-07-03 23:32:39 +02:00
const commands = [
require ( './commands/editAlarm' ) ,
require ( './commands/exportPdf' ) ,
require ( './commands/hideModalMessage' ) ,
require ( './commands/moveToFolder' ) ,
require ( './commands/newNote' ) ,
2020-09-15 15:01:07 +02:00
require ( './commands/newFolder' ) ,
2020-10-25 19:29:52 +02:00
require ( './commands/newSubFolder' ) ,
2020-07-03 23:32:39 +02:00
require ( './commands/newTodo' ) ,
require ( './commands/print' ) ,
require ( './commands/renameFolder' ) ,
require ( './commands/renameTag' ) ,
require ( './commands/search' ) ,
require ( './commands/selectTemplate' ) ,
require ( './commands/setTags' ) ,
require ( './commands/showModalMessage' ) ,
require ( './commands/showNoteContentProperties' ) ,
require ( './commands/showNoteProperties' ) ,
require ( './commands/showShareNoteDialog' ) ,
2020-09-15 15:01:07 +02:00
require ( './commands/toggleEditors' ) ,
2020-07-03 23:32:39 +02:00
require ( './commands/toggleNoteList' ) ,
2020-10-18 22:52:10 +02:00
require ( './commands/toggleSideBar' ) ,
2020-07-03 23:32:39 +02:00
require ( './commands/toggleVisiblePanes' ) ,
2020-10-25 19:22:59 +02:00
require ( './commands/openNote' ) ,
require ( './commands/openFolder' ) ,
require ( './commands/openTag' ) ,
2020-07-03 23:32:39 +02:00
] ;
2020-09-15 15:01:07 +02:00
class MainScreenComponent extends React . Component < any , any > {
waitForNotesSavedIID_ :any ;
isPrinting_ :boolean ;
styleKey_ :string ;
styles_ :any ;
promptOnClose_ :Function ;
constructor ( props :any ) {
super ( props ) ;
2020-10-09 19:35:46 +02:00
this . state = {
promptOptions : null ,
modalLayer : {
visible : false ,
message : '' ,
} ,
notePropertiesDialogOptions : { } ,
noteContentPropertiesDialogOptions : { } ,
shareNoteDialogOptions : { } ,
layout : this.buildLayout ( props . plugins ) ,
} ;
this . registerCommands ( ) ;
this . setupAppCloseHandling ( ) ;
this . notePropertiesDialog_close = this . notePropertiesDialog_close . bind ( this ) ;
this . noteContentPropertiesDialog_close = this . noteContentPropertiesDialog_close . bind ( this ) ;
this . shareNoteDialog_close = this . shareNoteDialog_close . bind ( this ) ;
this . userWebview_message = this . userWebview_message . bind ( this ) ;
this . resizableLayout_resize = this . resizableLayout_resize . bind ( this ) ;
this . resizableLayout_renderItem = this . resizableLayout_renderItem . bind ( this ) ;
this . window_resize = this . window_resize . bind ( this ) ;
this . rowHeight = this . rowHeight . bind ( this ) ;
window . addEventListener ( 'resize' , this . window_resize ) ;
}
buildLayout ( plugins :any ) : LayoutItem {
2020-09-15 15:01:07 +02:00
const rootLayoutSize = this . rootLayoutSize ( ) ;
2020-10-09 19:35:46 +02:00
const theme = themeStyle ( this . props . themeId ) ;
2020-09-15 15:01:07 +02:00
const sideBarMinWidth = 200 ;
2020-10-09 19:35:46 +02:00
const sizes = {
sideBarColumn : {
width : 150 ,
} ,
noteListColumn : {
width : 150 ,
} ,
pluginColumn : {
width : 150 ,
} ,
. . . Setting . value ( 'ui.layout' ) ,
} ;
for ( const k in sizes ) {
if ( sizes [ k ] . width < sideBarMinWidth ) sizes [ k ] . width = sideBarMinWidth ;
}
const pluginColumnChildren :LayoutItem [ ] = [ ] ;
const infos = pluginUtils . viewInfosByType ( plugins , 'webview' ) ;
for ( const info of infos ) {
if ( info . view . containerType !== ContainerType . Panel ) continue ;
// For now it's assumed all views go in the "pluginColumn" so they are
// resizable vertically. But horizontally they stretch 100%
const viewId = info . view . id ;
const size = {
. . . ( sizes [ viewId ] ? sizes [ viewId ] : null ) ,
width : '100%' ,
} ;
pluginColumnChildren . push ( {
key : viewId ,
resizableBottom : true ,
context : {
plugin : info.plugin ,
control : info.view ,
} ,
. . . size ,
} ) ;
}
return {
2020-09-15 15:01:07 +02:00
key : 'root' ,
direction : LayoutItemDirection.Row ,
width : rootLayoutSize.width ,
height : rootLayoutSize.height ,
children : [
{
2020-10-09 19:35:46 +02:00
key : 'sideBarColumn' ,
2020-09-15 15:01:07 +02:00
direction : LayoutItemDirection.Column ,
2020-10-09 19:35:46 +02:00
resizableRight : true ,
width : sizes.sideBarColumn.width ,
2020-09-15 15:01:07 +02:00
visible : Setting.value ( 'sidebarVisibility' ) ,
minWidth : sideBarMinWidth ,
children : [
{
key : 'sideBar' ,
} ,
] ,
} ,
{
key : 'noteListColumn' ,
direction : LayoutItemDirection.Column ,
2020-10-09 19:35:46 +02:00
resizableRight : true ,
width : sizes.noteListColumn.width ,
2020-09-15 15:01:07 +02:00
visible : Setting.value ( 'noteListVisibility' ) ,
minWidth : sideBarMinWidth ,
children : [
{
height : theme.topRowHeight ,
key : 'noteListControls' ,
} ,
{
key : 'noteList' ,
} ,
] ,
} ,
2020-10-09 19:35:46 +02:00
{
key : 'pluginColumn' ,
direction : LayoutItemDirection.Column ,
resizableRight : true ,
width : sizes.pluginColumn.width ,
visible : ! ! pluginColumnChildren . length ,
minWidth : sideBarMinWidth ,
children : pluginColumnChildren ,
} ,
2020-09-15 15:01:07 +02:00
{
key : 'editorColumn' ,
direction : LayoutItemDirection.Column ,
children : [
{
key : 'editor' ,
} ,
] ,
} ,
] ,
} ;
}
window_resize() {
this . updateRootLayoutSize ( ) ;
2019-02-16 03:12:43 +02:00
}
2020-04-09 19:57:20 +02:00
setupAppCloseHandling() {
this . waitForNotesSavedIID_ = null ;
// This event is dispached from the main process when the app is about
// to close. The renderer process must respond with the "appCloseReply"
// and tell the main process whether the app can really be closed or not.
// For example, it cannot be closed right away if a note is being saved.
// If a note is being saved, we wait till it is saved and then call
// "appCloseReply" again.
ipcRenderer . on ( 'appClose' , ( ) = > {
2020-10-09 19:35:46 +02:00
if ( this . waitForNotesSavedIID_ ) shim . clearInterval ( this . waitForNotesSavedIID_ ) ;
2020-04-09 19:57:20 +02:00
this . waitForNotesSavedIID_ = null ;
ipcRenderer . send ( 'asynchronous-message' , 'appCloseReply' , {
canClose : ! this . props . hasNotesBeingSaved ,
} ) ;
if ( this . props . hasNotesBeingSaved ) {
2020-10-09 19:35:46 +02:00
this . waitForNotesSavedIID_ = shim . setInterval ( ( ) = > {
2020-04-09 19:57:20 +02:00
if ( ! this . props . hasNotesBeingSaved ) {
2020-10-09 19:35:46 +02:00
shim . clearInterval ( this . waitForNotesSavedIID_ ) ;
2020-04-09 19:57:20 +02:00
this . waitForNotesSavedIID_ = null ;
ipcRenderer . send ( 'asynchronous-message' , 'appCloseReply' , {
canClose : true ,
} ) ;
}
} , 50 ) ;
}
} ) ;
}
2018-09-16 20:37:31 +02:00
notePropertiesDialog_close() {
this . setState ( { notePropertiesDialogOptions : { } } ) ;
}
2020-02-25 11:43:31 +02:00
noteContentPropertiesDialog_close() {
this . setState ( { noteContentPropertiesDialogOptions : { } } ) ;
}
2019-12-13 03:16:34 +02:00
shareNoteDialog_close() {
this . setState ( { shareNoteDialogOptions : { } } ) ;
}
2020-09-15 15:01:07 +02:00
updateRootLayoutSize() {
2020-10-09 19:35:46 +02:00
this . setState ( { layout : produce ( this . state . layout , ( draft :any ) = > {
2020-09-15 15:01:07 +02:00
const s = this . rootLayoutSize ( ) ;
2020-10-09 19:35:46 +02:00
draft . width = s . width ;
draft . height = s . height ;
2020-09-15 15:01:07 +02:00
} ) } ) ;
}
2020-09-21 18:31:25 +02:00
componentDidUpdate ( prevProps :any , prevState :any ) {
2020-09-15 15:01:07 +02:00
if ( this . props . noteListVisibility !== prevProps . noteListVisibility || this . props . sidebarVisibility !== prevProps . sidebarVisibility ) {
2020-10-09 19:35:46 +02:00
this . setState ( { layout : produce ( this . state . layout , ( draft :any ) = > {
const noteListColumn = findItemByKey ( draft , 'noteListColumn' ) ;
2020-09-15 15:01:07 +02:00
noteListColumn . visible = this . props . noteListVisibility ;
2020-10-09 19:35:46 +02:00
const sideBarColumn = findItemByKey ( draft , 'sideBarColumn' ) ;
sideBarColumn . visible = this . props . sidebarVisibility ;
2020-09-15 15:01:07 +02:00
} ) } ) ;
}
2020-10-09 19:35:46 +02:00
if ( prevProps . style . width !== this . props . style . width ||
prevProps . style . height !== this . props . style . height ||
this . messageBoxVisible ( prevProps ) !== this . messageBoxVisible ( this . props )
) {
2020-09-15 15:01:07 +02:00
this . updateRootLayoutSize ( ) ;
}
2020-09-21 18:31:25 +02:00
2020-10-09 19:35:46 +02:00
if ( prevProps . plugins !== this . props . plugins ) {
this . setState ( { layout : this.buildLayout ( this . props . plugins ) } ) ;
}
2020-09-21 18:31:25 +02:00
if ( this . state . notePropertiesDialogOptions !== prevState . notePropertiesDialogOptions ) {
this . props . dispatch ( {
type : this . state . notePropertiesDialogOptions && this . state . notePropertiesDialogOptions . visible ? 'VISIBLE_DIALOGS_ADD' : 'VISIBLE_DIALOGS_REMOVE' ,
name : 'noteProperties' ,
} ) ;
}
if ( this . state . noteContentPropertiesDialogOptions !== prevState . noteContentPropertiesDialogOptions ) {
this . props . dispatch ( {
type : this . state . noteContentPropertiesDialogOptions && this . state . noteContentPropertiesDialogOptions . visible ? 'VISIBLE_DIALOGS_ADD' : 'VISIBLE_DIALOGS_REMOVE' ,
name : 'noteContentProperties' ,
} ) ;
}
if ( this . state . shareNoteDialogOptions !== prevState . shareNoteDialogOptions ) {
this . props . dispatch ( {
type : this . state . shareNoteDialogOptions && this . state . shareNoteDialogOptions . visible ? 'VISIBLE_DIALOGS_ADD' : 'VISIBLE_DIALOGS_REMOVE' ,
name : 'shareNote' ,
} ) ;
}
2020-09-15 15:01:07 +02:00
}
2020-07-03 23:32:39 +02:00
componentDidMount() {
2020-09-15 15:01:07 +02:00
this . updateRootLayoutSize ( ) ;
2020-07-03 23:32:39 +02:00
}
componentWillUnmount() {
this . unregisterCommands ( ) ;
2020-09-15 15:01:07 +02:00
window . removeEventListener ( 'resize' , this . window_resize ) ;
2017-11-08 19:51:55 +02:00
}
2020-10-18 22:52:10 +02:00
toggleSideBar() {
2018-04-15 17:50:39 +02:00
this . props . dispatch ( {
type : 'SIDEBAR_VISIBILITY_TOGGLE' ,
} ) ;
}
2019-10-30 11:40:34 +02:00
toggleNoteList() {
this . props . dispatch ( {
type : 'NOTELIST_VISIBILITY_TOGGLE' ,
} ) ;
}
2020-09-15 15:01:07 +02:00
async waitForNoteToSaved ( noteId :string ) {
2020-05-02 17:41:07 +02:00
while ( noteId && this . props . editorNoteStatuses [ noteId ] === 'saving' ) {
console . info ( 'Waiting for note to be saved...' , this . props . editorNoteStatuses ) ;
await time . msleep ( 100 ) ;
}
}
2020-09-15 15:01:07 +02:00
async printTo_ ( target :string , options :any ) {
2020-05-02 17:41:07 +02:00
// Concurrent print calls are disallowed to avoid incorrect settings being restored upon completion
if ( this . isPrinting_ ) {
console . info ( ` Printing ${ options . path } to ${ target } disallowed, already printing. ` ) ;
return ;
}
this . isPrinting_ = true ;
// Need to wait for save because the interop service reloads the note from the database
await this . waitForNoteToSaved ( options . noteId ) ;
if ( target === 'pdf' ) {
try {
const pdfData = await InteropServiceHelper . exportNoteToPdf ( options . noteId , {
printBackground : true ,
pageSize : Setting.value ( 'export.pdfPageSize' ) ,
landscape : Setting.value ( 'export.pdfPageOrientation' ) === 'landscape' ,
customCss : this.props.customCss ,
} ) ;
await shim . fsDriver ( ) . writeFile ( options . path , pdfData , 'buffer' ) ;
} catch ( error ) {
console . error ( error ) ;
bridge ( ) . showErrorMessageBox ( error . message ) ;
}
} else if ( target === 'printer' ) {
try {
await InteropServiceHelper . printNote ( options . noteId , {
printBackground : true ,
customCss : this.props.customCss ,
} ) ;
} catch ( error ) {
console . error ( error ) ;
bridge ( ) . showErrorMessageBox ( error . message ) ;
}
}
this . isPrinting_ = false ;
}
2020-09-15 15:01:07 +02:00
rootLayoutSize() {
return {
width : window.innerWidth ,
height : this.rowHeight ( ) ,
} ;
}
rowHeight() {
if ( ! this . props ) return 0 ;
return this . props . style . height - ( this . messageBoxVisible ( ) ? this . messageBoxHeight ( ) : 0 ) ;
}
messageBoxHeight() {
return 50 ;
}
2020-10-09 19:35:46 +02:00
styles ( themeId :number , width :number , height :number , messageBoxVisible :boolean , isSidebarVisible :any , isNoteListVisible :any ) {
const styleKey = [ themeId , width , height , messageBoxVisible , + isSidebarVisible , + isNoteListVisible ] . join ( '_' ) ;
2017-11-30 01:03:10 +02:00
if ( styleKey === this . styleKey_ ) return this . styles_ ;
2017-11-06 22:54:58 +02:00
2017-11-30 01:03:10 +02:00
const theme = themeStyle ( themeId ) ;
2017-11-06 22:54:58 +02:00
2017-11-30 01:03:10 +02:00
this . styleKey_ = styleKey ;
2017-11-06 20:35:04 +02:00
2017-11-30 01:03:10 +02:00
this . styles_ = { } ;
this . styles_ . header = {
width : width ,
} ;
2017-12-05 01:57:13 +02:00
this . styles_ . messageBox = {
width : width ,
2020-09-15 15:01:07 +02:00
height : this.messageBoxHeight ( ) ,
2017-12-05 01:57:13 +02:00
display : 'flex' ,
alignItems : 'center' ,
paddingLeft : 10 ,
backgroundColor : theme.warningBackgroundColor ,
2019-07-29 14:13:23 +02:00
} ;
2017-12-05 01:57:13 +02:00
2020-09-15 15:01:07 +02:00
const rowHeight = height - ( messageBoxVisible ? this . styles_.messageBox.height : 0 ) ;
this . styles_ . rowHeight = rowHeight ;
2019-12-30 14:00:53 +02:00
2020-09-15 15:01:07 +02:00
this . styles_ . resizableLayout = {
height : rowHeight ,
} ;
2017-11-30 01:03:10 +02:00
this . styles_ . prompt = {
width : width ,
height : height ,
2017-11-08 19:51:55 +02:00
} ;
2018-02-27 22:04:38 +02:00
this . styles_ . modalLayer = Object . assign ( { } , theme . textStyle , {
zIndex : 10000 ,
position : 'absolute' ,
top : 0 ,
left : 0 ,
2018-03-23 19:59:18 +02:00
backgroundColor : theme.backgroundColor ,
2018-02-27 22:04:38 +02:00
width : width - 20 ,
height : height - 20 ,
padding : 10 ,
} ) ;
2017-11-30 01:03:10 +02:00
return this . styles_ ;
}
2020-09-15 15:01:07 +02:00
renderNotification ( theme :any , styles :any ) {
2020-03-13 19:42:50 +02:00
if ( ! this . messageBoxVisible ( ) ) return null ;
const onViewStatusScreen = ( ) = > {
this . props . dispatch ( {
type : 'NAV_GO' ,
routeName : 'Status' ,
} ) ;
} ;
const onViewEncryptionConfigScreen = ( ) = > {
this . props . dispatch ( {
type : 'NAV_GO' ,
routeName : 'Config' ,
props : {
defaultSection : 'encryption' ,
} ,
} ) ;
} ;
2020-08-02 13:28:50 +02:00
const onRestartAndUpgrade = async ( ) = > {
Setting . setValue ( 'sync.upgradeState' , Setting . SYNC_UPGRADE_STATE_MUST_DO ) ;
await Setting . saveAll ( ) ;
bridge ( ) . restart ( ) ;
} ;
2020-03-13 19:42:50 +02:00
let msg = null ;
2020-08-02 13:28:50 +02:00
if ( this . props . shouldUpgradeSyncTarget ) {
msg = (
< span >
{ _ ( 'The sync target needs to be upgraded before Joplin can sync. The operation may take a few minutes to complete and the app needs to be restarted. To proceed please click on the link.' ) } { ' ' }
< a href = "#" onClick = { ( ) = > onRestartAndUpgrade ( ) } >
{ _ ( 'Restart and upgrade' ) }
< / a >
< / span >
) ;
} else if ( this . props . hasDisabledSyncItems ) {
2020-03-13 19:42:50 +02:00
msg = (
< span >
{ _ ( 'Some items cannot be synchronised.' ) } { ' ' }
< a href = "#" onClick = { ( ) = > onViewStatusScreen ( ) } >
{ _ ( 'View them now' ) }
< / a >
< / span >
) ;
} else if ( this . props . hasDisabledEncryptionItems ) {
msg = (
< span >
{ _ ( 'Some items cannot be decrypted.' ) } { ' ' }
< a href = "#" onClick = { ( ) = > onViewStatusScreen ( ) } >
{ _ ( 'View them now' ) }
< / a >
< / span >
) ;
} else if ( this . props . showMissingMasterKeyMessage ) {
msg = (
< span >
{ _ ( 'One or more master keys need a password.' ) } { ' ' }
< a href = "#" onClick = { ( ) = > onViewEncryptionConfigScreen ( ) } >
{ _ ( 'Set the password' ) }
< / a >
< / span >
) ;
} else if ( this . props . showNeedUpgradingMasterKeyMessage ) {
msg = (
< span >
{ _ ( 'One of your master keys use an obsolete encryption method.' ) } { ' ' }
< a href = "#" onClick = { ( ) = > onViewEncryptionConfigScreen ( ) } >
{ _ ( 'View them now' ) }
< / a >
< / span >
) ;
} else if ( this . props . showShouldReencryptMessage ) {
msg = (
< span >
2020-03-14 02:52:28 +02:00
{ _ ( 'The default encryption method has been changed, you should re-encrypt your data.' ) } { ' ' }
2020-03-13 19:42:50 +02:00
< a href = "#" onClick = { ( ) = > onViewEncryptionConfigScreen ( ) } >
{ _ ( 'More info' ) }
< / a >
< / span >
) ;
}
return (
< div style = { styles . messageBox } >
< span style = { theme . textStyle } > { msg } < / span >
< / div >
) ;
}
2020-10-09 19:35:46 +02:00
messageBoxVisible ( props :any = null ) {
if ( ! props ) props = this . props ;
return props . hasDisabledSyncItems || props . showMissingMasterKeyMessage || props . showNeedUpgradingMasterKeyMessage || props . showShouldReencryptMessage || props . hasDisabledEncryptionItems || this . props . shouldUpgradeSyncTarget ;
2020-03-13 19:42:50 +02:00
}
2020-07-03 23:32:39 +02:00
registerCommands() {
for ( const command of commands ) {
CommandService . instance ( ) . registerRuntime ( command . declaration . name , command . runtime ( this ) ) ;
}
}
unregisterCommands() {
for ( const command of commands ) {
CommandService . instance ( ) . unregisterRuntime ( command . declaration . name ) ;
}
}
2020-10-09 19:35:46 +02:00
userWebview_message ( event :any ) {
PluginService . instance ( ) . pluginById ( event . pluginId ) . viewController ( event . viewId ) . emitMessage ( event ) ;
}
2020-09-15 15:01:07 +02:00
resizableLayout_resize ( event :any ) {
this . setState ( { layout : event.layout } ) ;
2020-10-09 19:35:46 +02:00
Setting . setValue ( 'ui.layout' , allDynamicSizes ( event . layout ) ) ;
2020-09-15 15:01:07 +02:00
}
resizableLayout_renderItem ( key :string , event :any ) {
const eventEmitter = event . eventEmitter ;
if ( key === 'sideBar' ) {
return < SideBar key = { key } / > ;
} else if ( key === 'noteList' ) {
return < NoteList key = { key } resizableLayoutEventEmitter = { eventEmitter } size = { event . size } visible = { event . visible } / > ;
} else if ( key === 'editor' ) {
const bodyEditor = this . props . settingEditorCodeView ? 'CodeMirror' : 'TinyMCE' ;
return < NoteEditor key = { key } bodyEditor = { bodyEditor } / > ;
} else if ( key === 'noteListControls' ) {
2020-09-29 13:31:19 +02:00
return < NoteListControls key = { key } showNewNoteButtons = { this . props . focusedField !== 'globalSearch' } / > ;
2020-10-09 19:35:46 +02:00
} else if ( key . indexOf ( 'plugin-view' ) === 0 ) {
const { control , plugin } = event . item . context ;
return < UserWebview
key = { control . id }
viewId = { control . id }
themeId = { this . props . themeId }
html = { control . html }
scripts = { control . scripts }
pluginId = { plugin . id }
onMessage = { this . userWebview_message }
borderBottom = { true }
fitToContent = { false }
/ > ;
2020-09-15 15:01:07 +02:00
}
throw new Error ( ` Invalid layout component: ${ key } ` ) ;
}
2020-10-09 19:35:46 +02:00
renderPluginDialogs() {
const output = [ ] ;
const infos = pluginUtils . viewInfosByType ( this . props . plugins , 'webview' ) ;
for ( const info of infos ) {
const { plugin , view } = info ;
if ( view . containerType !== ContainerType . Dialog ) continue ;
if ( ! view . opened ) continue ;
output . push ( < UserWebviewDialog
key = { view . id }
viewId = { view . id }
themeId = { this . props . themeId }
html = { view . html }
scripts = { view . scripts }
pluginId = { plugin . id }
onMessage = { this . userWebview_message }
buttons = { view . buttons }
/ > ) ;
}
if ( ! output . length ) return null ;
return (
< StyledUserWebviewDialogContainer >
{ output }
< / StyledUserWebviewDialogContainer >
) ;
}
2017-11-30 01:03:10 +02:00
render() {
2020-09-15 15:01:07 +02:00
const theme = themeStyle ( this . props . themeId ) ;
2019-07-29 14:13:23 +02:00
const style = Object . assign (
{
color : theme.color ,
backgroundColor : theme.backgroundColor ,
} ,
2020-08-05 00:00:11 +02:00
this . props . style
2019-07-29 14:13:23 +02:00
) ;
2017-11-30 01:03:10 +02:00
const promptOptions = this . state . promptOptions ;
2018-04-15 17:50:39 +02:00
const sidebarVisibility = this . props . sidebarVisibility ;
2019-10-30 11:40:34 +02:00
const noteListVisibility = this . props . noteListVisibility ;
2020-10-09 19:35:46 +02:00
const styles = this . styles ( this . props . themeId , style . width , style . height , this . messageBoxVisible ( ) , sidebarVisibility , noteListVisibility ) ;
2018-03-20 01:04:48 +02:00
2017-11-30 01:03:10 +02:00
if ( ! this . promptOnClose_ ) {
2020-09-15 15:01:07 +02:00
this . promptOnClose_ = ( answer :any , buttonType :any ) = > {
2017-11-30 01:03:10 +02:00
return this . state . promptOptions . onClose ( answer , buttonType ) ;
2019-07-29 14:13:23 +02:00
} ;
2017-11-30 01:03:10 +02:00
}
2020-03-13 19:42:50 +02:00
const messageComp = this . renderNotification ( theme , styles ) ;
2017-12-05 01:57:13 +02:00
2020-10-09 19:35:46 +02:00
const dialogInfo = PluginManager . instance ( ) . pluginDialogToShow ( this . props . pluginsLegacy ) ;
2019-07-29 14:13:23 +02:00
const pluginDialog = ! dialogInfo ? null : < dialogInfo.Dialog { ...dialogInfo.props } / > ;
2019-04-01 21:43:13 +02:00
2018-02-27 22:04:38 +02:00
const modalLayerStyle = Object . assign ( { } , styles . modalLayer , { display : this.state.modalLayer.visible ? 'block' : 'none' } ) ;
2018-09-16 20:37:31 +02:00
const notePropertiesDialogOptions = this . state . notePropertiesDialogOptions ;
2020-02-25 11:43:31 +02:00
const noteContentPropertiesDialogOptions = this . state . noteContentPropertiesDialogOptions ;
2019-12-13 03:16:34 +02:00
const shareNoteDialogOptions = this . state . shareNoteDialogOptions ;
2018-09-16 20:37:31 +02:00
2017-11-06 20:35:04 +02:00
return (
< div style = { style } >
2018-02-27 22:04:38 +02:00
< div style = { modalLayerStyle } > { this . state . modalLayer . message } < / div >
2020-10-09 19:35:46 +02:00
{ this . renderPluginDialogs ( ) }
2020-09-15 15:01:07 +02:00
{ noteContentPropertiesDialogOptions . visible && < NoteContentPropertiesDialog markupLanguage = { noteContentPropertiesDialogOptions . markupLanguage } themeId = { this . props . themeId } onClose = { this . noteContentPropertiesDialog_close } text = { noteContentPropertiesDialogOptions . text } / > }
{ notePropertiesDialogOptions . visible && < NotePropertiesDialog themeId = { this . props . themeId } noteId = { notePropertiesDialogOptions . noteId } onClose = { this . notePropertiesDialog_close } onRevisionLinkClick = { notePropertiesDialogOptions . onRevisionLinkClick } / > }
{ shareNoteDialogOptions . visible && < ShareNoteDialog themeId = { this . props . themeId } noteIds = { shareNoteDialogOptions . noteIds } onClose = { this . shareNoteDialog_close } / > }
2019-07-29 14:13:23 +02:00
2020-09-15 15:01:07 +02:00
< PromptDialog autocomplete = { promptOptions && 'autocomplete' in promptOptions ? promptOptions.autocomplete : null } defaultValue = { promptOptions && promptOptions . value ? promptOptions . value : '' } themeId = { this . props . themeId } style = { styles . prompt } onClose = { this . promptOnClose_ } label = { promptOptions ? promptOptions . label : '' } description = { promptOptions ? promptOptions.description : null } visible = { ! ! this . state . promptOptions } buttons = { promptOptions && 'buttons' in promptOptions ? promptOptions.buttons : null } inputType = { promptOptions && 'inputType' in promptOptions ? promptOptions.inputType : null } / >
2018-09-16 20:37:31 +02:00
2017-12-05 01:57:13 +02:00
{ messageComp }
2020-09-15 15:01:07 +02:00
< ResizableLayout
width = { this . state . width }
height = { styles . rowHeight }
layout = { this . state . layout }
onResize = { this . resizableLayout_resize }
renderItem = { this . resizableLayout_renderItem }
/ >
2019-07-29 14:13:23 +02:00
{ pluginDialog }
2017-11-06 20:35:04 +02:00
< / div >
) ;
}
}
2020-09-15 15:01:07 +02:00
const mapStateToProps = ( state :any ) = > {
2017-11-06 22:54:58 +02:00
return {
2020-09-15 15:01:07 +02:00
themeId : state.settings.theme ,
2020-05-02 17:41:07 +02:00
settingEditorCodeView : state.settings [ 'editor.codeView' ] ,
2018-04-15 17:50:39 +02:00
sidebarVisibility : state.sidebarVisibility ,
2019-10-30 11:40:34 +02:00
noteListVisibility : state.noteListVisibility ,
2017-11-13 02:23:12 +02:00
folders : state.folders ,
notes : state.notes ,
2017-12-05 20:56:39 +02:00
hasDisabledSyncItems : state.hasDisabledSyncItems ,
2020-03-13 19:42:50 +02:00
hasDisabledEncryptionItems : state.hasDisabledEncryptionItems ,
2017-12-22 20:50:27 +02:00
showMissingMasterKeyMessage : state.notLoadedMasterKeys.length && state . masterKeys . length ,
2020-03-13 19:42:50 +02:00
showNeedUpgradingMasterKeyMessage : ! ! EncryptionService . instance ( ) . masterKeysThatNeedUpgrading ( state . masterKeys ) . length ,
showShouldReencryptMessage : state.settings [ 'encryption.shouldReencrypt' ] >= Setting . SHOULD_REENCRYPT_YES ,
2020-08-02 13:28:50 +02:00
shouldUpgradeSyncTarget : state.settings [ 'sync.upgradeState' ] === Setting . SYNC_UPGRADE_STATE_SHOULD_DO ,
2018-01-31 22:19:11 +02:00
selectedFolderId : state.selectedFolderId ,
2019-03-15 23:57:58 +02:00
selectedNoteId : state.selectedNoteIds.length === 1 ? state . selectedNoteIds [ 0 ] : null ,
2020-10-09 19:35:46 +02:00
pluginsLegacy : state.pluginsLegacy ,
plugins : state.pluginService.plugins ,
2019-07-20 23:13:10 +02:00
templates : state.templates ,
2020-05-02 17:41:07 +02:00
customCss : state.customCss ,
editorNoteStatuses : state.editorNoteStatuses ,
2020-04-09 19:57:20 +02:00
hasNotesBeingSaved : stateUtils.hasNotesBeingSaved ( state ) ,
2020-09-29 13:31:19 +02:00
focusedField : state.focusedField ,
2017-11-06 22:54:58 +02:00
} ;
2017-11-06 20:35:04 +02:00
} ;
2020-09-15 15:01:07 +02:00
export default connect ( mapStateToProps ) ( MainScreenComponent ) ;