1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Support for dark/light theme

This commit is contained in:
Laurent Cozic 2017-08-01 17:59:01 +00:00
parent a270a345d3
commit cc54e32823
13 changed files with 511 additions and 323 deletions

View File

@ -7,6 +7,18 @@ import { _ } from 'lib/locale.js';
class AppNavComponent extends Component {
render() {
// if (!this.props.route) throw new Error('Route must not be null');
// let route = this.props.route;
// let Screen = null;
// Screen = this.props.screens[route.routeName].screen;
// return (
// <View style={{ flex: 1 }}>
// <Screen navigation={{ state: route }} />
// </View>
// );
if (!this.props.route) throw new Error('Route must not be null');
let route = this.props.route;

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { globalStyle } from 'lib/components/global-style.js';
import { globalStyle, themeStyle } from 'lib/components/global-style.js';
const styleObject_ = {
screen: {
@ -11,6 +11,8 @@ const styleObject_ = {
const styles_ = StyleSheet.create(styleObject_);
let rootStyles_ = {};
class BaseScreenComponent extends React.Component {
styles() {
@ -21,6 +23,18 @@ class BaseScreenComponent extends React.Component {
return styleObject_;
}
rootStyle(themeId) {
const theme = themeStyle(themeId);
if (rootStyles_[themeId]) return rootStyles_[themeId];
rootStyles_[themeId] = StyleSheet.create({
root: {
flex: 1,
backgroundColor: theme.backgroundColor,
},
});
return rootStyles_[themeId];
}
}
export { BaseScreenComponent };

View File

@ -1,3 +1,5 @@
import { Setting } from 'lib/models/setting.js';
const globalStyle = {
fontSize: 16,
margin: 15, // No text and no interactive component should be within this margin
@ -5,6 +7,8 @@ const globalStyle = {
itemMarginBottom: 10,
backgroundColor: "#ffffff",
color: "#555555", // For regular text
colorError: "red",
colorWarn: "#9A5B00",
colorFaded: "#777777", // For less important text
fontSizeSmaller: 14,
dividerColor: "#dddddd",
@ -37,4 +41,27 @@ globalStyle.lineInput = {
backgroundColor: globalStyle.backgroundColor,
};
export { globalStyle }
let themeCache_ = {};
function themeStyle(theme) {
if (themeCache_[theme]) return themeCache_[theme];
let output = Object.assign({}, globalStyle);
if (theme == Setting.THEME_LIGHT) return output;
output.backgroundColor = '#1D2024';
output.color = '#ffffff';
output.colorFaded = '#777777';
output.dividerColor = '#555555';
output.selectedColor = '#333333';
output.htmlColor = 'white';
output.raisedBackgroundColor = "#0F2051";
output.raisedColor = "#405593";
output.raisedHighlightedColor = "#ffffff";
themeCache_[theme] = output;
return themeCache_[theme];
}
export { globalStyle, themeStyle }

View File

@ -7,35 +7,15 @@ import { Checkbox } from 'lib/components/checkbox.js';
import { reg } from 'lib/registry.js';
import { Note } from 'lib/models/note.js';
import { time } from 'lib/time-utils.js';
import { globalStyle } from 'lib/components/global-style.js';
let styles = {
listItem: {
flexDirection: 'row',
//height: 40,
borderBottomWidth: 1,
borderBottomColor: globalStyle.dividerColor,
alignItems: 'center',
paddingLeft: globalStyle.marginLeft,
paddingRight: globalStyle.marginRight,
paddingTop: globalStyle.itemMarginTop,
paddingBottom: globalStyle.itemMarginBottom,
backgroundColor: globalStyle.backgroundColor,
},
listItemText: {
flex: 1,
color: globalStyle.color,
fontSize: globalStyle.fontSize,
},
};
styles.listItemFadded = Object.assign({}, styles.listItem);
styles.listItemFadded.opacity = 0.4;
styles = StyleSheet.create(styles);
import { globalStyle, themeStyle } from 'lib/components/global-style.js';
class NoteItemComponent extends Component {
constructor() {
super();
this.styles_ = {};
}
noteItem_press(noteId) {
this.props.dispatch({
type: 'NAV_GO',
@ -44,6 +24,39 @@ class NoteItemComponent extends Component {
});
}
styles() {
const theme = themeStyle(this.props.theme);
if (this.styles_[this.props.theme]) return this.styles_[this.props.theme];
this.styles_ = {};
let styles = {
listItem: {
flexDirection: 'row',
//height: 40,
borderBottomWidth: 1,
borderBottomColor: theme.dividerColor,
alignItems: 'center',
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
paddingTop: theme.itemMarginTop,
paddingBottom: theme.itemMarginBottom,
backgroundColor: theme.backgroundColor,
},
listItemText: {
flex: 1,
color: theme.color,
fontSize: theme.fontSize,
},
};
styles.listItemFadded = Object.assign({}, styles.listItem);
styles.listItemFadded.opacity = 0.4;
this.styles_[this.props.theme] = StyleSheet.create(styles);
return this.styles_[this.props.theme];
}
async todoCheckbox_change(checked) {
if (!this.props.note) return;
@ -68,11 +81,12 @@ class NoteItemComponent extends Component {
const note = this.props.note ? this.props.note : {};
const onPress = this.props.onPress;
const onCheckboxChange = this.props.onCheckboxChange;
const theme = themeStyle(this.props.theme);
const checkboxStyle = !Number(note.is_todo) ? { display: 'none' } : { color: globalStyle.color };
const checkboxStyle = !Number(note.is_todo) ? { display: 'none' } : { color: theme.color };
const checkboxChecked = !!Number(note.todo_completed);
const listItemStyle = !!Number(note.is_todo) && checkboxChecked ? styles.listItemFadded : styles.listItem;
const listItemStyle = !!Number(note.is_todo) && checkboxChecked ? this.styles().listItemFadded : this.styles().listItem;
return (
<TouchableHighlight onPress={() => this.onPress()} underlayColor="#0066FF">
@ -82,7 +96,7 @@ class NoteItemComponent extends Component {
checked={checkboxChecked}
onChange={(checked) => this.todoCheckbox_change(checked)}
/>
<Text style={styles.listItemText}>{note.title}</Text>
<Text style={this.styles().listItemText}>{note.title}</Text>
</View>
</TouchableHighlight>
);
@ -92,7 +106,9 @@ class NoteItemComponent extends Component {
const NoteItem = connect(
(state) => {
return {};
return {
theme: state.settings.theme,
};
}
)(NoteItemComponent)

View File

@ -9,7 +9,7 @@ import { Setting } from 'lib/models/setting.js';
import { FileApi } from 'lib/file-api.js';
import { FileApiDriverOneDrive } from 'lib/file-api-driver-onedrive.js';
import { reg } from 'lib/registry.js'
import { globalStyle } from 'lib/components/global-style.js';
import { themeStyle } from 'lib/components/global-style.js';
// Rather than applying a padding to the whole bar, it is applied to each
// individual component (button, picker, etc.) so that the touchable areas
@ -17,114 +17,128 @@ import { globalStyle } from 'lib/components/global-style.js';
// default height.
const PADDING_V = 10;
let styleObject = {
container: {
flexDirection: 'row',
backgroundColor: globalStyle.raisedBackgroundColor,
alignItems: 'center',
shadowColor: '#000000',
elevation: 5,
},
folderPicker: {
flex:1,
color: globalStyle.raisedHighlightedColor,
// Note: cannot set backgroundStyle as that would remove the arrow in the component
},
divider: {
borderBottomWidth: 1,
borderColor: globalStyle.dividerColor,
backgroundColor: "#0000ff"
},
sideMenuButton: {
flex: 1,
alignItems: 'center',
backgroundColor: globalStyle.raisedBackgroundColor,
paddingLeft: globalStyle.marginLeft,
paddingRight: 5,
marginRight: 2,
paddingTop: PADDING_V,
paddingBottom: PADDING_V,
},
iconButton: {
flex: 1,
backgroundColor: globalStyle.raisedBackgroundColor,
paddingLeft: 15,
paddingRight: 15,
paddingTop: PADDING_V,
paddingBottom: PADDING_V,
},
saveButton: {
flex: 0,
flexDirection: 'row',
alignItems: 'center',
padding: 10,
borderWidth: 1,
borderColor: globalStyle.raisedHighlightedColor,
borderRadius: 4,
marginRight: 8,
},
saveButtonText: {
textAlignVertical: 'center',
color: globalStyle.raisedHighlightedColor,
fontWeight: 'bold',
},
savedButtonIcon: {
fontSize: 20,
color: globalStyle.raisedHighlightedColor,
width: 18,
height: 18,
},
saveButtonIcon: {
width: 18,
height: 18,
},
contextMenuTrigger: {
fontSize: 25,
paddingRight: globalStyle.marginRight,
color: globalStyle.raisedColor,
fontWeight: 'bold',
},
contextMenu: {
backgroundColor: globalStyle.raisedBackgroundColor,
},
contextMenuItem: {
backgroundColor: globalStyle.backgroundColor,
},
contextMenuItemText: {
flex: 1,
textAlignVertical: 'center',
paddingLeft: globalStyle.marginLeft,
paddingRight: globalStyle.marginRight,
paddingTop: globalStyle.itemMarginTop,
paddingBottom: globalStyle.itemMarginBottom,
color: globalStyle.color,
backgroundColor: globalStyle.backgroundColor,
fontSize: globalStyle.fontSize,
},
titleText: {
flex: 1,
marginLeft: 0,
color: globalStyle.raisedHighlightedColor,
fontWeight: 'bold',
fontSize: globalStyle.fontSize,
}
};
styleObject.topIcon = Object.assign({}, globalStyle.icon);
styleObject.topIcon.flex = 1;
styleObject.topIcon.textAlignVertical = 'center';
styleObject.topIcon.color = globalStyle.raisedColor;
styleObject.backButton = Object.assign({}, styleObject.iconButton);
styleObject.backButton.marginRight = 1;
styleObject.backButtonDisabled = Object.assign({}, styleObject.backButton, { opacity: globalStyle.disabledOpacity });
styleObject.saveButtonDisabled = Object.assign({}, styleObject.saveButton, { opacity: globalStyle.disabledOpacity });
const styles = StyleSheet.create(styleObject);
class ScreenHeaderComponent extends Component {
constructor() {
super();
this.styles_ = {};
}
styles() {
const themeId = Setting.value('theme');
if (this.styles_[themeId]) return this.styles_[themeId];
this.styles_ = {};
const theme = themeStyle(themeId);
let styleObject = {
container: {
flexDirection: 'row',
backgroundColor: theme.raisedBackgroundColor,
alignItems: 'center',
shadowColor: '#000000',
elevation: 5,
},
folderPicker: {
flex:1,
color: theme.raisedHighlightedColor,
// Note: cannot set backgroundStyle as that would remove the arrow in the component
},
divider: {
borderBottomWidth: 1,
borderColor: theme.dividerColor,
backgroundColor: "#0000ff"
},
sideMenuButton: {
flex: 1,
alignItems: 'center',
backgroundColor: theme.raisedBackgroundColor,
paddingLeft: theme.marginLeft,
paddingRight: 5,
marginRight: 2,
paddingTop: PADDING_V,
paddingBottom: PADDING_V,
},
iconButton: {
flex: 1,
backgroundColor: theme.raisedBackgroundColor,
paddingLeft: 15,
paddingRight: 15,
paddingTop: PADDING_V,
paddingBottom: PADDING_V,
},
saveButton: {
flex: 0,
flexDirection: 'row',
alignItems: 'center',
padding: 10,
borderWidth: 1,
borderColor: theme.raisedHighlightedColor,
borderRadius: 4,
marginRight: 8,
},
saveButtonText: {
textAlignVertical: 'center',
color: theme.raisedHighlightedColor,
fontWeight: 'bold',
},
savedButtonIcon: {
fontSize: 20,
color: theme.raisedHighlightedColor,
width: 18,
height: 18,
},
saveButtonIcon: {
width: 18,
height: 18,
},
contextMenuTrigger: {
fontSize: 25,
paddingRight: theme.marginRight,
color: theme.raisedColor,
fontWeight: 'bold',
},
contextMenu: {
backgroundColor: theme.raisedBackgroundColor,
},
contextMenuItem: {
backgroundColor: theme.backgroundColor,
},
contextMenuItemText: {
flex: 1,
textAlignVertical: 'center',
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
paddingTop: theme.itemMarginTop,
paddingBottom: theme.itemMarginBottom,
color: theme.color,
backgroundColor: theme.backgroundColor,
fontSize: theme.fontSize,
},
titleText: {
flex: 1,
marginLeft: 0,
color: theme.raisedHighlightedColor,
fontWeight: 'bold',
fontSize: theme.fontSize,
}
};
styleObject.topIcon = Object.assign({}, theme.icon);
styleObject.topIcon.flex = 1;
styleObject.topIcon.textAlignVertical = 'center';
styleObject.topIcon.color = theme.raisedColor;
styleObject.backButton = Object.assign({}, styleObject.iconButton);
styleObject.backButton.marginRight = 1;
styleObject.backButtonDisabled = Object.assign({}, styleObject.backButton, { opacity: theme.disabledOpacity });
styleObject.saveButtonDisabled = Object.assign({}, styleObject.saveButton, { opacity: theme.disabledOpacity });
this.styles_[themeId] = StyleSheet.create(styleObject);
return this.styles_[themeId];
}
sideMenuButton_press() {
this.props.dispatch({ type: 'SIDE_MENU_TOGGLE' });
}
@ -173,7 +187,7 @@ class ScreenHeaderComponent extends Component {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.sideMenuButton}>
<Icon name='md-menu' style={styleObject.topIcon} />
<Icon name='md-menu' style={styles.topIcon} />
</View>
</TouchableOpacity>
);
@ -218,32 +232,32 @@ class ScreenHeaderComponent extends Component {
for (let i = 0; i < this.props.menuOptions.length; i++) {
let o = this.props.menuOptions[i];
menuOptionComponents.push(
<MenuOption value={o.onPress} key={'menuOption_' + key++} style={styles.contextMenuItem}>
<Text style={styles.contextMenuItemText}>{o.title}</Text>
<MenuOption value={o.onPress} key={'menuOption_' + key++} style={this.styles().contextMenuItem}>
<Text style={this.styles().contextMenuItemText}>{o.title}</Text>
</MenuOption>);
}
if (menuOptionComponents.length) {
menuOptionComponents.push(<View key={'menuOption_' + key++} style={styles.divider}/>);
menuOptionComponents.push(<View key={'menuOption_' + key++} style={this.styles().divider}/>);
}
menuOptionComponents.push(
<MenuOption value={() => this.log_press()} key={'menuOption_' + key++} style={styles.contextMenuItem}>
<Text style={styles.contextMenuItemText}>{_('Log')}</Text>
<MenuOption value={() => this.log_press()} key={'menuOption_' + key++} style={this.styles().contextMenuItem}>
<Text style={this.styles().contextMenuItemText}>{_('Log')}</Text>
</MenuOption>);
menuOptionComponents.push(
<MenuOption value={() => this.status_press()} key={'menuOption_' + key++} style={styles.contextMenuItem}>
<Text style={styles.contextMenuItemText}>{_('Status')}</Text>
<MenuOption value={() => this.status_press()} key={'menuOption_' + key++} style={this.styles().contextMenuItem}>
<Text style={this.styles().contextMenuItemText}>{_('Status')}</Text>
</MenuOption>);
if (menuOptionComponents.length) {
menuOptionComponents.push(<View key={'menuOption_' + key++} style={styles.divider}/>);
menuOptionComponents.push(<View key={'menuOption_' + key++} style={this.styles().divider}/>);
}
menuOptionComponents.push(
<MenuOption value={() => this.config_press()} key={'menuOption_' + key++} style={styles.contextMenuItem}>
<Text style={styles.contextMenuItemText}>{_('Configuration')}</Text>
<MenuOption value={() => this.config_press()} key={'menuOption_' + key++} style={this.styles().contextMenuItem}>
<Text style={this.styles().contextMenuItemText}>{_('Configuration')}</Text>
</MenuOption>);
const createTitleComponent = () => {
@ -256,29 +270,29 @@ class ScreenHeaderComponent extends Component {
}
return (
<View style={{ flex: 1 }}>
<Picker style={styles.folderPicker} selectedValue={p.selectedValue} onValueChange={(itemValue, itemIndex) => { if (p.onValueChange) p.onValueChange(itemValue, itemIndex); }}>
<Picker style={this.styles().folderPicker} selectedValue={p.selectedValue} onValueChange={(itemValue, itemIndex) => { if (p.onValueChange) p.onValueChange(itemValue, itemIndex); }}>
{ items }
</Picker>
</View>
);
} else {
let title = 'title' in this.props && this.props.title !== null ? this.props.title : '';
return <Text style={styles.titleText}>{title}</Text>
return <Text style={this.styles().titleText}>{title}</Text>
}
}
const titleComp = createTitleComponent();
return (
<View style={styles.container} >
{ sideMenuButton(styles, () => this.sideMenuButton_press()) }
{ backButton(styles, () => this.backButton_press(), !this.props.historyCanGoBack) }
{ saveButton(styles, () => { if (this.props.onSaveButtonPress) this.props.onSaveButtonPress() }, this.props.saveButtonDisabled === true, this.props.showSaveButton === true) }
<View style={this.styles().container} >
{ sideMenuButton(this.styles(), () => this.sideMenuButton_press()) }
{ backButton(this.styles(), () => this.backButton_press(), !this.props.historyCanGoBack) }
{ saveButton(this.styles(), () => { if (this.props.onSaveButtonPress) this.props.onSaveButtonPress() }, this.props.saveButtonDisabled === true, this.props.showSaveButton === true) }
{ titleComp }
{ searchButton(styles, () => this.searchButton_press()) }
<Menu onSelect={(value) => this.menu_select(value)} style={styles.contextMenu}>
{ searchButton(this.styles(), () => this.searchButton_press()) }
<Menu onSelect={(value) => this.menu_select(value)} style={this.styles().contextMenu}>
<MenuTrigger style={{ paddingTop: PADDING_V, paddingBottom: PADDING_V }}>
<Text style={styles.contextMenuTrigger}> &#8942;</Text>
<Text style={this.styles().contextMenuTrigger}> &#8942;</Text>
</MenuTrigger>
<MenuOptions>
{ menuOptionComponents }
@ -299,6 +313,7 @@ const ScreenHeader = connect(
return {
historyCanGoBack: state.historyCanGoBack,
locale: state.settings.locale,
theme: state.settings.theme,
};
}
)(ScreenHeaderComponent)

View File

@ -4,50 +4,64 @@ import { connect } from 'react-redux'
import { ScreenHeader } from 'lib/components/screen-header.js';
import { _, setLocale } from 'lib/locale.js';
import { BaseScreenComponent } from 'lib/components/base-screen.js';
import { globalStyle } from 'lib/components/global-style.js';
import { themeStyle } from 'lib/components/global-style.js';
import { Setting } from 'lib/models/setting.js';
let styles = {
settingContainer: {
borderBottomWidth: 1,
borderBottomColor: globalStyle.dividerColor,
paddingTop: globalStyle.marginTop,
paddingBottom: globalStyle.marginBottom,
paddingLeft: globalStyle.marginLeft,
paddingRight: globalStyle.marginRight,
},
settingText: {
fontWeight: 'bold',
color: globalStyle.color,
fontSize: globalStyle.fontSize,
},
settingControl: {
color: globalStyle.color,
},
pickerItem: {
fontSize: globalStyle.fontSize,
}
}
styles.switchSettingText = Object.assign({}, styles.settingText);
styles.switchSettingText.width = '80%';
styles.switchSettingContainer = Object.assign({}, styles.settingContainer);
styles.switchSettingContainer.flexDirection = 'row';
styles.switchSettingContainer.justifyContent = 'space-between';
styles.switchSettingControl = Object.assign({}, styles.settingControl);
delete styles.switchSettingControl.color;
styles.switchSettingControl.width = '20%';
styles = StyleSheet.create(styles);
class ConfigScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
constructor() {
super();
this.styles_ = {};
}
styles() {
const themeId = this.props.theme;
const theme = themeStyle(themeId);
if (this.styles_[themeId]) return this.styles_[themeId];
this.styles_ = {};
let styles = {
settingContainer: {
borderBottomWidth: 1,
borderBottomColor: theme.dividerColor,
paddingTop: theme.marginTop,
paddingBottom: theme.marginBottom,
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
},
settingText: {
fontWeight: 'bold',
color: theme.color,
fontSize: theme.fontSize,
},
settingControl: {
color: theme.color,
},
pickerItem: {
fontSize: theme.fontSize,
}
}
styles.switchSettingText = Object.assign({}, styles.settingText);
styles.switchSettingText.width = '80%';
styles.switchSettingContainer = Object.assign({}, styles.settingContainer);
styles.switchSettingContainer.flexDirection = 'row';
styles.switchSettingContainer.justifyContent = 'space-between';
styles.switchSettingControl = Object.assign({}, styles.settingControl);
delete styles.switchSettingControl.color;
styles.switchSettingControl.width = '20%';
this.styles_[themeId] = StyleSheet.create(styles);
return this.styles_[themeId];
}
settingToComponent(key, value) {
let output = null;
@ -72,25 +86,25 @@ class ConfigScreenComponent extends BaseScreenComponent {
}
return (
<View key={key} style={styles.settingContainer}>
<Text key="label" style={styles.settingText}>{md.label()}</Text>
<Picker key="control" style={styles.settingControl} selectedValue={value} onValueChange={(itemValue, itemIndex) => updateSettingValue(key, itemValue)} >
<View key={key} style={this.styles().settingContainer}>
<Text key="label" style={this.styles().settingText}>{md.label()}</Text>
<Picker key="control" style={this.styles().settingControl} selectedValue={value} onValueChange={(itemValue, itemIndex) => updateSettingValue(key, itemValue)} >
{ items }
</Picker>
</View>
);
} else if (md.type == Setting.TYPE_BOOL) {
return (
<View key={key} style={styles.switchSettingContainer}>
<Text key="label" style={styles.switchSettingText}>{md.label()}</Text>
<Switch key="control" style={styles.switchSettingControl} value={value} onValueChange={(value) => updateSettingValue(key, value)} />
<View key={key} style={this.styles().switchSettingContainer}>
<Text key="label" style={this.styles().switchSettingText}>{md.label()}</Text>
<Switch key="control" style={this.styles().switchSettingControl} value={value} onValueChange={(value) => updateSettingValue(key, value)} />
</View>
);
} else if (md.type == Setting.TYPE_INT) {
return (
<View key={key} style={styles.settingContainer}>
<Text key="label" style={styles.settingText}>{md.label()}</Text>
<Slider key="control" style={styles.settingControl} value={value} onValueChange={(value) => updateSettingValue(key, value)} />
<View key={key} style={this.styles().settingContainer}>
<Text key="label" style={this.styles().settingText}>{md.label()}</Text>
<Slider key="control" style={this.styles().settingControl} value={value} onValueChange={(value) => updateSettingValue(key, value)} />
</View>
);
} else {
@ -115,9 +129,9 @@ class ConfigScreenComponent extends BaseScreenComponent {
}
return (
<View style={this.styles().screen}>
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader title={_('Configuration')}/>
<View style={styles.body}>
<View style={this.styles().body}>
{ settingComps }
</View>
</View>
@ -128,7 +142,10 @@ class ConfigScreenComponent extends BaseScreenComponent {
const ConfigScreen = connect(
(state) => {
return { settings: state.settings };
return {
settings: state.settings,
theme: state.settings.theme,
};
}
)(ConfigScreenComponent)

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { View, Button, TextInput } from 'react-native';
import { View, Button, TextInput, StyleSheet } from 'react-native';
import { connect } from 'react-redux'
import { Log } from 'lib/log.js'
import { ActionButton } from 'lib/components/action-button.js';
@ -9,6 +9,7 @@ import { ScreenHeader } from 'lib/components/screen-header.js';
import { reg } from 'lib/registry.js';
import { BaseScreenComponent } from 'lib/components/base-screen.js';
import { dialogs } from 'lib/dialogs.js';
import { themeStyle } from 'lib/components/global-style.js';
import { _ } from 'lib/locale.js';
class FolderScreenComponent extends BaseScreenComponent {
@ -23,6 +24,23 @@ class FolderScreenComponent extends BaseScreenComponent {
folder: Folder.new(),
lastSavedFolder: null,
};
this.styles_ = {};
}
styles() {
const theme = themeStyle(this.props.theme);
if (this.styles_[this.props.theme]) return this.styles_[this.props.theme];
this.styles_ = {};
let styles = {
textInput: {
color: theme.color,
},
};
this.styles_[this.props.theme] = StyleSheet.create(styles);
return this.styles_[this.props.theme];
}
componentWillMount() {
@ -87,14 +105,14 @@ class FolderScreenComponent extends BaseScreenComponent {
let saveButtonDisabled = !this.isModified();
return (
<View style={this.styles().screen}>
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader
title={_('Edit notebook')}
showSaveButton={true}
saveButtonDisabled={saveButtonDisabled}
onSaveButtonPress={() => this.saveFolderButton_press()}
/>
<TextInput autoFocus={true} value={this.state.folder.title} onChangeText={(text) => this.title_changeText(text)} />
<TextInput style={this.styles().textInput} autoFocus={true} value={this.state.folder.title} onChangeText={(text) => this.title_changeText(text)} />
<dialogs.DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
</View>
);
@ -106,6 +124,7 @@ const FolderScreen = connect(
(state) => {
return {
folderId: state.selectedFolderId,
theme: state.settings.theme,
};
}
)(FolderScreenComponent)

View File

@ -1,10 +1,11 @@
import React, { Component } from 'react';
import { ListView, View, Text, Button } from 'react-native';
import { ListView, View, Text, Button, StyleSheet } from 'react-native';
import { connect } from 'react-redux'
import { Log } from 'lib/log.js'
import { reg } from 'lib/registry.js'
import { ScreenHeader } from 'lib/components/screen-header.js';
import { time } from 'lib/time-utils'
import { themeStyle } from 'lib/components/global-style.js';
import { Logger } from 'lib/logger.js';
import { BaseScreenComponent } from 'lib/components/base-screen.js';
import { _ } from 'lib/locale.js';
@ -23,6 +24,38 @@ class LogScreenComponent extends BaseScreenComponent {
this.state = {
dataSource: ds,
};
this.styles_ = {};
}
styles() {
const theme = themeStyle(this.props.theme);
if (this.styles_[this.props.theme]) return this.styles_[this.props.theme];
this.styles_ = {};
let styles = {
row: {
flexDirection: 'row',
paddingLeft: 1,
paddingRight: 1,
paddingTop:0,
paddingBottom:0,
},
rowText: {
fontFamily: 'monospace',
fontSize: 10,
color: theme.color,
},
};
styles.rowTextError = Object.assign({}, styles.rowText);
styles.rowTextError.color = theme.colorError;
styles.rowTextWarn = Object.assign({}, styles.rowWarn);
styles.rowTextWarn.color = theme.colorWarn;
this.styles_[this.props.theme] = StyleSheet.create(styles);
return this.styles_[this.props.theme];
}
componentWillMount() {
@ -38,25 +71,20 @@ class LogScreenComponent extends BaseScreenComponent {
render() {
let renderRow = (item) => {
let color = 'black';
if (item.level == Logger.LEVEL_WARN) color = '#9A5B00';
if (item.level == Logger.LEVEL_ERROR) color = 'red';
let style = {
fontFamily: 'monospace',
fontSize: 10,
color: color,
};
let textStyle = this.styles().rowText;
if (item.level == Logger.LEVEL_WARN) textStyle = this.styles().rowTextWarn;
if (item.level == Logger.LEVEL_ERROR) textStyle = this.styles().rowTextError;
return (
<View style={{flexDirection: 'row', paddingLeft: 1, paddingRight: 1, paddingTop:0, paddingBottom:0 }}>
<Text style={style}>{time.formatMsToLocal(item.timestamp, 'MM-DDTHH:mm:ss') + ': ' + item.message}</Text>
<View style={this.styles().row}>
<Text style={textStyle}>{time.formatMsToLocal(item.timestamp, 'MM-DDTHH:mm:ss') + ': ' + item.message}</Text>
</View>
);
}
// `enableEmptySections` is to fix this warning: https://github.com/FaridSafi/react-native-gifted-listview/issues/39
return (
<View style={this.styles().screen}>
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader title={_('Log')}/>
<ListView
dataSource={this.state.dataSource}
@ -72,7 +100,9 @@ class LogScreenComponent extends BaseScreenComponent {
const LogScreen = connect(
(state) => {
return {};
return {
theme: state.settings.theme,
};
}
)(LogScreenComponent)

View File

@ -7,6 +7,8 @@ import { NoteList } from 'lib/components/note-list.js'
import { Folder } from 'lib/models/folder.js'
import { Tag } from 'lib/models/tag.js'
import { Note } from 'lib/models/note.js'
import { Setting } from 'lib/models/setting.js'
import { themeStyle } from 'lib/components/global-style.js';
import { ScreenHeader } from 'lib/components/screen-header.js';
import { MenuOption, Text } from 'react-native-popup-menu';
import { _ } from 'lib/locale.js';
@ -131,7 +133,13 @@ class NotesScreenComponent extends BaseScreenComponent {
let title = parent ? parent.title : null;
const addFolderNoteButtons = this.props.selectedFolderId && this.props.selectedFolderId != Folder.conflictFolderId();
let rootStyle = Object.assign({}, this.styleObject().screen);
const theme = themeStyle(Setting.value('theme'));
let rootStyle = {
flex: 1,
backgroundColor: theme.backgroundColor,
}
if (!this.props.visible) {
rootStyle.flex = 0.001; // This is a bit of a hack but it seems to work fine - it makes the component invisible but without unmounting it
}
@ -160,6 +168,7 @@ const NotesScreen = connect(
notesOrder: state.notesOrder,
notesSource: state.notesSource,
uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop,
theme: state.settings.theme,
};
}
)(NotesScreenComponent)

View File

@ -7,30 +7,7 @@ import { _ } from 'lib/locale.js';
import { Note } from 'lib/models/note.js';
import { NoteItem } from 'lib/components/note-item.js';
import { BaseScreenComponent } from 'lib/components/base-screen.js';
import { globalStyle } from 'lib/components/global-style.js';
let styles = {
body: {
flex: 1,
},
searchContainer: {
flexDirection: 'row',
alignItems: 'center',
borderWidth: 1,
borderColor: globalStyle.dividerColor,
}
}
styles.searchTextInput = Object.assign({}, globalStyle.lineInput);
styles.searchTextInput.paddingLeft = globalStyle.marginLeft;
styles.searchTextInput.flex = 1;
styles.clearIcon = Object.assign({}, globalStyle.icon);
styles.clearIcon.color = globalStyle.colorFaded;
styles.clearIcon.paddingRight = globalStyle.marginRight;
styles.clearIcon.backgroundColor = globalStyle.backgroundColor;
styles = StyleSheet.create(styles);
import { themeStyle } from 'lib/components/global-style.js';
class SearchScreenComponent extends BaseScreenComponent {
@ -45,6 +22,40 @@ class SearchScreenComponent extends BaseScreenComponent {
notes: [],
};
this.isMounted_ = false;
this.styles_ = {};
}
styles() {
const theme = themeStyle(this.props.theme);
if (this.styles_[this.props.theme]) return this.styles_[this.props.theme];
this.styles_ = {};
let styles = {
body: {
flex: 1,
},
searchContainer: {
flexDirection: 'row',
alignItems: 'center',
borderWidth: 1,
borderColor: theme.dividerColor,
}
}
styles.searchTextInput = Object.assign({}, theme.lineInput);
styles.searchTextInput.paddingLeft = theme.marginLeft;
styles.searchTextInput.flex = 1;
styles.searchTextInput.backgroundColor = theme.backgroundColor;
styles.searchTextInput.color = theme.color;
styles.clearIcon = Object.assign({}, theme.icon);
styles.clearIcon.color = theme.colorFaded;
styles.clearIcon.paddingRight = theme.marginRight;
styles.clearIcon.backgroundColor = theme.backgroundColor;
this.styles_[this.props.theme] = StyleSheet.create(styles);
return this.styles_[this.props.theme];
}
componentDidMount() {
@ -116,12 +127,12 @@ class SearchScreenComponent extends BaseScreenComponent {
if (!this.isMounted_) return null;
return (
<View style={this.styles().screen}>
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader title={_('Search')}/>
<View style={styles.body}>
<View style={styles.searchContainer}>
<View style={this.styles().body}>
<View style={this.styles().searchContainer}>
<TextInput
style={styles.searchTextInput}
style={this.styles().searchTextInput}
autoFocus={true}
underlineColorAndroid="#ffffff00"
onSubmitEditing={() => { this.searchTextInput_submit() }}
@ -129,7 +140,7 @@ class SearchScreenComponent extends BaseScreenComponent {
value={this.state.query}
/>
<TouchableHighlight onPress={() => this.clearButton_press() }>
<Icon name='md-close-circle' style={styles.clearIcon} />
<Icon name='md-close-circle' style={this.styles().clearIcon} />
</TouchableHighlight>
</View>
@ -149,6 +160,7 @@ const SearchScreen = connect(
(state) => {
return {
query: state.searchQuery,
theme: state.settings.theme,
};
}
)(SearchScreenComponent)

View File

@ -13,7 +13,7 @@ import { Folder } from 'lib/models/folder.js';
import { ReportService } from 'lib/services/report.js';
import { _ } from 'lib/locale.js';
import { BaseScreenComponent } from 'lib/components/base-screen.js';
import { globalStyle } from 'lib/components/global-style.js';
import { globalStyle, themeStyle } from 'lib/components/global-style.js';
const styles = StyleSheet.create({
body: {
@ -46,6 +46,8 @@ class StatusScreenComponent extends BaseScreenComponent {
}
render() {
const theme = themeStyle(this.props.theme);
function renderBody(report) {
let output = [];
let baseStyle = {
@ -54,7 +56,8 @@ class StatusScreenComponent extends BaseScreenComponent {
paddingTop: 0,
paddingBottom: 0,
flex: 0,
fontSize: globalStyle.fontSize,
color: theme.color,
fontSize: theme.fontSize,
};
for (let i = 0; i < report.length; i++) {
let section = report[i];
@ -77,7 +80,7 @@ class StatusScreenComponent extends BaseScreenComponent {
let body = renderBody(this.state.report);
return (
<View style={this.styles().screen}>
<View style={this.rootStyle(this.props.theme).root}>
<ScreenHeader title={_('Status')}/>
<View style={styles.body}>
{ body }
@ -91,7 +94,9 @@ class StatusScreenComponent extends BaseScreenComponent {
const StatusScreen = connect(
(state) => {
return {};
return {
theme: state.settings.theme,
};
}
)(StatusScreenComponent)

View File

@ -10,60 +10,7 @@ import { FoldersScreenUtils } from 'lib/components/screens/folders-utils.js'
import { Synchronizer } from 'lib/synchronizer.js';
import { reg } from 'lib/registry.js';
import { _ } from 'lib/locale.js';
import { globalStyle } from 'lib/components/global-style.js';
let styles = {
menu: {
flex: 1,
backgroundColor: globalStyle.backgroundColor,
borderTopWidth: 1,
borderTopColor: globalStyle.dividerColor,
},
button: {
flex: 1,
flexDirection: 'row',
height: 36,
alignItems: 'center',
paddingLeft: globalStyle.marginLeft,
paddingRight: globalStyle.marginRight,
},
buttonText: {
flex: 1,
color: globalStyle.color,
paddingLeft: 10,
fontSize: globalStyle.fontSize,
},
syncStatus: {
paddingLeft: globalStyle.marginLeft,
paddingRight: globalStyle.marginRight,
color: globalStyle.colorFaded,
fontSize: globalStyle.fontSizeSmaller,
},
tagItemList: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap'
},
};
styles.folderButton = Object.assign({}, styles.button);
styles.folderButtonText = Object.assign({}, styles.buttonText);
styles.folderButtonSelected = Object.assign({}, styles.folderButton);
styles.folderButtonSelected.backgroundColor = globalStyle.selectedColor;
styles.folderIcon = Object.assign({}, globalStyle.icon);
styles.folderIcon.color = '#0072d5';
styles.tagButton = Object.assign({}, styles.button);
styles.tagButtonSelected = Object.assign({}, styles.tagButton);
styles.tagButtonSelected.backgroundColor = globalStyle.selectedColor;
styles.tagButtonSelected.borderRadius = 1000;
styles.tagButtonText = Object.assign({}, styles.buttonText);
styles.tagButtonText.flex = 0;
styles.syncButton = Object.assign({}, styles.button);
styles.syncButtonText = Object.assign({}, styles.buttonText);
styles = StyleSheet.create(styles);
import { globalStyle, themeStyle } from 'lib/components/global-style.js';
class SideMenuContentComponent extends Component {
@ -72,6 +19,68 @@ class SideMenuContentComponent extends Component {
this.state = { syncReportText: '',
//width: 0,
};
this.styles_ = {};
}
styles() {
const theme = themeStyle(this.props.theme);
if (this.styles_[this.props.theme]) return this.styles_[this.props.theme];
this.styles_ = {};
let styles = {
menu: {
flex: 1,
backgroundColor: theme.backgroundColor,
borderTopWidth: 1,
borderTopColor: theme.dividerColor,
},
button: {
flex: 1,
flexDirection: 'row',
height: 36,
alignItems: 'center',
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
},
buttonText: {
flex: 1,
color: theme.color,
paddingLeft: 10,
fontSize: theme.fontSize,
},
syncStatus: {
paddingLeft: theme.marginLeft,
paddingRight: theme.marginRight,
color: theme.colorFaded,
fontSize: theme.fontSizeSmaller,
},
tagItemList: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap'
},
};
styles.folderButton = Object.assign({}, styles.button);
styles.folderButtonText = Object.assign({}, styles.buttonText);
styles.folderButtonSelected = Object.assign({}, styles.folderButton);
styles.folderButtonSelected.backgroundColor = theme.selectedColor;
styles.folderIcon = Object.assign({}, theme.icon);
styles.folderIcon.color = '#0072d5';
styles.tagButton = Object.assign({}, styles.button);
styles.tagButtonSelected = Object.assign({}, styles.tagButton);
styles.tagButtonSelected.backgroundColor = theme.selectedColor;
styles.tagButtonSelected.borderRadius = 1000;
styles.tagButtonText = Object.assign({}, styles.buttonText);
styles.tagButtonText.flex = 0;
styles.syncButton = Object.assign({}, styles.button);
styles.syncButtonText = Object.assign({}, styles.buttonText);
this.styles_[this.props.theme] = StyleSheet.create(styles);
return this.styles_[this.props.theme];
}
folder_press(folder) {
@ -124,28 +133,28 @@ class SideMenuContentComponent extends Component {
}
folderItem(folder, selected) {
const iconComp = selected ? <Icon name='md-folder-open' style={styles.folderIcon} /> : <Icon name='md-folder' style={styles.folderIcon} />;
const folderButtonStyle = selected ? styles.folderButtonSelected : styles.folderButton;
const iconComp = selected ? <Icon name='md-folder-open' style={this.styles().folderIcon} /> : <Icon name='md-folder' style={this.styles().folderIcon} />;
const folderButtonStyle = selected ? this.styles().folderButtonSelected : this.styles().folderButton;
return (
<TouchableOpacity key={folder.id} onPress={() => { this.folder_press(folder) }}>
<View style={folderButtonStyle}>
{ iconComp }
<Text numberOfLines={1} style={styles.folderButtonText}>{folder.title}</Text>
<Text numberOfLines={1} style={this.styles().folderButtonText}>{folder.title}</Text>
</View>
</TouchableOpacity>
);
}
tagItem(tag, selected) {
const iconComp = <Icon name='md-pricetag' style={styles.folderIcon} />
const tagButtonStyle = selected ? styles.tagButtonSelected : styles.tagButton;
const iconComp = <Icon name='md-pricetag' style={this.styles().folderIcon} />
const tagButtonStyle = selected ? this.styles().tagButtonSelected : this.styles().tagButton;
return (
<TouchableOpacity key={tag.id} onPress={() => { this.tag_press(tag) }}>
<View style={tagButtonStyle}>
{ iconComp }
<Text numberOfLines={1} style={styles.tagButtonText}>{tag.title}</Text>
<Text numberOfLines={1} style={this.styles().tagButtonText}>{tag.title}</Text>
</View>
</TouchableOpacity>
);
@ -157,9 +166,9 @@ class SideMenuContentComponent extends Component {
return (
<TouchableOpacity key={'synchronize_button'} onPress={() => { this.synchronize_press() }}>
<View style={styles.syncButton}>
<View style={this.styles().syncButton}>
{ iconComp }
<Text style={styles.syncButtonText}>{title}</Text>
<Text style={this.styles().syncButtonText}>{title}</Text>
</View>
</TouchableOpacity>
);
@ -193,7 +202,7 @@ class SideMenuContentComponent extends Component {
}
items.push(
<View style={styles.tagItemList} key="tag_items">
<View style={this.styles().tagItemList} key="tag_items">
{tagItems}
</View>
);
@ -207,7 +216,7 @@ class SideMenuContentComponent extends Component {
items.push(this.synchronizeButton(this.props.syncStarted ? 'cancel' : 'sync'));
items.push(<Text key='sync_report' style={styles.syncStatus}>{syncReportText}</Text>);
items.push(<Text key='sync_report' style={this.styles().syncStatus}>{syncReportText}</Text>);
items.push(<View style={{ height: globalStyle.marginBottom }} key='bottom_padding_hack'/>);
@ -216,7 +225,7 @@ class SideMenuContentComponent extends Component {
<View style={{flexDirection:'row'}}>
<Image style={{flex:1, height: 100}} source={require('../images/SideMenuHeader.png')} />
</View>
<ScrollView scrollsToTop={false} style={styles.menu}>
<ScrollView scrollsToTop={false} style={this.styles().menu}>
{ items }
</ScrollView>
</View>
@ -235,6 +244,7 @@ const SideMenuContent = connect(
selectedTagId: state.selectedTagId,
notesParentType: state.notesParentType,
locale: state.settings.locale,
theme: state.settings.theme,
};
}
)(SideMenuContentComponent)

View File

@ -340,11 +340,13 @@ const reducer = (state = defaultState, action) => {
newState = Object.assign({}, state);
newState.searchQuery = action.query.trim();
break;
case 'SET_APP_STATE':
newState = Object.assign({}, state);
newState.appState = action.state;
break;
}
} catch (error) {