2019-07-29 15:43:53 +02:00
const React = require ( 'react' ) ;
2019-07-29 15:58:33 +02:00
2018-03-09 22:59:12 +02:00
const { connect } = require ( 'react-redux' ) ;
2020-02-09 17:48:09 +02:00
const { View , Text , StyleSheet , TouchableOpacity , Image , ScrollView , Dimensions } = require ( 'react-native' ) ;
2018-03-09 22:59:12 +02:00
const Icon = require ( 'react-native-vector-icons/Ionicons' ) . default ;
2020-11-05 18:58:23 +02:00
const { BackButtonService } = require ( '../services/back-button.js' ) ;
2021-01-22 19:41:11 +02:00
const NavService = require ( '@joplin/lib/services/NavService' ) . default ;
2018-03-09 22:59:12 +02:00
const { Menu , MenuOptions , MenuOption , MenuTrigger } = require ( 'react-native-popup-menu' ) ;
2020-11-07 17:59:37 +02:00
const { _ } = require ( '@joplin/lib/locale' ) ;
const Setting = require ( '@joplin/lib/models/Setting' ) . default ;
2021-01-22 19:41:11 +02:00
const Note = require ( '@joplin/lib/models/Note' ) . default ;
const Folder = require ( '@joplin/lib/models/Folder' ) . default ;
2020-11-05 18:58:23 +02:00
const { themeStyle } = require ( './global-style.js' ) ;
const { Dropdown } = require ( './Dropdown.js' ) ;
const { dialogs } = require ( '../utils/dialogs.js' ) ;
2020-06-13 17:20:59 +02:00
const DialogBox = require ( 'react-native-dialogbox' ) . default ;
2021-08-12 17:54:10 +02:00
const { localSyncInfoFromState } = require ( '@joplin/lib/services/synchronizer/syncInfoUtils' ) ;
2021-08-17 13:03:19 +02:00
const { showMissingMasterKeyMessage } = require ( '@joplin/lib/services/e2ee/utils' ) ;
2017-05-16 21:57:09 +02:00
2020-02-09 16:51:12 +02:00
Icon . loadFont ( ) ;
2017-07-31 20:19:58 +02:00
// Rather than applying a padding to the whole bar, it is applied to each
// individual component (button, picker, etc.) so that the touchable areas
// are widder and to give more room to the picker component which has a larger
// default height.
const PADDING _V = 10 ;
2019-07-12 19:32:08 +02:00
class ScreenHeaderComponent extends React . PureComponent {
2017-08-01 19:59:01 +02:00
constructor ( ) {
super ( ) ;
this . styles _ = { } ;
2017-07-21 23:40:02 +02:00
}
2017-07-16 01:30:54 +02:00
2017-08-01 19:59:01 +02:00
styles ( ) {
2018-03-09 22:59:12 +02:00
const themeId = Setting . value ( 'theme' ) ;
2017-08-01 19:59:01 +02:00
if ( this . styles _ [ themeId ] ) return this . styles _ [ themeId ] ;
this . styles _ = { } ;
const theme = themeStyle ( themeId ) ;
2020-03-14 01:46:14 +02:00
const styleObject = {
2017-08-01 19:59:01 +02:00
container : {
2018-03-09 22:59:12 +02:00
flexDirection : 'column' ,
2020-06-10 23:08:59 +02:00
backgroundColor : theme . backgroundColor2 ,
2018-03-09 22:59:12 +02:00
alignItems : 'center' ,
shadowColor : '#000000' ,
2017-08-01 19:59:01 +02:00
elevation : 5 ,
} ,
divider : {
borderBottomWidth : 1 ,
borderColor : theme . dividerColor ,
2019-07-29 15:43:53 +02:00
backgroundColor : '#0000ff' ,
2017-08-01 19:59:01 +02:00
} ,
sideMenuButton : {
flex : 1 ,
2018-03-09 22:59:12 +02:00
alignItems : 'center' ,
2020-06-10 23:08:59 +02:00
backgroundColor : theme . backgroundColor2 ,
2017-08-01 19:59:01 +02:00
paddingLeft : theme . marginLeft ,
paddingRight : 5 ,
marginRight : 2 ,
paddingTop : PADDING _V ,
paddingBottom : PADDING _V ,
} ,
iconButton : {
flex : 1 ,
2020-06-10 23:08:59 +02:00
backgroundColor : theme . backgroundColor2 ,
2020-06-13 17:20:18 +02:00
paddingLeft : 10 ,
paddingRight : 10 ,
2017-08-01 19:59:01 +02:00
paddingTop : PADDING _V ,
paddingBottom : PADDING _V ,
} ,
saveButton : {
flex : 0 ,
2018-03-09 22:59:12 +02:00
flexDirection : 'row' ,
alignItems : 'center' ,
2017-08-01 19:59:01 +02:00
padding : 10 ,
borderWidth : 1 ,
2020-06-10 23:08:59 +02:00
borderColor : theme . colorBright2 ,
2017-08-01 19:59:01 +02:00
borderRadius : 4 ,
marginRight : 8 ,
} ,
saveButtonText : {
2018-03-09 22:59:12 +02:00
textAlignVertical : 'center' ,
2020-06-10 23:08:59 +02:00
color : theme . colorBright2 ,
2018-03-09 22:59:12 +02:00
fontWeight : 'bold' ,
2017-08-01 19:59:01 +02:00
} ,
savedButtonIcon : {
fontSize : 20 ,
2020-06-10 23:08:59 +02:00
color : theme . colorBright2 ,
2017-08-01 19:59:01 +02:00
width : 18 ,
height : 18 ,
} ,
saveButtonIcon : {
width : 18 ,
height : 18 ,
} ,
contextMenuTrigger : {
2018-05-01 20:30:41 +02:00
fontSize : 30 ,
paddingLeft : 10 ,
2017-08-01 19:59:01 +02:00
paddingRight : theme . marginRight ,
2020-06-10 23:08:59 +02:00
color : theme . color2 ,
2018-03-09 22:59:12 +02:00
fontWeight : 'bold' ,
2017-08-01 19:59:01 +02:00
} ,
contextMenu : {
2020-06-10 23:08:59 +02:00
backgroundColor : theme . backgroundColor2 ,
2017-08-01 19:59:01 +02:00
} ,
contextMenuItem : {
backgroundColor : theme . backgroundColor ,
} ,
contextMenuItemText : {
flex : 1 ,
2018-03-09 22:59:12 +02:00
textAlignVertical : 'center' ,
2017-08-01 19:59:01 +02:00
paddingLeft : theme . marginLeft ,
paddingRight : theme . marginRight ,
paddingTop : theme . itemMarginTop ,
paddingBottom : theme . itemMarginBottom ,
color : theme . color ,
backgroundColor : theme . backgroundColor ,
fontSize : theme . fontSize ,
} ,
titleText : {
flex : 1 ,
2018-03-09 22:59:12 +02:00
textAlignVertical : 'center' ,
2019-06-28 01:51:02 +02:00
marginLeft : 10 ,
2020-06-10 23:08:59 +02:00
color : theme . colorBright2 ,
2018-03-09 22:59:12 +02:00
fontWeight : 'bold' ,
2017-08-01 19:59:01 +02:00
fontSize : theme . fontSize ,
2018-03-16 22:17:52 +02:00
paddingTop : 15 ,
paddingBottom : 15 ,
2017-12-30 21:57:34 +02:00
} ,
warningBox : {
2019-07-29 15:43:53 +02:00
backgroundColor : '#ff9900' ,
2018-03-09 22:59:12 +02:00
flexDirection : 'row' ,
2017-12-30 21:57:34 +02:00
padding : theme . marginLeft ,
} ,
2017-08-01 19:59:01 +02:00
} ;
2017-07-22 18:36:55 +02:00
2017-08-01 19:59:01 +02:00
styleObject . topIcon = Object . assign ( { } , theme . icon ) ;
styleObject . topIcon . flex = 1 ;
2018-03-09 22:59:12 +02:00
styleObject . topIcon . textAlignVertical = 'center' ;
2020-06-10 23:08:59 +02:00
styleObject . topIcon . color = theme . colorBright2 ;
2017-07-23 00:52:24 +02:00
2017-08-01 19:59:01 +02:00
styleObject . backButton = Object . assign ( { } , styleObject . iconButton ) ;
styleObject . backButton . marginRight = 1 ;
2017-07-16 01:30:54 +02:00
2017-08-01 19:59:01 +02:00
styleObject . backButtonDisabled = Object . assign ( { } , styleObject . backButton , { opacity : theme . disabledOpacity } ) ;
styleObject . saveButtonDisabled = Object . assign ( { } , styleObject . saveButton , { opacity : theme . disabledOpacity } ) ;
2020-05-09 17:01:39 +02:00
styleObject . iconButtonDisabled = Object . assign ( { } , styleObject . iconButton , { opacity : theme . disabledOpacity } ) ;
2017-05-16 22:25:19 +02:00
2017-08-01 19:59:01 +02:00
this . styles _ [ themeId ] = StyleSheet . create ( styleObject ) ;
return this . styles _ [ themeId ] ;
}
2017-05-16 21:57:09 +02:00
2017-06-06 22:01:43 +02:00
sideMenuButton _press ( ) {
2018-03-09 22:59:12 +02:00
this . props . dispatch ( { type : 'SIDE_MENU_TOGGLE' } ) ;
2017-05-24 21:27:13 +02:00
}
2017-08-24 20:10:03 +02:00
async backButton _press ( ) {
2019-07-12 20:36:12 +02:00
if ( this . props . noteSelectionEnabled ) {
this . props . dispatch ( { type : 'NOTE_SELECTION_END' } ) ;
2019-07-29 15:43:53 +02:00
} else {
2019-07-12 20:36:12 +02:00
await BackButtonService . back ( ) ;
2019-07-29 15:43:53 +02:00
}
2017-05-16 21:57:09 +02:00
}
2020-03-14 00:41:56 +02:00
selectAllButton _press ( ) {
this . props . dispatch ( { type : 'NOTE_SELECT_ALL_TOGGLE' } ) ;
}
2017-07-23 00:52:24 +02:00
searchButton _press ( ) {
2018-03-09 22:59:12 +02:00
NavService . go ( 'Search' ) ;
2017-07-23 00:52:24 +02:00
}
2019-10-12 00:37:16 +02:00
async duplicateButton _press ( ) {
const noteIds = this . props . selectedNoteIds ;
2019-10-14 01:47:21 +02:00
// Duplicate all selected notes. ensureUniqueTitle is set to true to use the
// original note's name as a root for the new unique identifier.
2020-02-05 00:09:34 +02:00
await Note . duplicateMultipleNotes ( noteIds , { ensureUniqueTitle : true } ) ;
2019-10-12 00:37:16 +02:00
this . props . dispatch ( { type : 'NOTE_SELECTION_END' } ) ;
}
2017-11-23 20:47:51 +02:00
async deleteButton _press ( ) {
// Dialog needs to be displayed as a child of the parent component, otherwise
// it won't be visible within the header component.
2021-10-03 19:41:32 +02:00
const noteIds = this . props . selectedNoteIds ;
const msg = await Note . deleteMessage ( noteIds ) ;
if ( ! msg ) return ;
const ok = await dialogs . confirm ( this . props . parentComponent , msg ) ;
2017-11-23 20:47:51 +02:00
if ( ! ok ) return ;
2018-03-09 22:59:12 +02:00
this . props . dispatch ( { type : 'NOTE_SELECTION_END' } ) ;
2017-11-23 20:47:51 +02:00
await Note . batchDelete ( noteIds ) ;
}
2017-06-06 22:01:43 +02:00
menu _select ( value ) {
2019-07-29 15:43:53 +02:00
if ( typeof value == 'function' ) {
2017-05-16 22:25:19 +02:00
value ( ) ;
}
}
2017-07-07 19:19:24 +02:00
log _press ( ) {
2018-03-09 22:59:12 +02:00
NavService . go ( 'Log' ) ;
2017-07-07 19:19:24 +02:00
}
2017-07-10 21:16:59 +02:00
status _press ( ) {
2018-03-09 22:59:12 +02:00
NavService . go ( 'Status' ) ;
2017-07-10 21:16:59 +02:00
}
2019-12-28 21:50:06 +02:00
warningBox _press ( event ) {
NavService . go ( event . screen ) ;
}
renderWarningBox ( screen , message ) {
return (
< TouchableOpacity key = { screen } style = { this . styles ( ) . warningBox } onPress = { ( ) => this . warningBox _press ( { screen : screen } ) } activeOpacity = { 0.8 } >
< Text style = { { flex : 1 } } > { message } < / T e x t >
< / T o u c h a b l e O p a c i t y >
) ;
2017-12-30 21:57:34 +02:00
}
2017-05-16 21:57:09 +02:00
render ( ) {
2017-07-16 01:30:54 +02:00
function sideMenuButton ( styles , onPress ) {
return (
< TouchableOpacity onPress = { onPress } >
< View style = { styles . sideMenuButton } >
2019-07-29 15:43:53 +02:00
< Icon name = "md-menu" style = { styles . topIcon } / >
2017-07-16 01:30:54 +02:00
< / V i e w >
< / T o u c h a b l e O p a c i t y >
) ;
}
function backButton ( styles , onPress , disabled ) {
return (
< TouchableOpacity onPress = { onPress } disabled = { disabled } >
< View style = { disabled ? styles . backButtonDisabled : styles . backButton } >
2019-07-29 15:43:53 +02:00
< Icon name = "md-arrow-back" style = { styles . topIcon } / >
2017-07-16 01:30:54 +02:00
< / V i e w >
< / T o u c h a b l e O p a c i t y >
) ;
}
2017-07-16 12:17:40 +02:00
function saveButton ( styles , onPress , disabled , show ) {
if ( ! show ) return null ;
2019-07-29 15:43:53 +02:00
const icon = disabled ? < Icon name = "md-checkmark" style = { styles . savedButtonIcon } / > : < Image style = { styles . saveButtonIcon } source = { require ( './SaveIcon.png' ) } / > ;
2017-07-30 23:33:54 +02:00
2017-07-16 12:17:40 +02:00
return (
2019-07-29 15:43:53 +02:00
< TouchableOpacity onPress = { onPress } disabled = { disabled } style = { { padding : 0 } } >
< View style = { disabled ? styles . saveButtonDisabled : styles . saveButton } > { icon } < / V i e w >
2017-07-16 12:17:40 +02:00
< / T o u c h a b l e O p a c i t y >
) ;
}
2020-06-13 17:20:18 +02:00
const renderTopButton = ( options ) => {
if ( ! options . visible ) return null ;
const icon = < Icon name = { options . iconName } style = { this . styles ( ) . topIcon } / > ;
const viewStyle = options . disabled ? this . styles ( ) . iconButtonDisabled : this . styles ( ) . iconButton ;
return (
< TouchableOpacity onPress = { options . onPress } style = { { padding : 0 } } disabled = { ! ! options . disabled } >
< View style = { viewStyle } > { icon } < / V i e w >
< / T o u c h a b l e O p a c i t y >
) ;
} ;
const renderUndoButton = ( ) => {
return renderTopButton ( {
2020-10-16 17:26:19 +02:00
iconName : 'arrow-undo-circle-sharp' ,
2020-06-13 17:20:18 +02:00
onPress : this . props . onUndoButtonPress ,
visible : this . props . showUndoButton ,
disabled : this . props . undoButtonDisabled ,
} ) ;
} ;
const renderRedoButton = ( ) => {
return renderTopButton ( {
2020-10-16 17:26:19 +02:00
iconName : 'arrow-redo-circle-sharp' ,
2020-06-13 17:20:18 +02:00
onPress : this . props . onRedoButtonPress ,
visible : this . props . showRedoButton ,
} ) ;
} ;
2020-03-14 00:41:56 +02:00
function selectAllButton ( styles , onPress ) {
return (
< TouchableOpacity onPress = { onPress } >
< View style = { styles . iconButton } >
< Icon name = "md-checkmark-circle-outline" style = { styles . topIcon } / >
< / V i e w >
< / T o u c h a b l e O p a c i t y >
) ;
}
2017-07-23 00:52:24 +02:00
function searchButton ( styles , onPress ) {
return (
< TouchableOpacity onPress = { onPress } >
< View style = { styles . iconButton } >
2019-07-29 15:43:53 +02:00
< Icon name = "md-search" style = { styles . topIcon } / >
2017-07-23 00:52:24 +02:00
< / V i e w >
< / T o u c h a b l e O p a c i t y >
) ;
}
2020-05-09 17:01:39 +02:00
function deleteButton ( styles , onPress , disabled ) {
2017-11-23 20:47:51 +02:00
return (
2020-05-09 17:01:39 +02:00
< TouchableOpacity onPress = { onPress } disabled = { disabled } >
< View style = { disabled ? styles . iconButtonDisabled : styles . iconButton } >
2019-07-29 15:43:53 +02:00
< Icon name = "md-trash" style = { styles . topIcon } / >
2017-11-23 20:47:51 +02:00
< / V i e w >
< / T o u c h a b l e O p a c i t y >
) ;
}
2020-05-09 17:01:39 +02:00
function duplicateButton ( styles , onPress , disabled ) {
2019-10-12 00:37:16 +02:00
return (
2020-05-09 17:01:39 +02:00
< TouchableOpacity onPress = { onPress } disabled = { disabled } >
< View style = { disabled ? styles . iconButtonDisabled : styles . iconButton } >
2019-10-12 00:37:16 +02:00
< Icon name = "md-copy" style = { styles . topIcon } / >
< / V i e w >
< / T o u c h a b l e O p a c i t y >
) ;
}
2018-02-22 20:58:15 +02:00
function sortButton ( styles , onPress ) {
return (
< TouchableOpacity onPress = { onPress } >
< View style = { styles . iconButton } >
2020-10-16 17:26:19 +02:00
< Icon name = "filter-outline" style = { styles . topIcon } / >
2018-02-22 20:58:15 +02:00
< / V i e w >
< / T o u c h a b l e O p a c i t y >
) ;
}
2017-05-16 23:46:21 +02:00
let key = 0 ;
2020-03-14 01:46:14 +02:00
const menuOptionComponents = [ ] ;
2017-05-16 23:46:21 +02:00
2017-11-23 20:47:51 +02:00
if ( ! this . props . noteSelectionEnabled ) {
for ( let i = 0 ; i < this . props . menuOptions . length ; i ++ ) {
2020-03-14 01:46:14 +02:00
const o = this . props . menuOptions [ i ] ;
2017-11-28 22:31:14 +02:00
if ( o . isDivider ) {
2019-09-19 23:51:18 +02:00
menuOptionComponents . push ( < View key = { ` menuOption_ ${ key ++ } ` } style = { this . styles ( ) . divider } / > ) ;
2017-11-28 22:31:14 +02:00
} else {
menuOptionComponents . push (
2019-09-19 23:51:18 +02:00
< MenuOption value = { o . onPress } key = { ` menuOption_ ${ key ++ } ` } style = { this . styles ( ) . contextMenuItem } >
2017-11-28 22:31:14 +02:00
< Text style = { this . styles ( ) . contextMenuItemText } > { o . title } < / T e x t >
2019-07-29 15:43:53 +02:00
< / M e n u O p t i o n >
) ;
2017-11-28 22:31:14 +02:00
}
2017-11-23 20:47:51 +02:00
}
2017-09-24 16:48:23 +02:00
if ( menuOptionComponents . length ) {
2019-09-19 23:51:18 +02:00
menuOptionComponents . push ( < View key = { ` menuOption_ ${ key ++ } ` } style = { this . styles ( ) . divider } / > ) ;
2017-09-24 16:48:23 +02:00
}
2017-11-23 20:47:51 +02:00
} else {
2017-09-24 16:48:23 +02:00
menuOptionComponents . push (
2018-03-09 22:59:12 +02:00
< MenuOption value = { ( ) => this . deleteButton _press ( ) } key = { 'menuOption_delete' } style = { this . styles ( ) . contextMenuItem } >
< Text style = { this . styles ( ) . contextMenuItemText } > { _ ( 'Delete' ) } < / T e x t >
2019-07-29 15:43:53 +02:00
< / M e n u O p t i o n >
) ;
2019-10-12 00:37:16 +02:00
menuOptionComponents . push (
< MenuOption value = { ( ) => this . duplicateButton _press ( ) } key = { 'menuOption_duplicate' } style = { this . styles ( ) . contextMenuItem } >
< Text style = { this . styles ( ) . contextMenuItemText } > { _ ( 'Duplicate' ) } < / T e x t >
< / M e n u O p t i o n >
) ;
2017-09-24 16:48:23 +02:00
}
2017-07-10 21:16:59 +02:00
2020-05-09 17:01:39 +02:00
const createTitleComponent = ( disabled ) => {
2018-03-09 22:59:12 +02:00
const themeId = Setting . value ( 'theme' ) ;
2017-11-19 01:59:07 +02:00
const theme = themeStyle ( themeId ) ;
2017-11-23 20:47:51 +02:00
const folderPickerOptions = this . props . folderPickerOptions ;
if ( folderPickerOptions && folderPickerOptions . enabled ) {
2018-12-16 18:18:24 +02:00
const addFolderChildren = ( folders , pickerItems , indent ) => {
folders . sort ( ( a , b ) => {
2019-06-20 00:16:37 +02:00
const aTitle = a && a . title ? a . title : '' ;
const bTitle = b && b . title ? b . title : '' ;
return aTitle . toLowerCase ( ) < bTitle . toLowerCase ( ) ? - 1 : + 1 ;
2018-12-16 18:18:24 +02:00
} ) ;
for ( let i = 0 ; i < folders . length ; i ++ ) {
const f = folders [ i ] ;
2021-11-15 19:19:51 +02:00
const icon = Folder . unserializeIcon ( f . icon ) ;
const iconString = icon ? ` ${ icon . emoji } ` : '' ;
pickerItems . push ( { label : ` ${ ' ' . repeat ( indent ) } ${ iconString + Folder . displayTitle ( f ) } ` , value : f . id } ) ;
2018-12-16 18:18:24 +02:00
pickerItems = addFolderChildren ( f . children , pickerItems , indent + 1 ) ;
}
return pickerItems ;
2019-07-29 15:43:53 +02:00
} ;
2018-12-16 18:18:24 +02:00
2020-05-21 10:14:33 +02:00
const titlePickerItems = mustSelect => {
const folders = this . props . folders . filter ( f => f . id !== Folder . conflictFolderId ( ) ) ;
2017-11-23 20:47:51 +02:00
let output = [ ] ;
2018-03-09 22:59:12 +02:00
if ( mustSelect ) output . push ( { label : _ ( 'Move to notebook...' ) , value : null } ) ;
2019-07-12 19:32:08 +02:00
const folderTree = Folder . buildTree ( folders ) ;
2018-12-16 18:18:24 +02:00
output = addFolderChildren ( folderTree , output , 0 ) ;
2017-11-23 20:47:51 +02:00
return output ;
2019-07-29 15:43:53 +02:00
} ;
2017-11-19 01:59:07 +02:00
2017-07-16 18:06:05 +02:00
return (
2017-11-19 01:59:07 +02:00
< Dropdown
2017-11-23 20:47:51 +02:00
items = { titlePickerItems ( ! ! folderPickerOptions . mustSelect ) }
2017-11-19 01:59:07 +02:00
itemHeight = { 35 }
2020-05-09 17:01:39 +02:00
disabled = { disabled }
2018-12-16 18:18:24 +02:00
labelTransform = "trim"
2019-07-29 15:43:53 +02:00
selectedValue = { 'selectedFolderId' in folderPickerOptions ? folderPickerOptions . selectedFolderId : null }
2017-11-19 01:59:07 +02:00
itemListStyle = { {
backgroundColor : theme . backgroundColor ,
} }
headerStyle = { {
2020-06-10 23:08:59 +02:00
color : theme . colorBright2 ,
2017-11-19 01:59:07 +02:00
fontSize : theme . fontSize ,
2020-05-09 17:01:39 +02:00
opacity : disabled ? theme . disabledOpacity : 1 ,
2017-11-19 01:59:07 +02:00
} }
itemStyle = { {
color : theme . color ,
fontSize : theme . fontSize ,
} }
2017-11-23 20:41:35 +02:00
onValueChange = { async ( folderId , itemIndex ) => {
// If onValueChange is specified, use this as a callback, otherwise do the default
// which is to take the selectedNoteIds from the state and move them to the
// chosen folder.
if ( folderPickerOptions . onValueChange ) {
folderPickerOptions . onValueChange ( folderId , itemIndex ) ;
return ;
}
if ( ! folderId ) return ;
const noteIds = this . props . selectedNoteIds ;
if ( ! noteIds . length ) return ;
const folder = await Folder . load ( folderId ) ;
2020-06-13 17:20:59 +02:00
const ok = noteIds . length > 1 ? await dialogs . confirm ( this . props . parentComponent , _ ( 'Move %d notes to notebook "%s"?' , noteIds . length , folder . title ) ) : true ;
2017-11-23 20:41:35 +02:00
if ( ! ok ) return ;
2018-03-09 22:59:12 +02:00
this . props . dispatch ( { type : 'NOTE_SELECTION_END' } ) ;
2017-11-23 20:41:35 +02:00
for ( let i = 0 ; i < noteIds . length ; i ++ ) {
await Note . moveToFolder ( noteIds [ i ] , folderId ) ;
}
2017-11-23 20:47:51 +02:00
} }
2017-11-19 01:59:07 +02:00
/ >
2017-07-16 18:06:05 +02:00
) ;
} else {
2020-03-14 01:46:14 +02:00
const title = 'title' in this . props && this . props . title !== null ? this . props . title : '' ;
2020-05-09 16:33:06 +02:00
return < Text ellipsizeMode = { 'tail' } numberOfLines = { 1 } style = { this . styles ( ) . titleText } > { title } < / T e x t > ;
2017-07-16 18:06:05 +02:00
}
2019-07-29 15:43:53 +02:00
} ;
2017-07-16 18:06:05 +02:00
2019-12-28 21:50:06 +02:00
const warningComps = [ ] ;
if ( this . props . showMissingMasterKeyMessage ) warningComps . push ( this . renderWarningBox ( 'EncryptionConfig' , _ ( 'Press to set the decryption password.' ) ) ) ;
if ( this . props . hasDisabledSyncItems ) warningComps . push ( this . renderWarningBox ( 'Status' , _ ( 'Some items cannot be synchronised. Press for more info.' ) ) ) ;
2020-08-02 13:28:50 +02:00
if ( this . props . shouldUpgradeSyncTarget && this . props . showShouldUpgradeSyncTargetMessage !== false ) warningComps . push ( this . renderWarningBox ( 'UpgradeSyncTarget' , _ ( 'The sync target needs to be upgraded. Press this banner to proceed.' ) ) ) ;
2017-12-30 21:57:34 +02:00
2019-07-12 20:36:12 +02:00
const showSideMenuButton = ! ! this . props . showSideMenuButton && ! this . props . noteSelectionEnabled ;
2020-03-14 00:41:56 +02:00
const showSelectAllButton = this . props . noteSelectionEnabled ;
2019-07-12 20:36:12 +02:00
const showSearchButton = ! ! this . props . showSearchButton && ! this . props . noteSelectionEnabled ;
2018-03-16 22:17:52 +02:00
const showContextMenuButton = this . props . showContextMenuButton !== false ;
2019-07-12 20:36:12 +02:00
const showBackButton = ! ! this . props . noteSelectionEnabled || this . props . showBackButton !== false ;
let backButtonDisabled = ! this . props . historyCanGoBack ;
2019-07-29 15:43:53 +02:00
if ( this . props . noteSelectionEnabled ) backButtonDisabled = false ;
2020-05-09 17:01:39 +02:00
const headerItemDisabled = ! this . props . selectedNoteIds . length > 0 ;
2018-03-16 22:17:52 +02:00
2020-05-09 17:01:39 +02:00
const titleComp = createTitleComponent ( headerItemDisabled ) ;
2018-03-16 22:17:52 +02:00
const sideMenuComp = ! showSideMenuButton ? null : sideMenuButton ( this . styles ( ) , ( ) => this . sideMenuButton _press ( ) ) ;
2019-07-12 20:36:12 +02:00
const backButtonComp = ! showBackButton ? null : backButton ( this . styles ( ) , ( ) => this . backButton _press ( ) , backButtonDisabled ) ;
2020-03-14 00:41:56 +02:00
const selectAllButtonComp = ! showSelectAllButton ? null : selectAllButton ( this . styles ( ) , ( ) => this . selectAllButton _press ( ) ) ;
2018-03-16 22:17:52 +02:00
const searchButtonComp = ! showSearchButton ? null : searchButton ( this . styles ( ) , ( ) => this . searchButton _press ( ) ) ;
2020-05-09 17:01:39 +02:00
const deleteButtonComp = this . props . noteSelectionEnabled ? deleteButton ( this . styles ( ) , ( ) => this . deleteButton _press ( ) , headerItemDisabled ) : null ;
const duplicateButtonComp = this . props . noteSelectionEnabled ? duplicateButton ( this . styles ( ) , ( ) => this . duplicateButton _press ( ) , headerItemDisabled ) : null ;
2019-07-12 20:36:12 +02:00
const sortButtonComp = ! this . props . noteSelectionEnabled && this . props . sortButton _press ? sortButton ( this . styles ( ) , ( ) => this . props . sortButton _press ( ) ) : null ;
2018-03-09 22:59:12 +02:00
const windowHeight = Dimensions . get ( 'window' ) . height - 50 ;
2017-11-23 20:47:51 +02:00
2019-07-12 20:36:12 +02:00
const contextMenuStyle = { paddingTop : PADDING _V , paddingBottom : PADDING _V } ;
2019-07-29 15:43:53 +02:00
2019-07-12 20:36:12 +02:00
// HACK: if this button is removed during selection mode, the header layout is broken, so for now just make it 1 pixel large (normally it should be hidden)
2019-07-29 15:43:53 +02:00
if ( this . props . noteSelectionEnabled ) contextMenuStyle . width = 1 ;
const menuComp =
! menuOptionComponents . length || ! showContextMenuButton ? null : (
2020-05-21 10:14:33 +02:00
< Menu onSelect = { value => this . menu _select ( value ) } style = { this . styles ( ) . contextMenu } >
2019-07-29 15:43:53 +02:00
< MenuTrigger style = { contextMenuStyle } >
2020-10-16 17:26:19 +02:00
< Icon name = "md-ellipsis-vertical" style = { this . styles ( ) . contextMenuTrigger } / >
2019-07-29 15:43:53 +02:00
< / M e n u T r i g g e r >
< MenuOptions >
< ScrollView style = { { maxHeight : windowHeight } } > { menuOptionComponents } < / S c r o l l V i e w >
< / M e n u O p t i o n s >
< / M e n u >
) ;
2017-05-16 22:25:19 +02:00
2017-05-16 21:57:09 +02:00
return (
2019-07-29 15:43:53 +02:00
< View style = { this . styles ( ) . container } >
< View style = { { flexDirection : 'row' , alignItems : 'center' } } >
{ sideMenuComp }
{ backButtonComp }
2020-06-13 17:20:18 +02:00
{ renderUndoButton ( this . styles ( ) ) }
{ renderRedoButton ( this . styles ( ) ) }
2019-07-29 15:43:53 +02:00
{ saveButton (
this . styles ( ) ,
( ) => {
if ( this . props . onSaveButtonPress ) this . props . onSaveButtonPress ( ) ;
} ,
this . props . saveButtonDisabled === true ,
this . props . showSaveButton === true
) }
{ titleComp }
2020-03-14 00:41:56 +02:00
{ selectAllButtonComp }
2019-07-29 15:43:53 +02:00
{ searchButtonComp }
{ deleteButtonComp }
2019-10-12 00:37:16 +02:00
{ duplicateButtonComp }
2019-07-29 15:43:53 +02:00
{ sortButtonComp }
{ menuComp }
2017-12-30 21:57:34 +02:00
< / V i e w >
2019-12-28 21:50:06 +02:00
{ warningComps }
2020-06-13 17:20:59 +02:00
< DialogBox
ref = { dialogbox => {
this . dialogbox = dialogbox ;
} }
/ >
2017-05-16 21:57:09 +02:00
< / V i e w >
) ;
}
}
2017-06-11 23:11:14 +02:00
ScreenHeaderComponent . defaultProps = {
menuOptions : [ ] ,
} ;
2020-05-21 10:14:33 +02:00
const ScreenHeader = connect ( state => {
2021-08-12 17:54:10 +02:00
const syncInfo = localSyncInfoFromState ( state ) ;
2019-07-29 15:43:53 +02:00
return {
historyCanGoBack : state . historyCanGoBack ,
locale : state . settings . locale ,
folders : state . folders ,
2020-09-15 15:01:07 +02:00
themeId : state . settings . theme ,
2019-07-29 15:43:53 +02:00
noteSelectionEnabled : state . noteSelectionEnabled ,
selectedNoteIds : state . selectedNoteIds ,
2021-08-17 13:03:19 +02:00
showMissingMasterKeyMessage : showMissingMasterKeyMessage ( syncInfo , state . notLoadedMasterKeys ) ,
2019-12-28 21:50:06 +02:00
hasDisabledSyncItems : state . hasDisabledSyncItems ,
2020-08-02 13:28:50 +02:00
shouldUpgradeSyncTarget : state . settings [ 'sync.upgradeState' ] === Setting . SYNC _UPGRADE _STATE _SHOULD _DO ,
2019-07-29 15:43:53 +02:00
} ;
} ) ( ScreenHeaderComponent ) ;
module . exports = { ScreenHeader } ;