Hyperlinks to legalese such as Privacy Policy and Terms of Service

This commit is contained in:
Lyubomir Marinov 2016-11-29 14:04:56 -06:00
parent 841050953f
commit 1f457dfca5
11 changed files with 261 additions and 88 deletions

View File

@ -0,0 +1,87 @@
import React, { Component } from 'react';
import { Linking, Text } from 'react-native';
/**
* Implements a (hyper)link to a URL in the fashion of the HTML anchor element
* and its href attribute.
*/
export class Link extends Component {
/**
* Initializes a new Link instance.
*
* @param {Object} props - Component properties.
*/
constructor(props) {
super(props);
// Bind event handlers so they are only bound once for every instance.
this._onPress = this._onPress.bind(this);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
return (
<Text
onPress = { this._onPress }
style = { this.props.style }>
{
this.props.children
}
</Text>
);
}
/**
* Notifies this instance that Linking failed to open the associated URL.
*
* @param {any} reason - The rejection reason.
* @private
* @returns {void}
*/
_onLinkingOpenURLRejected(reason) {
const onRejected = this.props.onLinkingOpenURLRejected;
onRejected && onRejected(reason);
}
/**
* Handles press on this Link. Opens the URL associated with this Link.
*
* @private
* @returns {void}
*/
_onPress() {
Linking.openURL(this.props.url)
.catch(reason => this._onLinkingOpenURLRejected(reason));
}
}
/**
* Link component's property types.
*/
Link.propTypes = {
/**
* The children to be displayed within this Link.
*/
children: React.PropTypes.node,
/**
* Notifies that this Link failed to open the URL associated with it.
*/
onLinkingOpenURLRejected: React.PropTypes.function,
/**
* The CSS style to be applied to this Link for the purposes of display.
*/
style: React.PropTypes.object,
/**
* The URL to be opened when this Link is clicked/pressed.
*/
url: React.PropTypes.string
};

View File

@ -1 +1,2 @@
export * from './Container'; export * from './Container';
export * from './Link';

View File

@ -0,0 +1,15 @@
/**
* The application's default properties related to the CSS box model such as
* margins, borders, padding.
*/
export const BoxModel = {
/**
* The application's default margin when non-zero margin is necessary.
*/
margin: 10,
/**
* The application's default padding when non-zero padding is necessary.
*/
padding: 10
};

View File

@ -1,11 +1,26 @@
/** /**
* The application color palette. * The application's definition of the default color black.
*/
const BLACK = '#111111';
/**
* The application's color palette.
*/ */
export const ColorPalette = { export const ColorPalette = {
appBackground: '#111111', /**
* The application's background color.
*/
appBackground: BLACK,
/**
* The application's definition of the default color black. Generally,
* expected to be kept in sync with the application's background color for
* the sake of consistency.
*/
black: BLACK,
blue: '#17A0DB',
buttonUnderlay: '#495258', buttonUnderlay: '#495258',
jitsiBlue: '#17A0DB', darkGrey: '#555555',
jitsiDarkGrey: '#555555', red: '#D00000',
jitsiRed: '#D00000', white: 'white'
jitsiToggled: '#495258'
}; };

View File

@ -1 +1,2 @@
export * from './BoxModel';
export * from './ColorPalette'; export * from './ColorPalette';

View File

@ -1,7 +1,19 @@
import { createStyleSheet } from '../../../base/styles'; import { ColorPalette, createStyleSheet } from '../../../base/styles';
import { styles as platformIndependentStyles } from '../styles'; import { styles as platformIndependentStyles } from '../styles';
/**
* The base/default style of indicators such as audioMutedIndicator,
* moderatorIndicator, and videoMutedIndicator.
*/
const indicator = {
textShadowColor: ColorPalette.black,
textShadowOffset: {
height: -1,
width: 0
}
};
/** /**
* Native-specific styles for the film strip. * Native-specific styles for the film strip.
*/ */
@ -10,13 +22,7 @@ export const styles = createStyleSheet(platformIndependentStyles, {
/** /**
* Audio muted indicator style. * Audio muted indicator style.
*/ */
audioMutedIndicator: { audioMutedIndicator: indicator,
textShadowColor: 'black',
textShadowOffset: {
height: -1,
width: 0
}
},
/** /**
* Dominant speaker indicator background style. * Dominant speaker indicator background style.
@ -29,13 +35,7 @@ export const styles = createStyleSheet(platformIndependentStyles, {
/** /**
* Moderator indicator style. * Moderator indicator style.
*/ */
moderatorIndicator: { moderatorIndicator: indicator,
textShadowColor: 'black',
textShadowOffset: {
height: -1,
width: 0
}
},
/** /**
* Video thumbnail style. * Video thumbnail style.
@ -48,11 +48,5 @@ export const styles = createStyleSheet(platformIndependentStyles, {
/** /**
* Video muted indicator style. * Video muted indicator style.
*/ */
videoMutedIndicator: { videoMutedIndicator: indicator
textShadowColor: 'black',
textShadowOffset: {
height: -1,
width: 0
}
}
}); });

View File

@ -1,4 +1,4 @@
import { ColorPalette } from '../../base/styles'; import { BoxModel, ColorPalette } from '../../base/styles';
/** /**
* Film strip related styles common to both Web and native. * Film strip related styles common to both Web and native.
@ -9,7 +9,7 @@ export const styles = {
*/ */
audioMutedIndicator: { audioMutedIndicator: {
backgroundColor: 'transparent', backgroundColor: 'transparent',
color: 'white', color: ColorPalette.white,
left: 20, left: 20,
position: 'absolute', position: 'absolute',
top: 1 top: 1
@ -19,7 +19,7 @@ export const styles = {
* Dominant speaker indicator style. * Dominant speaker indicator style.
*/ */
dominantSpeakerIndicator: { dominantSpeakerIndicator: {
color: 'white', color: ColorPalette.white,
fontSize: 15 fontSize: 15
}, },
@ -27,7 +27,7 @@ export const styles = {
* Dominant speaker indicator background style. * Dominant speaker indicator background style.
*/ */
dominantSpeakerIndicatorBackground: { dominantSpeakerIndicatorBackground: {
backgroundColor: ColorPalette.jitsiBlue, backgroundColor: ColorPalette.blue,
borderRadius: 15, borderRadius: 15,
bottom: 2, bottom: 2,
left: 1, left: 1,
@ -41,7 +41,7 @@ export const styles = {
filmStrip: { filmStrip: {
alignItems: 'flex-end', alignItems: 'flex-end',
alignSelf: 'stretch', alignSelf: 'stretch',
bottom: 10, bottom: BoxModel.margin,
flex: 1, flex: 1,
flexDirection: 'column', flexDirection: 'column',
left: 0, left: 0,
@ -55,7 +55,7 @@ export const styles = {
* to allow scrolling through them if they do not fit within the display. * to allow scrolling through them if they do not fit within the display.
*/ */
filmStripScrollViewContentContainer: { filmStripScrollViewContentContainer: {
paddingHorizontal: 10 paddingHorizontal: BoxModel.padding
}, },
/** /**
@ -63,7 +63,7 @@ export const styles = {
*/ */
moderatorIndicator: { moderatorIndicator: {
backgroundColor: 'transparent', backgroundColor: 'transparent',
color: 'white', color: ColorPalette.white,
left: 1, left: 1,
position: 'absolute', position: 'absolute',
top: 1 top: 1
@ -74,7 +74,7 @@ export const styles = {
*/ */
thumbnail: { thumbnail: {
alignItems: 'stretch', alignItems: 'stretch',
backgroundColor: 'black', backgroundColor: ColorPalette.appBackground,
borderColor: '#424242', borderColor: '#424242',
borderStyle: 'solid', borderStyle: 'solid',
borderWidth: 1, borderWidth: 1,
@ -88,8 +88,8 @@ export const styles = {
* Pinned video thumbnail style. * Pinned video thumbnail style.
*/ */
thumbnailPinned: { thumbnailPinned: {
borderColor: ColorPalette.jitsiBlue, borderColor: ColorPalette.blue,
shadowColor: 'black', shadowColor: ColorPalette.black,
shadowOffset: { shadowOffset: {
height: 5, height: 5,
width: 5 width: 5
@ -102,7 +102,7 @@ export const styles = {
*/ */
videoMutedIndicator: { videoMutedIndicator: {
backgroundColor: 'transparent', backgroundColor: 'transparent',
color: 'white', color: ColorPalette.white,
left: 35, left: 35,
position: 'absolute', position: 'absolute',
top: 1 top: 1

View File

@ -76,7 +76,7 @@ class Toolbar extends AbstractToolbar {
onClick = { this._onHangup } onClick = { this._onHangup }
style = {{ style = {{
...styles.toolbarButton, ...styles.toolbarButton,
backgroundColor: ColorPalette.jitsiRed backgroundColor: ColorPalette.red
}} }}
underlayColor = { underlayColor } /> underlayColor = { underlayColor } />
<ToolbarButton <ToolbarButton

View File

@ -35,7 +35,7 @@ const container = {
*/ */
const icon = { const icon = {
alignSelf: 'center', alignSelf: 'center',
color: ColorPalette.jitsiDarkGrey, color: ColorPalette.darkGrey,
fontSize: 24 fontSize: 24
}; };
@ -49,7 +49,7 @@ export const styles = createStyleSheet({
*/ */
icon: { icon: {
...icon, ...icon,
color: ColorPalette.jitsiDarkGrey color: ColorPalette.darkGrey
}, },
/** /**
@ -74,7 +74,7 @@ export const styles = createStyleSheet({
*/ */
toolbarButton: { toolbarButton: {
...button, ...button,
backgroundColor: 'white', backgroundColor: ColorPalette.white,
marginLeft: 20, marginLeft: 20,
marginRight: 20, marginRight: 20,
opacity: 0.8 opacity: 0.8
@ -104,6 +104,6 @@ export const styles = createStyleSheet({
*/ */
whiteIcon: { whiteIcon: {
...icon, ...icon,
color: 'white' color: ColorPalette.white
} }
}); });

View File

@ -2,12 +2,23 @@ import React from 'react';
import { Text, TextInput, TouchableHighlight, View } from 'react-native'; import { Text, TextInput, TouchableHighlight, View } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { Link } from '../../base/react';
AbstractWelcomePage, import { ColorPalette } from '../../base/styles';
mapStateToProps
} from './AbstractWelcomePage'; import { AbstractWelcomePage, mapStateToProps } from './AbstractWelcomePage';
import { styles } from './styles'; import { styles } from './styles';
/**
* The URL at which the privacy policy is available to the user.
*/
const PRIVACY_POLICY_URL = 'https://www.atlassian.com/legal/privacy-policy';
/**
* The URL at which the terms of service are available to the user.
*/
const TERMS_OF_SERVICE_URL
= 'https://www.atlassian.com/legal/customer-agreement';
/** /**
* The native container rendering the welcome page. * The native container rendering the welcome page.
* *
@ -25,6 +36,25 @@ class WelcomePage extends AbstractWelcomePage {
{ {
this._renderLocalVideo() this._renderLocalVideo()
} }
{
this._renderLocalVideoOverlay()
}
</View>
);
}
/**
* Renders a View over the local video. The latter is thought of as the
* background (content) of this WelcomePage. The former is thought of as the
* foreground (content) of this WelcomePage such as the room name input, the
* button to initiate joining the specified room, etc.
*
* @private
* @returns {ReactElement}
*/
_renderLocalVideoOverlay() {
return (
<View style = { styles.localVideoOverlay }>
<View style = { styles.roomContainer }> <View style = { styles.roomContainer }>
<Text style = { styles.title }>Enter room name</Text> <Text style = { styles.title }>Enter room name</Text>
<TextInput <TextInput
@ -39,10 +69,22 @@ class WelcomePage extends AbstractWelcomePage {
disabled = { this._isJoinDisabled() } disabled = { this._isJoinDisabled() }
onPress = { this._onJoinClick } onPress = { this._onJoinClick }
style = { styles.button } style = { styles.button }
underlayColor = 'white'> underlayColor = { ColorPalette.white }>
<Text style = { styles.buttonText }>JOIN</Text> <Text style = { styles.buttonText }>JOIN</Text>
</TouchableHighlight> </TouchableHighlight>
</View> </View>
<View style = { styles.legaleseContainer }>
<Link
style = { styles.legaleseItem }
url = { PRIVACY_POLICY_URL }>
Privacy Policy
</Link>
<Link
style = { styles.legaleseItem }
url = { TERMS_OF_SERVICE_URL }>
Terms of Service
</Link>
</View>
</View> </View>
); );
} }

View File

@ -1,39 +1,26 @@
import { ColorPalette, createStyleSheet } from '../../base/styles'; import { BoxModel, ColorPalette, createStyleSheet } from '../../base/styles';
/** /**
* Welcome page container style. * The default color of text on the WelcomePage.
*/ */
const container = { const TEXT_COLOR = ColorPalette.white;
alignSelf: 'stretch',
backgroundColor: ColorPalette.jitsiBlue,
bottom: 0,
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
left: 0,
position: 'absolute',
right: 0,
top: 0
};
/** /**
* The welcome page style. * The styles of WelcomePage.
* TODO: Make styles more generic and reusable. Use color palette for all
* colors.
*/ */
export const styles = createStyleSheet({ export const styles = createStyleSheet({
/** /**
* Join button text style. * Join button style.
*/ */
button: { button: {
backgroundColor: 'white', backgroundColor: ColorPalette.white,
borderColor: 'white', borderColor: ColorPalette.white,
borderRadius: 8, borderRadius: 8,
borderWidth: 1, borderWidth: 1,
height: 45, height: 45,
justifyContent: 'center', justifyContent: 'center',
marginBottom: 10, marginBottom: BoxModel.margin,
marginTop: 10 marginTop: BoxModel.margin
}, },
/** /**
@ -46,25 +33,56 @@ export const styles = createStyleSheet({
}, },
/** /**
* Welcome page container style. * The style of the top-level container of WelcomePage.
*/ */
container, container: {
alignSelf: 'stretch',
backgroundColor: ColorPalette.blue,
flex: 1
},
/**
* The style of the legal-related content such as (hyper)links to Privacy
* Policy and Terms of Service displayed on the WelcomePage.
*/
legaleseContainer: {
flex: 0,
flexDirection: 'row',
justifyContent: 'center'
},
/**
* The style of a piece of legal-related content such as a (hyper)link to
* Privacy Policy or Terms of Service displayed on the WelcomePage.
*/
legaleseItem: {
color: TEXT_COLOR,
margin: BoxModel.margin
},
/**
* The style of the View displayed over the local video. The latter is
* thought of as the background (content) of WelcomePage. The former is
* thought of as the foreground (content) of WelcomePage.
*/
localVideoOverlay: {
bottom: 0,
flex: 1,
flexDirection: 'column',
left: 0,
position: 'absolute',
right: 0,
top: 0
},
/** /**
* Container for room name input box and 'join' button. * Container for room name input box and 'join' button.
*/ */
roomContainer: { roomContainer: {
...container, flex: 1,
backgroundColor: 'transparent', flexDirection: 'column',
padding: 30 justifyContent: 'center',
}, margin: 3 * BoxModel.margin
/**
* Navigator container style.
*/
navContainer: {
backgroundColor: ColorPalette.appBackground,
flex: 1
}, },
/** /**
@ -72,11 +90,11 @@ export const styles = createStyleSheet({
*/ */
textInput: { textInput: {
backgroundColor: 'transparent', backgroundColor: 'transparent',
borderColor: 'white', borderColor: ColorPalette.white,
borderRadius: 8, borderRadius: 8,
borderStyle: 'solid', borderStyle: 'solid',
borderWidth: 1, borderWidth: 1,
color: 'white', color: TEXT_COLOR,
fontSize: 23, fontSize: 23,
height: 50, height: 50,
padding: 4, padding: 4,
@ -87,9 +105,9 @@ export const styles = createStyleSheet({
* Application title style. * Application title style.
*/ */
title: { title: {
color: '#fff', color: TEXT_COLOR,
fontSize: 25, fontSize: 25,
marginBottom: 20, marginBottom: 2 * BoxModel.margin,
textAlign: 'center' textAlign: 'center'
} }
}); });