diff --git a/my-project/App.js b/my-project/App.js index f730e8571557e15e7b699ff9b4b21bb0caeb32f9..cb904f68989755aa75fd16ac1c0d8538127aa094 100644 --- a/my-project/App.js +++ b/my-project/App.js @@ -1,19 +1,117 @@ -import React from 'react'; -import { StyleSheet, Text, View } from 'react-native'; - -export default function App() { - return ( - <View style={styles.container}> - <Text>Deathnight</Text> - </View> - ); +import React, { Component } from 'react'; +import { + StyleSheet, + Text, + View, + Image, + TouchableOpacity +} from 'react-native'; +import { + Provider as PaperProvider, + Appbar, + DefaultTheme +} from 'react-native-paper' + +import Song from './components/Song/Song' +import SongList from './components/SongList/SongList' +import Header from './components/Header/Header' +import Searchbar from './components/Searchbar/Searchbar' + +import SongStore from './components/SongService/SongStore' +import SongService from './components/SongService/SongService' + +class App extends Component { + + state = { + showMenu: false, + songData: [] + } + + songStore = new SongStore() + + executeSearch = async (searchParams) => { + this.setState({ + songData: await this.songStore.searchForSongAsync(searchParams) + }) + } + + toggleMenu = () => { + this.setState(prevState => ({ + showMenu: !prevState.showMenu + })) + } + + render() { + let twitter = this.state.isShowingTwitter + let songData = this.state.songData + + const theme = { + ...DefaultTheme, + roundness: 2, + colors: { + ...DefaultTheme.colors, + primary: '#222', + accent: '#fff', + }, + }; + + return ( + <PaperProvider theme={theme}> + <Header /> + <View style={styles.container}> + <Searchbar executeSearch={this.executeSearch} showMenu={this.state.showMenu}/> + <View style={styles.subContainer1}> + {/* <Text style={styles.text}>Results</Text> */} + {songData.length > 0 + ? + <SongList listOfSongs={songData} /> + : + <Text style={styles.text}>No results</Text> + } + <TouchableOpacity + style={styles.button} + onPress={this.toggleMenu} + > + <Text style={{fontSize: 20, color: 'white'}}>Search settings</Text> + </TouchableOpacity> + </View> + </View> + </PaperProvider> + ) + } } const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#fff', - alignItems: 'center', - justifyContent: 'center', - }, + container: { + flex: 1, + flexDirection: 'column', + backgroundColor: '#333', + alignItems: 'center', + justifyContent: 'space-between', + padding: 0, + height: 'auto', + overflow: 'hidden' + }, + text: { + fontSize: 25, + color: 'white', + marginTop: 10, + marginBottom: 10 + }, + subContainer1: { + flex: 1, + backgroundColor: '#333', + alignItems: 'center', + height: '100%' + }, + button: { + backgroundColor: '#222', + padding: 20, + borderRadius: 20, + fontSize: 20, + marginTop: 10, + marginBottom: 10 + } }); + +export default App diff --git a/my-project/components/Header/Header.js b/my-project/components/Header/Header.js new file mode 100644 index 0000000000000000000000000000000000000000..e0d50311214cd0185945f5d9bbd60fea1512792b --- /dev/null +++ b/my-project/components/Header/Header.js @@ -0,0 +1,47 @@ +// import React from 'react' +// import { +// StyleSheet, +// Text, +// View +// } from 'react-native'; +// +// function Header() { +// return( +// <View style={styles.header}> +// <Text style={styles.text}>The playlist of</Text> +// <Text style={styles.text}>Epicness</Text> +// </View> +// ) +// } +// +// const styles = StyleSheet.create({ +// header: { +// +// backgroundColor: '#3e3f40', +// alignItems: 'center', +// height: 'auto', +// width: '100%' +// }, +// text: { +// color: 'white', +// fontSize: 30 +// } +// }) + +import * as React from 'react'; +import { Appbar } from 'react-native-paper'; + +export default class Header extends React.Component { + render() { + return ( + <Appbar.Header> + <Appbar.Content + title="Spotifake" + subtitle="by Erling O" + /> + {/* <Appbar.Action icon="search" onPress={this._handleSearch} /> + <Appbar.Action icon="more-vert" onPress={this._handleMore} /> */} + </Appbar.Header> + ); + } +} diff --git a/my-project/components/Searchbar/FilterButton.js b/my-project/components/Searchbar/FilterButton.js new file mode 100644 index 0000000000000000000000000000000000000000..4cc5f3fd04a7b0199adbae8254907280c73e65eb --- /dev/null +++ b/my-project/components/Searchbar/FilterButton.js @@ -0,0 +1,78 @@ +import React, { Component } from 'react' +import { + StyleSheet, + Text, + View, + TouchableOpacity, + TouchableHighlight, +} from 'react-native' + +class FilterButton extends Component { + + state = { + active: false + } + + toggle = this.props.toggle + + handlePress = () => { + this.setState(prevState => ({ + active: !prevState.active + })) + this.toggle() + } + + render() { + const active = this.state.active + const text = this.props.text + + + return( + <View style={styles.container}> + {active + ? + <TouchableHighlight onPress={this.handlePress} style={styles.active}> + <Text style={styles.activeText}>{text}</Text> + </TouchableHighlight> + : + <TouchableHighlight onPress={this.handlePress} style={styles.inActive}> + <Text style={styles.inActiveText}>{text}</Text> + </TouchableHighlight> + } + </View> + ) + } +} + +const styles = StyleSheet.create({ + container: { + marginRight: 10, + width: 135 + }, + active: { + backgroundColor: 'pink', + padding: 20, + borderRadius: 20, + // marginTop: 10, + // marginBottom: 10 + }, + activeText: { + fontSize: 20, + color: 'black', + textAlign: 'center' + }, + inActive: { + backgroundColor: '#333', + padding: 20, + borderRadius: 20, + // marginTop: 10, + // marginBottom: 10 + }, + inActiveText: { + color: 'white', + fontSize: 20, + textAlign: 'center' + } +}) + +export default FilterButton diff --git a/my-project/components/Searchbar/Searchbar.js b/my-project/components/Searchbar/Searchbar.js new file mode 100644 index 0000000000000000000000000000000000000000..17daa2911002e998075fdf1c3a2111ec887105a2 --- /dev/null +++ b/my-project/components/Searchbar/Searchbar.js @@ -0,0 +1,122 @@ +import React, { Component } from 'react' +import { + StyleSheet, + Text, + View, + Image, + TouchableOpacity, + TextInput +} from 'react-native' + +import SongStore from '../SongService/SongStore' +import FilterButton from './FilterButton' + +class Searchbar extends Component { + + state = { + searchString: null, + limit: null, + offset: null, + filterBy: 'duration_ms', + greaterThan: null, + sortBy: 'name.keyword', + sortOrder: null, + } + + executeSearch = this.props.executeSearch + songStore = new SongStore() + + componentDidMount = () => { + this.setState({searchString: 'lil Wayne'}) + setTimeout(this.handleSearch, 0) + } + + handleSearch = async () => { + console.log('vi prøver dette') + console.log(this.state); + this.executeSearch(this.state) + } + + handleSortChange = async () => { + this.setState((prevState) =>( + prevState.sortOrder === null ? {sortOrder: 'asc'} : {sortOrder: null} + )) + setTimeout(this.handleSearch, 0) + } + + handleFilterChange = async () => { + this.setState((prevState) =>( + prevState.greaterThan == null ? {greaterThan: 180000} : {greaterThan: null} + )) + setTimeout(this.handleSearch, 0) + } + + + render() { + const sortButtonText = (this.state.sortOrder === null ? 'Relevance' : 'A-Z' ) + const showMenu = this.props.showMenu + + return( + <View style={styles.container}> + <View style={styles.searchBarContainer}> + <TextInput + style={styles.searchbar} + placeholder='Search...' + onChangeText={searchString => this.setState({searchString})} + onSubmitEditing={this.handleSearch} + /> + </View> + {showMenu && + <View> + <View style={styles.filterMenu}> + <Text style={{fontSize: 25, color: 'white'}}>Sort By:</Text> + <FilterButton text={sortButtonText} toggle={this.handleSortChange} /> + </View> + <View style={styles.filterMenu}> + <Text style={{fontSize: 25, color: 'white'}}>Filter:</Text> + <FilterButton text='>3 min' toggle={this.handleFilterChange} /> + </View> + </View> + } + </View> + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flexDirection: 'column', + alignItems: 'center', + backgroundColor: '#222', + width: '100%', + paddingBottom: 10, + paddingTop: 5 + }, + searchBarContainer: { + flexDirection: 'row', + justifyContent: 'space-around', + alignItems: 'flex-start', + backgroundColor: '#222', + width: '100%', + paddingBottom: 10, + }, + searchbar: { + height: 50, + borderColor: '#9c9b9a', + backgroundColor:'#e1e3e8', + width: '85%', + borderWidth: 2, + borderRadius: 15, + fontSize: 25 + }, + filterMenu: { + flexDirection: 'row', + width: '70%', + marginTop: 10, + justifyContent: 'space-between', + alignItems: 'center' + } +}) + +export default Searchbar diff --git a/my-project/components/Song/Song.js b/my-project/components/Song/Song.js new file mode 100644 index 0000000000000000000000000000000000000000..d67736d7943b2cef2eb692cded615f09c06be462 --- /dev/null +++ b/my-project/components/Song/Song.js @@ -0,0 +1,178 @@ +import React, { Component } from 'react' +import { + StyleSheet, + Text, + View, + Image, + TouchableOpacity, + Linking +} from 'react-native'; + +class Song extends Component { + + state = { + image: {uri: this.props.imageURL}, + name: this.props.name, + artist: this.props.artist, + album: this.props.album, + spotifyURL: this.props.spotifyURL, + duration: this.props.duration, + collapsed: true + } + + handlePress = () => { + this.setState(prevState => ( + { collapsed: !prevState.collapsed } + )) + } + + render() { + let image = this.state.image + let name = this.state.name + let artist = this.state.artist + let album = this.state.album + let duration = this.state.duration + let collapsed = this.state.collapsed + const spotifyURL = this.state.spotifyURL + const spotifyIcon = { uri: 'https://static.spin.com/files/2018/05/Spotify-Logo-1526659588-640x469.png'} + + return( + <View style={styles.container}> + {collapsed ? + <TouchableOpacity style={styles.songContainerCollapsed} onPress={this.handlePress}> + <Image source={image} style={styles.image}/> + <Text numberOfLines={2} style={styles.songName}>{name}</Text> + </TouchableOpacity> + : + <TouchableOpacity style={styles.songContainerFull} onPress={this.handlePress}> + <View style={styles.imagecontainerFull}> + <Image source={image} style={styles.imageFull}/> + </View> + <View style={styles.headerBox}> + <Text style={styles.songNameFull}>{name}</Text> + <Text style={styles.artist}>{artist}</Text> + <Text style={styles.album}>{duration} min</Text> + </View> + <TouchableOpacity + style={styles.button} + onPress={() => Linking.openURL(spotifyURL)} + > + <Image style={styles.imageMini} source={spotifyIcon} /> + <Text style={styles.buttonText}>Spotify</Text> + </TouchableOpacity> + + </TouchableOpacity> + } + </View> + ) + } +} + +const styles = StyleSheet.create({ + container: { + backgroundColor: '#333', + alignItems: 'center', + flexDirection: 'row', + marginBottom: 10, + justifyContent: 'space-around', + }, + songContainerCollapsed: { + alignItems: 'center', + flexDirection: 'row', + backgroundColor: '#393b40', + width: '95%', + borderRadius: 40, + height: 90, + }, + songContainerFull: { + flexDirection: 'column', + justifyContent: 'space-around', + alignItems: 'center', + backgroundColor: '#393b40', + width: '95%', + borderRadius: 40, + // height: 300, + }, + image: { + flex: 1, + maxWidth: 80, + height: 80, + borderRadius: 40, + marginLeft: 5, + }, + imageFull: { + flex: 1, + maxWidth: 200, + height: 200, + borderRadius: 40, + marginBottom: 10, + marginTop: 10 + }, + imageMini: { + flex: 1, + maxWidth: 30, + height: 30, + borderRadius: 10, + marginLeft: 2, + }, + imagecontainerFull: { + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + width: '100%', + }, + songName: { + fontSize: 22, + color: 'white', + paddingLeft: 20, + maxWidth: 250 + }, + songNameFull: { + fontSize: 25, + color: 'white', + textAlign: 'center', + paddingBottom: 0 + }, + artist: { + fontSize: 23, + color: '#84888a', + textAlign: 'center', + paddingBottom: 10 + }, + album: { + fontSize: 18, + color: 'white', + textAlign: 'center' + }, + headerBox: { + // flex: 2, + flexDirection: 'column', + alignItems: 'center', + marginBottom: 20 + }, + imageBoxFull: { + flex: 1, + justifyContent: 'center', + alignItems: 'center' + }, + button: { + flex: 1, + backgroundColor: '#222', + alignItems: 'center', + flexDirection: 'row', + maxWidth: 150, + padding: 15, + borderRadius: 20, + fontSize: 20, + marginTop: 10, + marginBottom: 10 + }, + buttonText: { + flex: 2, + paddingLeft: 10, + fontSize: 22, + color: 'white' + } +}) + +export default Song diff --git a/my-project/components/SongList/SongList.js b/my-project/components/SongList/SongList.js new file mode 100644 index 0000000000000000000000000000000000000000..acb096e1d255bda9433238530655adb802b68b2b --- /dev/null +++ b/my-project/components/SongList/SongList.js @@ -0,0 +1,44 @@ +import React, { Component } from 'react' +import { + StyleSheet, + Text, + View, + ScrollView, + Image, + TouchableOpacity +} from 'react-native'; + +import Song from '../Song/Song' + +class SongList extends Component { + + render() { + + let listOfSongs = this.props.listOfSongs + + return( + <ScrollView style={styles.container}> + {listOfSongs.map(song => ( + <Song + key={song.id} + name={song.name} + artist={song.artist} + album={song.album} + duration={song.duration} + imageURL={song.imageURL} + spotifyURL={song.url} + /> + ))} + </ScrollView> + ) + } +} + +const styles = StyleSheet.create({ + container: { + paddingTop: 10, + height: 'auto' + } +}) + +export default SongList diff --git a/my-project/components/SongService/SongService.js b/my-project/components/SongService/SongService.js new file mode 100644 index 0000000000000000000000000000000000000000..d7ccf6d4c2318ff56e8969c5ff1a714c87ead1bb --- /dev/null +++ b/my-project/components/SongService/SongService.js @@ -0,0 +1,49 @@ +const webApiUrl = "http://it2810-67.idi.ntnu.no:5000/api/tracks"; + +class SongService { + get = async (urlParams) => { + const options = { + method: "GET", + }; + const request = new Request(webApiUrl + "?" + urlParams, options); + const response = await fetch(request); + return response.json(); + }; + post = async (model, urlParams) => { + const headers = new Headers(); + headers.append("Content-Type", "application/json"); + let options = { + method: "POST", + headers, + body: JSON.stringify(model) + }; + const request = new Request(webApiUrl + "/" + urlParams, options); + const response = await fetch(request); + return response; + }; + put = async (model) => { + const headers = new Headers() + headers.append("Content-Type", "application/json"); + let options = { + method: "PUT", + headers, + body: JSON.stringify(model) + }; + const request = new Request(webApiUrl, options); + const response = await fetch(request); + return response; + }; + delete = async (id) => { + const headers = new Headers(); + headers.append("Content-Type", "application/json"); + const options = { + method: "DELETE", + headers + }; + const request = new Request(webApiUrl + "/" + id, options); + const response = await fetch(request); + return response; + }; +} + +export default SongService; diff --git a/my-project/components/SongService/SongStore.js b/my-project/components/SongService/SongStore.js new file mode 100644 index 0000000000000000000000000000000000000000..9712f28fb3bbbacb2a06dfdd049d8d1ae9ff6772 --- /dev/null +++ b/my-project/components/SongService/SongStore.js @@ -0,0 +1,155 @@ +import SongService from "./SongService"; + + +class SongStore { + songData = []; + status; + initialQuery; + + constructor() { + this.songService = new SongService(); + this.status = "initial"; + this.initialQuery = ""; + } + + clearSongData = () => { + this.songData = []; + }; + + searchForSongAsync = async (paramList) => { + let urlParamsObject = {}; + console.log(paramList) + + if (!(paramList.searchString === null || paramList.searchString === "")) { + urlParamsObject['searchString'] = paramList.searchString + } + if (paramList.filterBy !== null) { + urlParamsObject['filterBy'] = paramList.filterBy + } + if (paramList.greaterThan !== null) { + urlParamsObject['greaterThan'] = paramList.greaterThan + } + if (paramList.sortBy !== null) { + urlParamsObject['sortBy'] = paramList.sortBy + } + if (paramList.sortOrder !== null) { + urlParamsObject['sortOrder'] = paramList.sortOrder + } + if (paramList.limit !== null) { + urlParamsObject['limit'] = paramList.limit + } + if (paramList.offset !== null) { + urlParamsObject['offset'] = paramList.offset + } + const urlParams = new URLSearchParams(urlParamsObject); + const data = await this.songService.get(urlParams) + .then((data) => { + this.clearSongData(); + let i = 0; + data.body.hits.hits.forEach((song) => { + song = song._source; + this.songData.push({ + id: song.id, + url: song.external_urls.spotify, + imageURL: song.album.images[1].url, + name: song.name, + artist: song.artists[0].name, + album: song.album.name, + duration: Math.floor(song.duration_ms / 60000), + rating: Math.round(song.cumulated_user_review_score / song.total_user_reviews) + }); + i++; + }); + console.log("New request has ran"); + + }) + const listOfSongs = this.songData + // console.log('this is the list of songs') + // console.log(listOfSongs); + return( + listOfSongs + ) + } + + searchForSongWithoutListWipeAsync = async (paramList) => { + let urlParamsObject = {}; + + if (!(paramList.searchString === null || paramList.searchString === "")) { + urlParamsObject['searchString'] = paramList.searchString + } + if (paramList.filterBy !== null) { + urlParamsObject['filterBy'] = paramList.filterBy + } + if (paramList.greaterThan !== null) { + urlParamsObject['greaterThan'] = paramList.greaterThan + } + if (paramList.sortBy !== null) { + urlParamsObject['sortBy'] = paramList.sortBy + } + if (paramList.sortOrder !== null) { + urlParamsObject['sortOrder'] = paramList.sortOrder + } + if (paramList.limit !== null) { + urlParamsObject['limit'] = paramList.limit + } + if (paramList.offset !== null) { + urlParamsObject['offset'] = paramList.offset + } + + const urlParams = new URLSearchParams(urlParamsObject); + const data = await this.songService.get(urlParams) + .then((data) => { + let i = 0; + data.body.hits.hits.forEach((song) => { + song = song._source; + this.songData.push({ + id: song.id, + name: song.name, + artist: song.artists[0].name, + imageURL: song.album.images[1].url, + album: song.album.name, + duration: Math.floor(song.duration_ms / 60000), + rating: Math.round(song.cumulated_user_review_score / song.total_user_reviews) + }); + i++; + }); + console.log("New request has ran"); + + return( + this.songData + ) + + // ListStore.addElementsToList(this.songData); + // ListStore.setTotalHits(data.body.hits.total.value); + }) + }; +} +export default SongStore + + // createSongRatingAsync = async (model) => { + // try { + // let data = model.split("-"); + // let params = { + // id: data[0], + // rating: data[1] + // }; + // const response = await this.songService.post(model, params.id + "?score=" + params.rating); + // if (response.status === 201) { + // runInAction(() => { + // this.status = "success"; + // }) + // } + // + // } catch (error) { + // runInAction(() => { + // this.status = error.toString(); + // }); + // } + // }; +// +// } + + +//export instance of SongStore in order to use the same information in the same store accross the application +// const store = new SongStore(); +// export default store; diff --git a/my-project/package.json b/my-project/package.json index 54ebe788436d0777662268bd886e974e1c757884..c1a92abfb9a1a882910153674c3cc8107e8bb878 100644 --- a/my-project/package.json +++ b/my-project/package.json @@ -12,6 +12,7 @@ "react": "16.8.3", "react-dom": "16.8.3", "react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz", + "react-native-paper": "^3.2.1", "react-native-web": "^0.11.7" }, "devDependencies": { diff --git a/my-project/yarn.lock b/my-project/yarn.lock index 9273bb2c57bfcc169bd97c80b7078cea6a0a4b41..12b589005d4286954b8dc6656c2a933388f54fc2 100644 --- a/my-project/yarn.lock +++ b/my-project/yarn.lock @@ -850,6 +850,14 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@callstack/react-theme-provider@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@callstack/react-theme-provider/-/react-theme-provider-3.0.5.tgz#a173e455e9603c9c45357a3b6ace1273086527ca" + integrity sha512-Iec+ybWN0FvNj87sD3oWo/49edGUP0UOSdMnzCJEFJIDYr992ECIuOV89burAAh2/ibPCxgLiK6dmgv2mO/8Tg== + dependencies: + deepmerge "^3.2.0" + hoist-non-react-statics "^3.3.0" + "@expo/vector-icons@^10.0.2": version "10.0.6" resolved "https://registry.yarnpkg.com/@expo/vector-icons/-/vector-icons-10.0.6.tgz#5718953ff0b97827d11dae5787976fa8ce5caaed" @@ -1519,7 +1527,7 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -1531,11 +1539,32 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== +color@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" + integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + commander@^2.19.0, commander@^2.9.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -1741,6 +1770,11 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deepmerge@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.3.0.tgz#d3c47fd6f3a93d517b14426b0628a17b0125f5f7" + integrity sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA== + define-properties@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -2488,6 +2522,18 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" +hoist-non-react-statics@^2.3.1: + version "2.5.5" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" + integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== + +hoist-non-react-statics@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#101685d3aff3b23ea213163f6e8e12f4f111e19f" + integrity sha512-wbg3bpgA/ZqWrZuMOeJi8+SKMhr7X9TesL/rXMjTzh0p0JUBo3II8DHboYbuIXWRlttrUFxwcu/5kygrCw8fJw== + dependencies: + react-is "^16.7.0" + hosted-git-info@^2.1.4: version "2.8.5" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" @@ -2622,6 +2668,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -4171,7 +4222,7 @@ react-dom@16.8.3: prop-types "^15.6.2" scheduler "^0.13.3" -react-is@^16.8.1: +react-is@^16.7.0, react-is@^16.8.1: version "16.11.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa" integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw== @@ -4181,6 +4232,22 @@ react-native-branch@~3.0.1: resolved "https://registry.yarnpkg.com/react-native-branch/-/react-native-branch-3.0.1.tgz#5b07b61cbd290168cd3c3662e017ebe0f356d2ca" integrity sha512-vbcYxPZlpF5f39GAEUF8kuGQqCNeD3E6zEdvtOq8oCGZunHXlWlKgAS6dgBKCvsHvXgHuMtpvs39VgOp8DaKig== +react-native-paper@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-3.2.1.tgz#8b3f4b8ce36ca471aba3fa7407194afe8595cd35" + integrity sha512-PpdKW/NQd/dLeeo17+uC82sF2g236dp4ksJ6L11fUXikGaOQaIiIojHxpWxHHVrXya6ZwXXbHGuyOHY3+XNzfw== + dependencies: + "@callstack/react-theme-provider" "^3.0.5" + color "^3.1.2" + react-native-safe-area-view "^0.12.0" + +react-native-safe-area-view@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.12.0.tgz#5c312f087300ecf82e8541c3eac25d560e147f22" + integrity sha512-UrAXmBC4KNR5K2eczIDZgqceWyKsgG9gmWFerHCvoyApfei8ceBB9u/c//PWCpS5Gt8MRLTmX5jPtzdXo2yNqg== + dependencies: + hoist-non-react-statics "^2.3.1" + react-native-view-shot@2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/react-native-view-shot/-/react-native-view-shot-2.6.0.tgz#3b23675826f67658366352c4b97b59a6aded2f43" @@ -4659,6 +4726,13 @@ simple-plist@^1.0.0: bplist-parser "0.2.0" plist "^3.0.1" +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"