Skip to content

Commit

Permalink
Merge branch 'release/0.13.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Željko Rumenjak committed Apr 10, 2017
2 parents 38c7982 + 113bb32 commit a9484d8
Show file tree
Hide file tree
Showing 27 changed files with 6,718 additions and 1,539 deletions.
10 changes: 7 additions & 3 deletions components/ListView.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,22 @@ class ListView extends React.Component {
}

createRenderHeader(renderHeader, autoHideHeader) {
const headerProps = {};
if (!renderHeader) {
return;
}

const { style } = this.props;
const headerContainerProps = {
style: style.headerContainer,
};

if (autoHideHeader) {
headerProps.onLayout = this.autoHideHeader;
headerContainerProps.onLayout = this.autoHideHeader;
}

// eslint-disable-next-line consistent-return
return () => (
<View {...headerProps}>{renderHeader()}</View>
<View {...headerContainerProps}>{renderHeader()}</View>
);
}

Expand Down
67 changes: 67 additions & 0 deletions components/Touchable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { PropTypes } from 'react';
import { Platform } from 'react-native';

import { connectStyle } from '@shoutem/theme';

import {
TouchableOpacity,
TouchableNativeFeedback,
View,
} from '../index';

/**
* A universal touchable component with a
* platform specific feedback. This
* component displays a TouchableOpacity on
* iOS, and a TouchableNativeFeedback on
* Android.
*/
function Touchable(props) {
const style = { ...props.style };
delete style.touchableOpacity;
delete style.touchableNativeFeedback;

if (Platform.OS === 'android') {
return (
<TouchableNativeFeedback
{...props}
style={props.style.touchableNativeFeedback}
>
<View
virtual
style={style}
styleName={props.styleName}
>
{props.children}
</View>
</TouchableNativeFeedback>
);
}

return (
<TouchableOpacity
{...props}
style={{
...style,
...props.style.touchableOpacity,
}}
>
{props.children}
</TouchableOpacity>
);
}

Touchable.propTypes = {
...TouchableOpacity.propTypes,
...TouchableNativeFeedback.propTypes,
style: PropTypes.object,
};

const StyledTouchable = connectStyle('shoutem.ui.Touchable', {
touchableNativeFeedback: {},
touchableOpacity: {},
})(Touchable);

export {
StyledTouchable as Touchable,
};
40 changes: 40 additions & 0 deletions components/TouchableNativeFeedback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { PropTypes } from 'react';
import { TouchableNativeFeedback as RNTouchableNativeFeedback } from 'react-native';

import { connectStyle } from '@shoutem/theme';

function TouchableNativeFeedback(props) {
// Remove the props that are not valid
// style keys.
const style = {
...props.style,
};
delete style.background;
delete style.useForeground;

return (
<RNTouchableNativeFeedback
{...props}
style={style}
background={props.style.background}
useForeground={props.style.useForeground}
>
{props.children}
</RNTouchableNativeFeedback>
);
}

TouchableNativeFeedback.propTypes = {
...RNTouchableNativeFeedback.propTypes,
style: PropTypes.shape({
background: PropTypes.object,
useForeground: PropTypes.bool,
}),
};

const StyledTouchableNativeFeedback =
connectStyle('shoutem.ui.TouchableNativeFeedback')(TouchableNativeFeedback);

export {
StyledTouchableNativeFeedback as TouchableNativeFeedback,
};
36 changes: 20 additions & 16 deletions components/TouchableOpacity.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,27 @@ import { TouchableOpacity as RNTouchableOpacity } from 'react-native';

import { connectStyle } from '@shoutem/theme';

function TouchableOpacity(props) {
// The activeOpacity is not a valid RN style
// property, so we have to unset it here.
const style = {
...props.style,
};
delete style.activeOpacity;
class TouchableOpacity extends React.Component {
render() {
const props = this.props;

return (
<RNTouchableOpacity
{...props}
style={style}
activeOpacity={props.style.activeOpacity}
>
{props.children}
</RNTouchableOpacity>
);
// The activeOpacity is not a valid RN style
// property, so we have to unset it here.
const style = {
...props.style,
};
delete style.activeOpacity;

return (
<RNTouchableOpacity
{...props}
style={style}
activeOpacity={props.style.activeOpacity}
>
{props.children}
</RNTouchableOpacity>
);
}
}

TouchableOpacity.propTypes = {
Expand Down
16 changes: 13 additions & 3 deletions components/Video/Video.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,22 @@ import VideoSourceReader from './VideoSourceReader';
const propTypes = {
width: PropTypes.number,
height: PropTypes.number,
// `playerParams` currently only works for Youtube
playerParams: PropTypes.object,
source: PropTypes.shape({
uri: PropTypes.string,
}),
style: PropTypes.object,
};

function createSourceObject(source) {
const sourceReader = new VideoSourceReader(source.uri);
const defaultProps = {
playerParams: {
showinfo: 0,
},
};

function createSourceObject(source, playerParams) {
const sourceReader = new VideoSourceReader(source.uri, playerParams);
const url = sourceReader.getUrl();

if (sourceReader.isEmbeddableVideo()) {
Expand Down Expand Up @@ -55,19 +63,21 @@ function Video({
height,
source,
style,
playerParams,
}) {
return (
<View style={style.container}>
<WebView
style={{ width, height }}
source={createSourceObject(source)}
source={createSourceObject(source, playerParams)}
scrollEnabled={false}
/>
</View>
);
}

Video.propTypes = propTypes;
Video.defaultProps = defaultProps;

const AnimatedVideo = connectAnimation(Video);
const StyledVideo = connectStyle('shoutem.ui.Video', {})(AnimatedVideo);
Expand Down
13 changes: 9 additions & 4 deletions components/Video/VideoSourceReader.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { stringify } from 'qs';

function getYouTubeVideoId(url) {
const regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\??v?=?))([^#&\?]*).*/;
const match = url.match(regExp);
Expand All @@ -22,8 +24,9 @@ function getVimeoVideoId(url) {
return false;
}

function getYouTubeEmbedUrl(id) {
return `https://www.youtube.com/embed/${id}`;
function getYouTubeEmbedUrl(id, playerParams) {
const serializedParams = stringify(playerParams);
return `https://www.youtube.com/embed/${id}?${serializedParams}`;
}

function getVimeoEmbedUrl(id) {
Expand All @@ -34,9 +37,11 @@ function getVimeoEmbedUrl(id) {
* Reads the video source and provides the video
* url in embedded form if necessary
*/

export default class VideoSourceReader {
constructor(source) {
constructor(source, playerParams) {
this.source = source;
this.playerParams = playerParams;
this.isYouTube = !!getYouTubeVideoId(source);
this.isVimeo = !!getVimeoVideoId(source);
}
Expand All @@ -47,7 +52,7 @@ export default class VideoSourceReader {

getUrl() {
if (this.isYouTube) {
return getYouTubeEmbedUrl(getYouTubeVideoId(this.source));
return getYouTubeEmbedUrl(getYouTubeVideoId(this.source), this.playerParams);
} else if (this.isVimeo) {
return getVimeoEmbedUrl(getVimeoVideoId(this.source));
}
Expand Down
2 changes: 1 addition & 1 deletion examples/RestaurantsApp/app/RestaurantDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default class RestaurantDetails extends Component {
<Screen styleName="paper full-screen">
<NavigationBar
title={restaurant.name}
styleName="clear"
styleName="clear hide-title"
animationName="solidify"
/>

Expand Down
46 changes: 23 additions & 23 deletions examples/RestaurantsApp/assets/data/restaurants.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,42 @@
"name": "Gaspar Brasserie",
"address": "185 Sutter St, San Francisco, CA 94109",
"description": "Gaspar is a delightful French restaurant in San Francisco’s Financial District that is inspired by the romantic, bustling Paris of old.\n\nLocated near famed Union Square, our richly-designed interiors make you feel as if you are truly in Paris and provide the perfect setting for enjoying our exquisite classic and modern French fare such as Duck Leg Confit and always popular Steak Frites.\n\nGaspar is a delightful French restaurant in San Francisco’s Financial District that is inspired by the romantic, bustling Paris of old. Located near famed Union Square, our richly-designed interiors make you feel as if you are truly in Paris and provide the perfect setting for enjoying our exquisite classic and modern French fare such as Duck Leg Confit and always popular Steak Frites.",
"url": "gasparbrasserie.com",
"image": { "url": "https://shoutem.github.io/restaurants/restaurant-1.jpg" },
"url": "https://gasparbrasserie.com",
"image": { "url": "https://shoutem.github.io/static/getting-started/restaurant-1.jpg" },
"mail": "info@gasparbrasserie.com"
}, {
"name": "Chalk Point Kitchen",
"address": "527 Broome St, New York, NY 10013",
"description": "Situated in the heart of SoHo, at 527 Broome Street (between Thompson and Sullivan) Chalk Point Kitchen is a 60 seat “market to table” owned by Lower East Side restaurateur, Matt Levine and his indieFORK team.",
"url": "",
"image": { "url": "https://shoutem.github.io/restaurants/restaurant-2.jpg" },
"mail": ""
"url": "https://www.chalkpointkitchen.com/",
"image": { "url": "https://shoutem.github.io/static/getting-started/restaurant-2.jpg" },
"mail": "FeedMe@ChalkPointKitchen.com"
}, {
"name": "Kyoto Amber Upper East",
"address": "225 Mulberry St, New York, NY 10012",
"description": "",
"url": "",
"image": { "url": "https://shoutem.github.io/restaurants/restaurant-3.jpg" },
"mail": ""
"description": "High quality, freshness, craveable flavors are just a few of the many qualities you will find by ordering online from us.\n\nAfter years of experience we have created the original and distinctive style that makes us stand out from other restaurants. Our mouthwatering dishes will definitely offer your palette flavors that are both unique and delicious.",
"url": "http://ambertogo.com/",
"image": { "url": "https://shoutem.github.io/static/getting-started/restaurant-3.jpg" },
"mail": "info@ambertogo.com"
}, {
"name": "Sushi Academy",
"address": "",
"description": "",
"url": "",
"image": { "url": "https://shoutem.github.io/restaurants/restaurant-4.jpg" },
"mail": ""
"address": "11310 Nebraska Ave. #1, Los Angeles, CA 90025",
"description": "The educational philosophy of the California Sushi Academy crosses borders, race and gender to bring greater Japanese cultural understanding and appreciation through the culinary experience.",
"url": "https://www.sushi-academy.com",
"image": { "url": "https://shoutem.github.io/static/getting-started/restaurant-4.jpg" },
"mail": "email@sushi-academy.com"
}, {
"name": "Sushibo",
"address": "",
"description": "",
"url": "",
"image": { "url": "https://shoutem.github.io/restaurants/restaurant-5.jpg" },
"mail": ""
"description": "Our passion for authentic, fresh Japanese cooking has brought us to connect with an extensive base of clients, as well as hotels and several businesses all around the city.\n\nAs a healthy and nutritious food, due to its low fat levels and high protein content, our sushi is made fresh daily in our kitchen.",
"url": "http://www.sushibo.cat/en/",
"image": { "url": "https://shoutem.github.io/static/getting-started/restaurant-5.jpg" },
"mail": "info@sushibo.cat"
}, {
"name": "Mastergrill",
"address": "",
"description": "",
"url": "",
"image": { "url": "https://shoutem.github.io/restaurants/restaurant-6.jpg" },
"mail": ""
"address": "34-09 College Point Blvd., Flushing, NY 11354",
"description": "A carnivore’s nirvana, Master Grill entertains families with nightly live music. And given the restaurant’s 1,000 seats, there’s plenty of space for high-energy little ones to boogie. The international food and salad bar is always a hit.",
"url": "https://mastergrillny.com",
"image": { "url": "https://shoutem.github.io/static/getting-started/restaurant-6.jpg" },
"mail": "info@mastergrillny.com"
}]
Loading

0 comments on commit a9484d8

Please sign in to comment.