Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RNMobile] Try dark mode (iOS) #17067

Merged
merged 24 commits into from
Aug 23, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7ebe160
Adding dark mode component implemented on list and list block
etoledom Aug 14, 2019
8a4a8a4
Adding DarkMode handling to RichText, ToolBar and SafeArea
etoledom Aug 14, 2019
8958ff6
Mobile: Using DarkMode as HOC
etoledom Aug 16, 2019
a1a26a5
Merge commit 'bbe692b' into rnmobile/try-dark-mode
etoledom Aug 20, 2019
8bb6d0e
iOS DarkMode: Modified colors on block list and block container
etoledom Aug 20, 2019
aa61ee7
iOS DarkMode: Improved Header Toolbar colors
etoledom Aug 20, 2019
d3c7eef
iOS DarkMode: Removing background from buttons
etoledom Aug 20, 2019
0d8f630
iOS DarkMode warning and unsupported
etoledom Aug 20, 2019
580b63b
iOS DarkMode: MediaPlaceholder
etoledom Aug 21, 2019
43bc042
iOS DarkMode: BottomSheets
etoledom Aug 21, 2019
d79f027
iOS DarkMode: Inserter
etoledom Aug 21, 2019
c096c3c
iOS DarkMode: DefaultBlockAppender
etoledom Aug 21, 2019
c826cf1
iOS DarkMode: PostTite
etoledom Aug 21, 2019
16ad3d8
Update hardcoded colors with variables
etoledom Aug 21, 2019
8654cb1
iOS DarkMode: Fix bottom-sheet cell value color
etoledom Aug 21, 2019
2809ebf
iOS DarkMode: More - PageBreak - Add Block Here
etoledom Aug 21, 2019
67cefed
iOS DarkMode: Better text color
etoledom Aug 22, 2019
8cb3708
iOS Darkmode: Code block
etoledom Aug 22, 2019
bf2a1b5
iOS DarkMode: HTML View
etoledom Aug 22, 2019
3f71f3d
iOS DarkMode: Improve colors on SafeArea
etoledom Aug 22, 2019
5aee1ce
Fix toolbar not avoiding keyboard regression
etoledom Aug 23, 2019
852fa05
Fix native unit tests
etoledom Aug 23, 2019
327d545
Fix gutenberg-mobile unit tests
etoledom Aug 23, 2019
de173df
Adding RNDarkMode mocks
etoledom Aug 23, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { withDispatch, withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { getBlockType } from '@wordpress/blocks';
import { __, sprintf } from '@wordpress/i18n';
import { useStyle, withTheme } from '@wordpress/components';

/**
* Internal dependencies
Expand Down Expand Up @@ -111,8 +112,10 @@ class BlockListBlock extends Component {
isValid,
showTitle,
title,
theme,
} = this.props;

const blockContainerStyle = useStyle( styles.blockContainer, styles.blockContainerDark, theme );
const borderColor = isSelected ? focusedBorderColor : 'transparent';

const accessibilityLabel = this.getAccessibilityLabel();
Expand All @@ -127,7 +130,7 @@ class BlockListBlock extends Component {
{ showTitle && this.renderBlockTitle() }
<View
accessibilityLabel={ accessibilityLabel }
style={ [ ! isSelected && styles.blockContainer, isSelected && styles.blockContainerFocused ] }
style={ [ ! isSelected && blockContainerStyle, isSelected && styles.blockContainerFocused ] }
>
{ isValid && this.getBlockForType() }
{ ! isValid &&
Expand Down Expand Up @@ -217,4 +220,5 @@ export default compose( [
},
};
} ),
withTheme,
] )( BlockListBlock );
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
padding-bottom: 12px;
}

.blockContainerDark {
background-color: #1c1c1e;
}

.blockContainerFocused {
background-color: $white;
padding-left: 16px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { __ } from '@wordpress/i18n';
import { withDispatch, withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { createBlock, isUnmodifiedDefaultBlock } from '@wordpress/blocks';
import { KeyboardAwareFlatList, ReadableContentView } from '@wordpress/components';
import { KeyboardAwareFlatList, ReadableContentView, useStyle, withTheme } from '@wordpress/components';

/**
* Internal dependencies
Expand Down Expand Up @@ -103,7 +103,7 @@ export class BlockList extends Component {
innerRef={ this.scrollViewInnerRef }
extraScrollHeight={ innerToolbarHeight + 10 }
keyboardShouldPersistTaps="always"
style={ styles.list }
style={ useStyle( styles.list, styles.listDark, this.context ) }
data={ this.props.blockClientIds }
extraData={ [ this.props.isFullyBordered ] }
keyExtractor={ identity }
Expand Down Expand Up @@ -214,5 +214,6 @@ export default compose( [
replaceBlock,
};
} ),
withTheme,
] )( BlockList );

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
flex: 1;
}

.listDark {
background: #1c1c1e;
}

.switch {
flex-direction: row;
justify-content: flex-start;
Expand Down
20 changes: 18 additions & 2 deletions packages/components/src/button/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
*/
import { StyleSheet, TouchableOpacity, Text, View, Platform } from 'react-native';

/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
import { useStyle, withTheme } from '../mobile/dark-mode';

const isAndroid = Platform.OS === 'android';
const marginBottom = isAndroid ? -0.5 : 0;
const marginLeft = -3;
Expand All @@ -22,6 +30,9 @@ const styles = StyleSheet.create( {
aspectRatio: 1,
backgroundColor: 'white',
},
buttonInactiveDark: {
backgroundColor: 'black',
},
buttonActive: {
flex: 1,
flexDirection: 'row',
Expand Down Expand Up @@ -50,7 +61,7 @@ const styles = StyleSheet.create( {
},
} );

export default function Button( props ) {
export function Button( props ) {
const {
children,
onClick,
Expand All @@ -60,12 +71,15 @@ export default function Button( props ) {
'aria-label': ariaLabel,
'aria-pressed': ariaPressed,
'data-subscript': subscript,
theme,
} = props;

const isDisabled = ariaDisabled || disabled;
const buttonInactiveStyle = useStyle( styles.buttonInactive, styles.buttonInactiveDark, theme );

const buttonViewStyle = {
opacity: isDisabled ? 0.2 : 1,
...( ariaPressed ? styles.buttonActive : styles.buttonInactive ),
...( ariaPressed ? styles.buttonActive : buttonInactiveStyle ),
};

const states = [];
Expand Down Expand Up @@ -98,3 +112,5 @@ export default function Button( props ) {
</TouchableOpacity>
);
}

export default withTheme( Button );
1 change: 1 addition & 0 deletions packages/components/src/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export { default as KeyboardAvoidingView } from './mobile/keyboard-avoiding-view
export { default as KeyboardAwareFlatList } from './mobile/keyboard-aware-flat-list';
export { default as Picker } from './mobile/picker';
export { default as ReadableContentView } from './mobile/readable-content-view';
export * from './mobile/dark-mode';
37 changes: 37 additions & 0 deletions packages/components/src/mobile/dark-mode/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* External dependencies
*/
import { eventEmitter, initialMode } from 'react-native-dark-mode';
import React from 'react';

export function useStyle( light, dark, theme ) {
const finalDark = {
...light,
...dark,
};

return theme === 'dark' ? finalDark : light;
Copy link
Contributor

@mchowning mchowning Aug 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this PR, but another possibly interesting idea would be to somehow dynamically get the dark style when appropriate from the style object. I haven't given this enough thought to say it's a good or even decent idea (especially since your current implementation already seems pretty good), but it's interesting, and I just wanted to throw it out there.

Psuedocode:

style={ useStyle(style, 'containerLayout', theme) }

function useStyle( style, styleProp, theme ) {
  const finalDark = {
     ...style.`${styleProp}Dark`,
     ...style.`${styleProp}`
  }
  ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a very interesting idea. I gave a couple of seconds to similar possibilities, and definitely something to look for on a next iteration!

Thanks for the suggestion! 🙏

}

// This function takes a component...
export function withTheme( WrappedComponent ) {
return class extends React.Component {
constructor( props ) {
super( props );

this.state = {
mode: initialMode,
};
}

componentDidMount() {
eventEmitter.on( 'currentModeChanged', ( newMode ) => {
this.setState( { mode: newMode } );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal preference, but if mode only has two valid states ('light' and 'dark'), it would be easier for me to follow this if the state had something like an isLightTheme boolean instead of a mode string. We could then pass the boolean to the wrapped component, and it would be obvious from the wrapped component that isLightTheme is a boolean variable with two possible states.

} );
}

render() {
return <WrappedComponent theme={ this.state.mode } { ...this.props } />;
Copy link
Contributor

@mchowning mchowning Aug 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your approach looks really good and clean @etoledom . 🎉 I don't see any issues. I had a couple of thoughts as I was looking at it that I'll include here just as food for thought.

Since the theme prop is only used as an argument to the useStyle function, another option would be to just set the appropriate useStyle function as a prop itself. Then the useStyle function "prop" would only need to take the two styles as parameters, it wouldn't need to take the theme as a third parameter because it could access the mode state here directly. The benefit of this would be that it would avoid exposing the "theme" string to all the components that wrap this class. A negative of this would be that the withTheme name fits really well with your current separation of concerns.

One other thing that I was wondering is if long-term the dark/light "theme" is something that we should put in the redux store. I'm honestly not sure, and I think your current approach is better at this time because it is both simpler and easier to change if/when we need to.

Again, these are just a couple of thoughts I had as I was looking it over that I wanted to share.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for sharing your thoughts!

another option would be to just set the appropriate useStyle function as a prop itself.

I like that idea. It's been quite annoying the need to pass the third argument all the time. But there has been a couple of cases where having the current theme has been helpful, cases where the color is given by html class name. But we still can pass both the function and the theme itself I guess :)

I'll do some experiments about this. Thanks again!

}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
Inserter,
BlockToolbar,
} from '@wordpress/block-editor';
import { Toolbar, ToolbarButton } from '@wordpress/components';
import { Toolbar, ToolbarButton, useStyle, withTheme } from '@wordpress/components';

/**
* Internal dependencies
Expand All @@ -30,9 +30,10 @@ function HeaderToolbar( {
showInserter,
showKeyboardHideButton,
clearSelectedBlock,
theme,
} ) {
return (
<View style={ styles.container }>
<View style={ useStyle( styles.container, styles.containerDark, theme ) }>
<ScrollView
horizontal={ true }
showsHorizontalScrollIndicator={ false }
Expand Down Expand Up @@ -91,4 +92,5 @@ export default compose( [
clearSelectedBlock: dispatch( 'core/block-editor' ).clearSelectedBlock,
} ) ),
withViewportMatch( { isLargeViewport: 'medium' } ),
withTheme,
] )( HeaderToolbar );
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
border-top-width: 1px;
}

.containerDark {
background-color: #000;
border-top-color: #3a3a3c;
}

.scrollableContent {
flex-grow: 1; // Fixes RTL issue on Android.
}
Expand Down
5 changes: 3 additions & 2 deletions packages/edit-post/src/components/layout/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { sendNativeEditorDidLayout } from 'react-native-gutenberg-bridge';
import { Component } from '@wordpress/element';
import { withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { HTMLTextInput, KeyboardAvoidingView, ReadableContentView } from '@wordpress/components';
import { HTMLTextInput, KeyboardAvoidingView, ReadableContentView, useStyle, withTheme } from '@wordpress/components';

/**
* Internal dependencies
Expand Down Expand Up @@ -112,7 +112,7 @@ class Layout extends Component {
};

return (
<SafeAreaView style={ styles.container } onLayout={ this.onRootViewLayout }>
<SafeAreaView style={ useStyle( styles.container, styles.containerDark, this.props.theme ) } onLayout={ this.onRootViewLayout }>
<View style={ { flex: 1 } }>
{ mode === 'text' ? this.renderHTML() : this.renderVisual() }
</View>
Expand Down Expand Up @@ -143,4 +143,5 @@ export default compose( [
mode: getEditorMode(),
};
} ),
withTheme,
] )( Layout );
4 changes: 4 additions & 0 deletions packages/edit-post/src/components/layout/style.native.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
background-color: #fff;
}

.containerDark {
background-color: #000;
}

.toolbarKeyboardAvoidingView {
position: absolute;
bottom: 0;
Expand Down
11 changes: 8 additions & 3 deletions packages/rich-text/src/component/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { childrenBlock } from '@wordpress/blocks';
import { decodeEntities } from '@wordpress/html-entities';
import { BACKSPACE } from '@wordpress/keycodes';
import { isURL } from '@wordpress/url';
import { useStyle, withTheme } from '@wordpress/components';

/**
* Internal dependencies
Expand Down Expand Up @@ -772,12 +773,13 @@ export class RichText extends Component {
style,
__unstableIsSelected: isSelected,
children,
theme,
} = this.props;

const record = this.getRecord();
const html = this.getHtmlToRender( record, tagName );

let minHeight = styles[ 'rich-text' ].minHeight;
let minHeight = styles.richText.minHeight;
if ( style && style.minHeight ) {
minHeight = style.minHeight;
}
Expand All @@ -790,7 +792,7 @@ export class RichText extends Component {
color: defaultColor,
textDecorationColor: defaultTextDecorationColor,
fontFamily: defaultFontFamily,
} = styles[ 'rich-text' ];
} = useStyle( styles.richText, styles.richTextDark, theme );

let selection = null;
if ( this.needsSelectionUpdate ) {
Expand Down Expand Up @@ -819,6 +821,8 @@ export class RichText extends Component {
this.firedAfterTextChanged = false;
}

const dynamicStyle = useStyle( style, styles.richTextDark, theme );

return (
<View>
{ children && children( {
Expand All @@ -835,7 +839,7 @@ export class RichText extends Component {
}
} }
style={ {
...style,
...dynamicStyle,
minHeight: Math.max( minHeight, this.state.height ),
} }
text={ { text: html, eventCount: this.lastEventCount, selection } }
Expand Down Expand Up @@ -880,4 +884,5 @@ export default compose( [
withSelect( ( select ) => ( {
formatTypes: select( 'core/rich-text' ).getFormatTypes(),
} ) ),
withTheme,
] )( RichText );
8 changes: 7 additions & 1 deletion packages/rich-text/src/component/style.native.scss
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@

.rich-text {
.richText {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just asking so I know, is camelcase the preferred convention for our .scss files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's a convention already, but I have seen more camel-cases on mobile scss lately. And it's easier to work with on JS files. The snake-cased ones seem to be older ones.

So I took the liberty to modify some that were needed on this PR.

font-family: $default-regular-font;
min-height: $min-height-paragraph;
color: $gray-900;
text-decoration-color: $blue-500;
}

.richTextDark {
color: $white;
text-decoration-color: $blue-500;
background-color: #1c1c1e;
}

.rich-text-placeholder {
color: $gray;
}