Skip to content

Commit

Permalink
add spinner for AVView, TextView, and mobile ImageView (#13281)
Browse files Browse the repository at this point in the history
* add spinner for AVView, TextView, and mobile ImageView

also fix some BarePreview styleing issues

* oops

* review feedback from chrisnojima

* use underStatusBar as suggested by chrisnojima
  • Loading branch information
songgao committed Aug 15, 2018
1 parent 22ddf02 commit 604cfa0
Show file tree
Hide file tree
Showing 17 changed files with 251 additions and 129 deletions.
5 changes: 5 additions & 0 deletions shared/common-adapters/web-view.desktop.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ class WebView extends React.PureComponent<WebViewProps> {
ref.insertCSS(css)
ref.executeJavaScript(javaScript)
})
const {onLoadingStateChange} = this.props
if (onLoadingStateChange) {
ref.addEventListener('did-start-loading', () => onLoadingStateChange(true))
ref.addEventListener('did-stop-loading', () => onLoadingStateChange(false))
}
}
render() {
return <webview ref={this._setWebviewRef} style={this.props.style} src={this.props.url} />
Expand Down
1 change: 1 addition & 0 deletions shared/common-adapters/web-view.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type WebViewProps = {
url: string,
injections?: WebViewInjections,
style?: Object,
onLoadingStateChange?: (isLoading: boolean)=>void,
}

declare export default React.ComponentType<WebViewProps>
38 changes: 24 additions & 14 deletions shared/common-adapters/web-view.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,27 @@ const combineJavaScriptAndCSS = (injections?: WebViewInjections) =>
`

export default (isIOS
? (props: WebViewProps) => (
<WKWebView
source={{uri: props.url}}
injectedJavaScript={memoize(combineJavaScriptAndCSS)(props.injections)}
style={props.style}
/>
)
: (props: WebViewProps) => (
<WebView
source={{uri: props.url}}
injectedJavaScript={memoize(combineJavaScriptAndCSS)(props.injections)}
style={props.style}
/>
))
? (props: WebViewProps) => {
const {onLoadingStateChange} = props
return (
<WKWebView
source={{uri: props.url}}
injectedJavaScript={memoize(combineJavaScriptAndCSS)(props.injections)}
style={props.style}
onLoadStart={onLoadingStateChange && (() => onLoadingStateChange(true))}
onLoadEnd={onLoadingStateChange && (() => onLoadingStateChange(false))}
/>
)
}
: (props: WebViewProps) => {
const {onLoadingStateChange} = props
return (
<WebView
source={{uri: props.url}}
injectedJavaScript={memoize(combineJavaScriptAndCSS)(props.injections)}
style={props.style}
onLoadStart={onLoadingStateChange && (() => onLoadingStateChange(true))}
onLoadEnd={onLoadingStateChange && (() => onLoadingStateChange(false))}
/>
)
})
7 changes: 5 additions & 2 deletions shared/fs/common/path-item-action-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type OwnProps = {
path: Types.Path,
actionIconClassName?: string,
actionIconFontSize?: number,
actionIconWhite?: boolean,
}

const mapStateToProps = (state: TypedState) => ({
Expand Down Expand Up @@ -151,10 +152,11 @@ const getRootMenuActionsByPathLevel = (pathLevel: number, stateProps, dispatchPr
}
}

const mergeProps = (stateProps, dispatchProps, {path, actionIconClassName, actionIconFontSize}) => {
const pathElements = Types.getPathElements(path)
const mergeProps = (stateProps, dispatchProps, ownProps) => {
const {_pathItems, _username} = stateProps
const {loadFolderList, loadMimeType} = dispatchProps
const {path, actionIconClassName, actionIconFontSize, actionIconWhite} = ownProps
const pathElements = Types.getPathElements(path)
const pathItem = _pathItems.get(path, Constants.unknownPathItem)
const type = pathElements.length <= 3 ? 'folder' : pathItem.type
const {childrenFolders, childrenFiles} =
Expand Down Expand Up @@ -197,6 +199,7 @@ const mergeProps = (stateProps, dispatchProps, {path, actionIconClassName, actio
loadFolderList,
actionIconClassName,
actionIconFontSize,
actionIconWhite,
// menu actions
showInFileUI,
ignoreFolder,
Expand Down
3 changes: 2 additions & 1 deletion shared/fs/common/path-item-action.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type Props = {
itemStyles: Types.ItemStyles,
actionIconClassName?: string,
actionIconFontSize?: number,
actionIconWhite?: boolean,
path: Types.Path,
pathElements: Array<string>,
// Menu items
Expand Down Expand Up @@ -193,7 +194,7 @@ const PathItemAction = (props: Props & OverlayParentProps) => {
<ClickableBox onClick={props.toggleShowingMenu} ref={props.setAttachmentRef}>
<Icon
type="iconfont-ellipsis"
color={Styles.globalColors.black_40}
color={props.actionIconWhite ? Styles.globalColors.white : Styles.globalColors.black_40}
style={iconCastPlatformStyles(styles.actionIcon)}
fontSize={props.actionIconFontSize}
className={props.actionIconClassName}
Expand Down
7 changes: 6 additions & 1 deletion shared/fs/filepreview/av-view.desktop.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import {Box, WebView, type WebViewInjections} from '../../common-adapters'

const AVView = (props: AVViewProps) => (
<Box style={stylesContainer}>
<WebView style={stylesWebview} url="about:blank" injections={injections(props.url)} />
<WebView
style={stylesWebview}
url="about:blank"
injections={injections(props.url)}
onLoadingStateChange={props.onLoadingStateChange}
/>
</Box>
)

Expand Down
1 change: 1 addition & 0 deletions shared/fs/filepreview/av-view.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as React from 'react'

export type AVViewProps = {
url: string,
onLoadingStateChange?: (isLoading:boolean)=>void,
}

declare export default React.ComponentType<AVViewProps>
4 changes: 3 additions & 1 deletion shared/fs/filepreview/av-view.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {globalColors} from '../../styles'
import {WebView} from '../../common-adapters'
import {type AVViewProps} from './av-view'

const AVView = ({url, onInvalidToken}: AVViewProps) => <WebView styles={stylesAVView} url={url} />
const AVView = ({url, onInvalidToken, onLoadingStateChange}: AVViewProps) => (
<WebView styles={stylesAVView} url={url} onLoadingStateChange={onLoadingStateChange} />
)

const stylesAVView = {
backgroundColor: globalColors.blue5,
Expand Down
131 changes: 75 additions & 56 deletions shared/fs/filepreview/bare-preview.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import * as I from 'immutable'
import * as React from 'react'
import * as Types from '../../constants/types/fs'
import * as Constants from '../../constants/fs'
import {globalStyles, globalColors, globalMargins, platformStyles} from '../../styles'
import {Box, ClickableBox, Text} from '../../common-adapters'
import * as Styles from '../../styles'
import {Box, ClickableBox, Text, ProgressIndicator} from '../../common-adapters'
import {navigateUp} from '../../actions/route-tree'
import {connect, type Dispatch, type TypedState} from '../../util/container'
import {type BarePreviewProps} from './bare-preview'
Expand Down Expand Up @@ -36,65 +36,84 @@ type ConnectedBarePreviewProps = {
onBack: () => void,
}

const BarePreview = (props: ConnectedBarePreviewProps) => (
<Box style={stylesContainer}>
<Box style={stylesHeader}>
<ClickableBox onClick={props.onBack} style={stylesCloseBox}>
<Text type="Body" style={stylesText}>
Close
</Text>
</ClickableBox>
</Box>
<Box style={stylesContentContainer}>
<View path={props.path} routePath={props.routePath} />
</Box>
<Box style={stylesFooter}>
<PathItemAction path={props.path} actionIconStyle={stylesPathItemActionIcon} />
</Box>
</Box>
)
type State = {
loading: boolean,
}

class BarePreview extends React.PureComponent<ConnectedBarePreviewProps, State> {
state = {
loading: false,
}
_onLoadingStateChange = (loading: boolean) => this.setState({loading})

const stylesPathItemActionIcon = {
color: globalColors.white,
render() {
return (
<Box style={styles.container}>
<Box style={styles.header}>
<ClickableBox onClick={this.props.onBack} style={styles.closeBox}>
<Text type="Body" style={styles.text}>
Close
</Text>
</ClickableBox>
</Box>
<Box style={styles.contentContainer}>
<View
path={this.props.path}
routePath={this.props.routePath}
onLoadingStateChange={this._onLoadingStateChange}
/>
</Box>
<Box style={styles.footer}>
<PathItemAction path={this.props.path} actionIconWhite={true} />
</Box>
{this.state.loading && <ProgressIndicator style={styles.loading} white={true} />}
</Box>
)
}
}

const stylesContainer = platformStyles({
common: {
...globalStyles.flexBoxColumn,
...globalStyles.flexGrow,
backgroundColor: globalColors.black,
const styles = Styles.styleSheetCreate({
container: Styles.platformStyles({
common: {
...Styles.globalStyles.flexBoxColumn,
...Styles.globalStyles.flexGrow,
backgroundColor: Styles.globalColors.black,
},
}),
text: {
color: Styles.globalColors.white,
lineHeight: 48,
},
closeBox: {
paddingLeft: Styles.globalMargins.tiny,
height: 48,
width: 64,
},
isIOS: {
marginTop: -20, // top status bar
header: {
...Styles.globalStyles.flexBoxRow,
alignItems: 'center',
paddingLeft: Styles.globalMargins.tiny,
},
contentContainer: {
...Styles.globalStyles.flexGrow,
},
footer: {
...Styles.globalStyles.flexBoxRow,
alignItems: 'center',
paddingLeft: Styles.globalMargins.tiny,
height: 48,
},
loading: Styles.platformStyles({
common: {
height: 32,
width: 32,
},
isMobile: {
position: 'absolute',
top: 48,
left: Styles.globalMargins.small,
},
}),
})

const stylesText = {
color: globalColors.white,
lineHeight: 48,
}

const stylesCloseBox = {
paddingLeft: globalMargins.tiny,
height: 48,
width: 64,
}

const stylesHeader = {
...globalStyles.flexBoxRow,
alignItems: 'center',
paddingLeft: globalMargins.tiny,
}

const stylesContentContainer = {
...globalStyles.flexGrow,
}

const stylesFooter = {
...globalStyles.flexBoxRow,
alignItems: 'center',
height: 32,
paddingLeft: globalMargins.tiny,
}

export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(BarePreview)
1 change: 1 addition & 0 deletions shared/fs/filepreview/image-view.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as React from 'react'

export type ImageViewProps = {
url: string,
onLoadingStateChange?: (isLoading: boolean)=>void,
}

declare export default React.ComponentType<any>
47 changes: 34 additions & 13 deletions shared/fs/filepreview/image-view.native.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
// @flow
import * as React from 'react'
import * as Styles from '../../styles'
import {NativeImage, NativeDimensions, ZoomableBox} from '../../common-adapters/mobile.native'
import {type ImageViewProps} from './image-view'

const {width: screenWidth, height: screenHeight} = NativeDimensions.get('window')

class ImageView extends React.Component<any, {...ImageViewProps, width: number, height: number, loaded: boolean}> {
class ImageView extends React.Component<
ImageViewProps,
{...ImageViewProps, width: number, height: number, loaded: boolean}
> {
state = {height: 0, width: 0, loaded: false}
_mounted: boolean = false

Expand All @@ -24,30 +28,47 @@ class ImageView extends React.Component<any, {...ImageViewProps, width: number,
_setLoaded = () => this.setState({loaded: true})

render() {
const {onLoadingStateChange} = this.props
return (
<ZoomableBox
contentContainerStyle={{flex: 1, position: 'relative'}}
contentContainerStyle={styles.zoomableBoxContainer}
maxZoom={10}
style={{position: 'relative', overflow: 'hidden', width: '100%', height: '100%'}}
style={styles.zoomableBox}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
>
<NativeImage
source={{uri: this.props.url}}
style={{
...stylesImage,
height: Math.min(this.state.height, screenHeight),
width: Math.min(this.state.width, screenWidth),
}}
resizeMode="contain" />
style={Styles.collapseStyles([
styles.image,
{
height: Math.min(this.state.height, screenHeight),
width: Math.min(this.state.width, screenWidth),
},
])}
onLoadStart={onLoadingStateChange && (() => onLoadingStateChange(true))}
onLoadEnd={onLoadingStateChange && (() => onLoadingStateChange(false))}
resizeMode="contain"
/>
</ZoomableBox>
)
}
}

const stylesImage = {
flex: 1,
alignSelf: 'center',
}
const styles = Styles.styleSheetCreate({
image: {
flex: 1,
alignSelf: 'center',
},
zoomableBox: {
flex: 1,
position: 'relative',
},
zoomableBoxContainer: {
flex: 1,
position: 'relative',
overflow: 'hidden',
},
})

export default ImageView
Loading

0 comments on commit 604cfa0

Please sign in to comment.