parent
9e156db44b
commit
e64123427b
27 changed files with 2998 additions and 353 deletions
@ -1,67 +0,0 @@ |
||||
[ignore] |
||||
; We fork some components by platform |
||||
.*/*[.]android.js |
||||
|
||||
; Ignore "BUCK" generated dirs |
||||
<PROJECT_ROOT>/\.buckd/ |
||||
|
||||
; Ignore unexpected extra "@providesModule" |
||||
.*/node_modules/.*/node_modules/fbjs/.* |
||||
|
||||
; Ignore duplicate module providers |
||||
; For RN Apps installed via npm, "Libraries" folder is inside |
||||
; "node_modules/react-native" but in the source repo it is in the root |
||||
.*/Libraries/react-native/React.js |
||||
|
||||
; Ignore polyfills |
||||
.*/Libraries/polyfills/.* |
||||
|
||||
; Ignore metro |
||||
.*/node_modules/metro/.* |
||||
|
||||
[include] |
||||
|
||||
[libs] |
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js |
||||
node_modules/react-native/flow/ |
||||
node_modules/react-native/flow-github/ |
||||
|
||||
[options] |
||||
emoji=true |
||||
|
||||
module.system=haste |
||||
module.system.haste.use_name_reducers=true |
||||
# get basename |
||||
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' |
||||
# strip .js or .js.flow suffix |
||||
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' |
||||
# strip .ios suffix |
||||
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' |
||||
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' |
||||
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' |
||||
module.system.haste.paths.blacklist=.*/__tests__/.* |
||||
module.system.haste.paths.blacklist=.*/__mocks__/.* |
||||
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.* |
||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.* |
||||
|
||||
munge_underscores=true |
||||
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' |
||||
|
||||
module.file_ext=.js |
||||
module.file_ext=.jsx |
||||
module.file_ext=.json |
||||
module.file_ext=.native.js |
||||
|
||||
suppress_type=$FlowIssue |
||||
suppress_type=$FlowFixMe |
||||
suppress_type=$FlowFixMeProps |
||||
suppress_type=$FlowFixMeState |
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) |
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ |
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy |
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError |
||||
|
||||
[version] |
||||
^0.75.0 |
@ -0,0 +1,7 @@ |
||||
__snapshots__ |
||||
android |
||||
coverage |
||||
ios |
||||
node_modules |
||||
package-lock.json |
||||
package.json |
@ -0,0 +1,10 @@ |
||||
language: node_js |
||||
node_js: "node" |
||||
install: |
||||
- travis_retry npm install -g codecov |
||||
- travis_retry npm install |
||||
script: |
||||
- npm run prettier |
||||
- npm run lint |
||||
- npm run test |
||||
- codecov |
@ -1 +0,0 @@ |
||||
{} |
@ -1,49 +0,0 @@ |
||||
import React, { Component } from 'react'; |
||||
import { Platform, StyleSheet, Text, View } from 'react-native'; |
||||
import { createBottomTabNavigator } from 'react-navigation'; |
||||
|
||||
import BrowserView from './app/components/BrowserView' |
||||
|
||||
const instructions = Platform.select({ |
||||
ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu', |
||||
android: |
||||
'Double tap R on your keyboard to reload,\n' + |
||||
'Shake or press menu button for dev menu', |
||||
}); |
||||
|
||||
class App extends Component { |
||||
render() { |
||||
return ( |
||||
<View style={styles.container}> |
||||
<Text style={styles.welcome}>Welcome to React Bar!</Text> |
||||
<Text style={styles.instructions}>To get started, edit App.js</Text> |
||||
<Text style={styles.instructions}>{instructions}</Text> |
||||
</View> |
||||
); |
||||
} |
||||
} |
||||
|
||||
const styles = StyleSheet.create({ |
||||
container: { |
||||
flex: 1, |
||||
justifyContent: 'center', |
||||
alignItems: 'center', |
||||
backgroundColor: '#F5FCFF', |
||||
}, |
||||
welcome: { |
||||
fontSize: 20, |
||||
textAlign: 'center', |
||||
margin: 10, |
||||
}, |
||||
instructions: { |
||||
textAlign: 'center', |
||||
color: '#333333', |
||||
marginBottom: 5, |
||||
}, |
||||
}); |
||||
|
||||
export default createBottomTabNavigator({ |
||||
Home: { |
||||
screen: BrowserView |
||||
}, |
||||
}); |
@ -0,0 +1,20 @@ |
||||
MIT License |
||||
|
||||
Copyright (c) 2018 MetaMask |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
@ -1,9 +1,21 @@ |
||||
- [ ] i18n |
||||
- [ ] design systems |
||||
- [ ] android |
||||
- [ ] ci |
||||
- [ ] integration testing |
||||
- [ ] repo structure |
||||
- [ ] documentation |
||||
- [ ] changelog |
||||
- [ ] enable http (not just https) |
||||
 |
||||
|
||||
MetaMask is mobile web browser that provides easy access to websites that use the [Ethereum](https://ethereum.org/) blockchain. |
||||
|
||||
[http://metamask.io/](http://metamask.io/) |
||||
|
||||
[](https://travis-ci.org/bitpshr/MetaMask) |
||||
[](https://codecov.io/gh/bitpshr/MetaMask) |
||||
|
||||
## Development |
||||
|
||||
The following instructions assume that the React Native [Getting Started](https://facebook.github.io/react-native/docs/getting-started.html) guide for your platform has been completed. |
||||
|
||||
``` |
||||
$ npm i |
||||
$ react-native run-ios |
||||
``` |
||||
|
||||
## License |
||||
|
||||
[MIT](./LICENSE) |
||||
|
@ -0,0 +1,4 @@ |
||||
import Adapter from 'enzyme-adapter-react-16'; |
||||
import Enzyme from 'enzyme'; |
||||
|
||||
Enzyme.configure({ adapter: new Adapter() }); |
@ -0,0 +1,43 @@ |
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
||||
exports[`App should render correctly 1`] = ` |
||||
<Navigator |
||||
navigation={ |
||||
Object { |
||||
"actions": Object {}, |
||||
"addListener": [Function], |
||||
"dangerouslyGetParent": [Function], |
||||
"dispatch": [Function], |
||||
"getChildNavigation": [Function], |
||||
"getScreenProps": [Function], |
||||
"goBack": [Function], |
||||
"isFocused": [Function], |
||||
"navigate": [Function], |
||||
"router": Object { |
||||
"childRouters": Object { |
||||
"Home": null, |
||||
}, |
||||
"getActionCreators": [Function], |
||||
"getActionForPathAndParams": [Function], |
||||
"getComponentForRouteName": [Function], |
||||
"getComponentForState": [Function], |
||||
"getPathAndParamsForState": [Function], |
||||
"getScreenOptions": [Function], |
||||
"getStateForAction": [Function], |
||||
}, |
||||
"setParams": [Function], |
||||
"state": Object { |
||||
"index": 0, |
||||
"isTransitioning": false, |
||||
"routes": Array [ |
||||
Object { |
||||
"key": "Home", |
||||
"params": undefined, |
||||
"routeName": "Home", |
||||
}, |
||||
], |
||||
}, |
||||
} |
||||
} |
||||
/> |
||||
`; |
@ -0,0 +1,11 @@ |
||||
import { createBottomTabNavigator } from 'react-navigation'; |
||||
import BrowserScreen from '../BrowserScreen'; |
||||
|
||||
/** |
||||
* Root application component responsible for configurating the tab navigator |
||||
*/ |
||||
export default createBottomTabNavigator({ |
||||
Home: { |
||||
screen: BrowserScreen |
||||
} |
||||
}); |
@ -0,0 +1,10 @@ |
||||
import React from 'react'; |
||||
import { shallow } from 'enzyme'; |
||||
import App from './'; |
||||
|
||||
describe('App', () => { |
||||
it('should render correctly', () => { |
||||
const wrapper = shallow(<App />); |
||||
expect(wrapper).toMatchSnapshot(); |
||||
}); |
||||
}); |
@ -0,0 +1,120 @@ |
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
||||
exports[`Browser should render correctly 1`] = ` |
||||
<Component |
||||
style={ |
||||
Object { |
||||
"flex": 1, |
||||
} |
||||
} |
||||
> |
||||
<Component |
||||
style={ |
||||
Object { |
||||
"alignItems": "stretch", |
||||
"backgroundColor": "#f1f2f6", |
||||
"flexDirection": "row", |
||||
"paddingVertical": 8, |
||||
} |
||||
} |
||||
> |
||||
<Icon |
||||
allowFontScaling={false} |
||||
disabled={true} |
||||
name="angle-left" |
||||
onPress={[Function]} |
||||
size={30} |
||||
style={ |
||||
Object { |
||||
"color": "#ced6e0", |
||||
"flex": 0, |
||||
"height": 28, |
||||
"lineHeight": 28, |
||||
"paddingTop": 2, |
||||
"textAlign": "center", |
||||
"width": 36, |
||||
} |
||||
} |
||||
/> |
||||
<Icon |
||||
allowFontScaling={false} |
||||
disabled={true} |
||||
name="angle-right" |
||||
onPress={[Function]} |
||||
size={30} |
||||
style={ |
||||
Object { |
||||
"color": "#ced6e0", |
||||
"flex": 0, |
||||
"height": 28, |
||||
"lineHeight": 28, |
||||
"paddingTop": 2, |
||||
"textAlign": "center", |
||||
"width": 36, |
||||
} |
||||
} |
||||
/> |
||||
<TextInput |
||||
allowFontScaling={true} |
||||
autoCapitalize="none" |
||||
autoCorrect={false} |
||||
clearButtonMode="while-editing" |
||||
keyboardType="url" |
||||
onChangeText={[Function]} |
||||
onSubmitEditing={[Function]} |
||||
placeholder="Enter website address" |
||||
placeholderTextColor="#747d8c" |
||||
returnKeyType="go" |
||||
style={ |
||||
Object { |
||||
"backgroundColor": "#dfe4ea", |
||||
"borderRadius": 3, |
||||
"flex": 1, |
||||
"fontSize": 14, |
||||
"padding": 8, |
||||
} |
||||
} |
||||
underlineColorAndroid="transparent" |
||||
value="http://metamask.io" |
||||
/> |
||||
<Icon |
||||
allowFontScaling={false} |
||||
disabled={true} |
||||
name="refresh" |
||||
onPress={[Function]} |
||||
size={20} |
||||
style={ |
||||
Object { |
||||
"color": "#2f3542", |
||||
"flex": 0, |
||||
"height": 28, |
||||
"lineHeight": 28, |
||||
"paddingTop": 2, |
||||
"textAlign": "center", |
||||
"width": 36, |
||||
} |
||||
} |
||||
/> |
||||
</Component> |
||||
<WebView |
||||
onNavigationStateChange={[Function]} |
||||
originWhitelist={ |
||||
Array [ |
||||
"http://*", |
||||
"https://*", |
||||
] |
||||
} |
||||
scalesPageToFit={true} |
||||
source={ |
||||
Object { |
||||
"uri": "http://metamask.io", |
||||
} |
||||
} |
||||
style={ |
||||
Object { |
||||
"width": 750, |
||||
} |
||||
} |
||||
/> |
||||
</Component> |
||||
`; |
@ -0,0 +1,75 @@ |
||||
import React from 'react'; |
||||
import { TextInput, WebView } from 'react-native'; |
||||
import { shallow } from 'enzyme'; |
||||
import Browser from './'; |
||||
|
||||
describe('Browser', () => { |
||||
it('should render correctly', () => { |
||||
const wrapper = shallow(<Browser defaultURL="http://metamask.io" />); |
||||
expect(wrapper).toMatchSnapshot(); |
||||
}); |
||||
|
||||
it('should update input value', () => { |
||||
const wrapper = shallow(<Browser defaultURL="http://metamask.io" />); |
||||
wrapper.find(TextInput).simulate('ChangeText', 'foobar'); |
||||
expect(wrapper.state().inputValue).toBe('foobar'); |
||||
}); |
||||
|
||||
it('should enable back button', () => { |
||||
const wrapper = shallow(<Browser defaultURL="http://metamask.io" />); |
||||
expect(wrapper.find('[name="angle-left"]').prop('disabled')).toBe(true); |
||||
wrapper.find(WebView).simulate('NavigationStateChange', { canGoBack: true }); |
||||
expect(wrapper.find('[name="angle-left"]').prop('disabled')).toBe(false); |
||||
}); |
||||
|
||||
it('should enable forward button', () => { |
||||
const wrapper = shallow(<Browser defaultURL="http://metamask.io" />); |
||||
expect(wrapper.find('[name="angle-right"]').prop('disabled')).toBe(true); |
||||
wrapper.find(WebView).simulate('NavigationStateChange', { canGoForward: true }); |
||||
expect(wrapper.find('[name="angle-right"]').prop('disabled')).toBe(false); |
||||
}); |
||||
|
||||
it('should go back', () => { |
||||
const wrapper = shallow(<Browser defaultURL="http://metamask.io" />); |
||||
wrapper.setState({ inputValue: 'https://foobar' }); |
||||
wrapper.find(TextInput).simulate('SubmitEditing'); |
||||
expect(wrapper.state().url).toBe('https://foobar'); |
||||
}); |
||||
|
||||
it('should add protocol', () => { |
||||
const wrapper = shallow(<Browser defaultURL="http://metamask.io" />); |
||||
wrapper.setState({ inputValue: 'foobar' }); |
||||
wrapper.find(TextInput).simulate('SubmitEditing'); |
||||
expect(wrapper.state().url).toBe('https://foobar'); |
||||
}); |
||||
|
||||
it('should go back', () => { |
||||
const MockWebView = { goBack() {} }; // eslint-disable-line no-empty-function
|
||||
const stub = spyOn(MockWebView, 'goBack'); |
||||
const wrapper = shallow(<Browser defaultURL="http://metamask.io" />); |
||||
wrapper.find(WebView).simulate('NavigationStateChange', { canGoBack: true }); |
||||
wrapper.instance().webview = { current: MockWebView }; |
||||
wrapper.find('[name="angle-left"]').simulate('press'); |
||||
expect(stub).toBeCalled(); |
||||
}); |
||||
|
||||
it('should go forward', () => { |
||||
const MockWebView = { goForward() {} }; // eslint-disable-line no-empty-function
|
||||
const stub = spyOn(MockWebView, 'goForward'); |
||||
const wrapper = shallow(<Browser defaultURL="http://metamask.io" />); |
||||
wrapper.find(WebView).simulate('NavigationStateChange', { canGoBack: true }); |
||||
wrapper.instance().webview = { current: MockWebView }; |
||||
wrapper.find('[name="angle-right"]').simulate('press'); |
||||
expect(stub).toBeCalled(); |
||||
}); |
||||
|
||||
it('should reload', () => { |
||||
const MockWebView = { reload() {} }; // eslint-disable-line no-empty-function
|
||||
const stub = spyOn(MockWebView, 'reload'); |
||||
const wrapper = shallow(<Browser defaultURL="http://metamask.io" />); |
||||
wrapper.find(WebView).simulate('NavigationStateChange', {}); |
||||
wrapper.instance().webview = { current: MockWebView }; |
||||
wrapper.find('[name="refresh"]').simulate('press'); |
||||
expect(stub).toBeCalled(); |
||||
}); |
||||
}); |
@ -0,0 +1,10 @@ |
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
||||
exports[`BrowserScreen should render correctly 1`] = ` |
||||
<Screen> |
||||
<Browser |
||||
defaultProtocol="https://" |
||||
defaultURL="http://metamask.io" |
||||
/> |
||||
</Screen> |
||||
`; |
@ -0,0 +1,10 @@ |
||||
import React from 'react'; |
||||
import { shallow } from 'enzyme'; |
||||
import BrowserScreen from './'; |
||||
|
||||
describe('BrowserScreen', () => { |
||||
it('should render correctly', () => { |
||||
const wrapper = shallow(<BrowserScreen />); |
||||
expect(wrapper).toMatchSnapshot(); |
||||
}); |
||||
}); |
@ -0,0 +1,42 @@ |
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
||||
|
||||
exports[`Screen should render correctly 1`] = ` |
||||
<Component |
||||
style={ |
||||
Object { |
||||
"flex": 1, |
||||
} |
||||
} |
||||
> |
||||
<Component |
||||
style={ |
||||
Object { |
||||
"backgroundColor": "#2f3542", |
||||
"height": 1334, |
||||
"left": 0, |
||||
"position": "absolute", |
||||
"top": 0, |
||||
"width": 750, |
||||
} |
||||
} |
||||
> |
||||
<StatusBar |
||||
animated={false} |
||||
backgroundColor="#2f3542" |
||||
barStyle="light-content" |
||||
showHideTransition="fade" |
||||
/> |
||||
</Component> |
||||
<SafeAreaView |
||||
style={ |
||||
Object { |
||||
"flex": 1, |
||||
} |
||||
} |
||||
> |
||||
<Component> |
||||
Foobar |
||||
</Component> |
||||
</SafeAreaView> |
||||
</Component> |
||||
`; |
@ -1,36 +1,38 @@ |
||||
import React from 'react'; |
||||
import { |
||||
Dimensions, |
||||
SafeAreaView, |
||||
StatusBar, |
||||
StyleSheet, |
||||
View |
||||
} from 'react-native'; |
||||
import { colors, common } from '../../styles/variables'; |
||||
|
||||
export default function({ children }) { |
||||
const { height, width } = Dimensions.get('window'); |
||||
|
||||
return ( |
||||
<View style={common.flexGrow}> |
||||
<View style={{...styles.statusBarUnderlay, ...{ width, height }}}> |
||||
<StatusBar |
||||
backgroundColor={colors.tar} |
||||
barStyle="light-content" |
||||
/> |
||||
</View> |
||||
<SafeAreaView style={common.flexGrow}> |
||||
{children} |
||||
</SafeAreaView> |
||||
</View> |
||||
); |
||||
} |
||||
import React, { Component } from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
import { Dimensions, SafeAreaView, StatusBar, StyleSheet, View } from 'react-native'; |
||||
import { colors, baseStyles } from '../../styles/common'; |
||||
|
||||
const styles = StyleSheet.create({ |
||||
statusBarUnderlay: { |
||||
underlay: { |
||||
backgroundColor: colors.tar, |
||||
left: 0, |
||||
position: 'absolute', |
||||
top: 0 |
||||
} |
||||
}); |
||||
|
||||
/** |
||||
* Base view component providing consistent styling meant to wrap other views |
||||
*/ |
||||
export default class Screen extends Component { |
||||
static propTypes = { |
||||
/** |
||||
* Content to wrap inside this view |
||||
*/ |
||||
children: PropTypes.node |
||||
}; |
||||
|
||||
render() { |
||||
const { height, width } = Dimensions.get('window'); |
||||
|
||||
return ( |
||||
<View style={baseStyles.flexGrow}> |
||||
<View style={{ ...styles.underlay, ...{ width, height } }}> |
||||
<StatusBar backgroundColor={colors.tar} barStyle="light-content" /> |
||||
</View> |
||||
<SafeAreaView style={baseStyles.flexGrow}>{this.props.children}</SafeAreaView> |
||||
</View> |
||||
); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,15 @@ |
||||
import React from 'react'; |
||||
import { shallow } from 'enzyme'; |
||||
import { View } from 'react-native'; |
||||
import Screen from './'; |
||||
|
||||
describe('Screen', () => { |
||||
it('should render correctly', () => { |
||||
const wrapper = shallow( |
||||
<Screen> |
||||
<View>Foobar</View> |
||||
</Screen> |
||||
); |
||||
expect(wrapper).toMatchSnapshot(); |
||||
}); |
||||
}); |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue