[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\"module:metro-react-native-babel-preset\"],\n  \"plugins\": [\n    [\n      \"@babel/plugin-proposal-decorators\",\n      {\n        \"legacy\": true\n      }\n    ]\n  ]\n}\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"extends\": \"airbnb\",\n  \"env\": {\n    \"browser\": true,\n    \"es6\": true,\n    \"jest/globals\": true\n  },\n  \"settings\": {\n    \"import/resolver\": {\n      \"node\": {\n        \"extensions\": [\".js\", \".android.js\", \".ios.js\"]\n      }\n    }\n  },\n  \"plugins\": [\"jest\"],\n  \"parser\": \"babel-eslint\",\n  \"rules\": {\n    \"no-use-before-define\": 0,\n    \"import/prefer-default-export\": 0,\n    \"react/jsx-filename-extension\": [\n      \"error\",\n      {\n        \"extensions\": [\".js\", \".jsx\"]\n      }\n    ],\n    \"react/prefer-stateless-function\": 0,\n    \"react/jsx-indent-props\": [\"error\", 2],\n    \"react/jsx-indent\": [\"error\", 2],\n    \"consistent-return\": 0,\n    \"max-len\": 0,\n    \"react/forbid-prop-types\": 0,\n    \"no-nested-ternary\": 0,\n    \"no-console\": 0,\n    \"no-mixed-operators\": 0,\n    \"react/no-array-index-key\": 0,\n    \"camelcase\": 0,\n    \"no-underscore-dangle\": 0,\n    \"react/sort-comp\": 0,\n    \"no-return-assign\": 0,\n    \"comma-dangle\": [\"error\", \"never\"]\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n\n*/*.DS_Store\n*.DS_Store\n\n# expo\n.expo/\n\n# dependencies\n/node_modules\n\n# misc\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\npackage-lock.json\nyarn.lock\n\n\n.vscode"
  },
  {
    "path": ".travis.yml",
    "content": "#\n# Travis CI config\n# https://docs.travis-ci.com/user/customizing-the-build/\n#\n\nenv:\n  - COVERALLS_ENV=production\n\nbranches:\n  only:\n    - master\n\nlanguage: node_js\n\nnode_js:\n  - \"11.2.0\"\n\ncache:\n  directories:\n    - \"node_modules\"\n\nscript:\n  - npm run lint\n"
  },
  {
    "path": "App.js",
    "content": "import React from 'react';\nimport Sentry from 'sentry-expo';\nimport { createAppContainer } from 'react-navigation';\nimport { RootStack } from './config/router';\n\n// Remove this once Sentry is correctly setup.\nSentry.enableInExpoDevelopment = false;\n\nSentry.config(\n  'https://705f92b0edb44599b814955f3219c1cd@sentry.io/1367138',\n).install();\n\n// App Containers\nconst AppContainer = createAppContainer(RootStack);\n\nexport default class App extends React.Component {\n  render() {\n    return <AppContainer />;\n  }\n}\n"
  },
  {
    "path": "App.test.js",
    "content": "import React from 'react';\nimport renderer from 'react-test-renderer';\nimport App from './App';\n\nit('renders without crashing', () => {\n  const rendered = renderer.create(<App />).toJSON();\n  expect(rendered).toBeTruthy();\n});\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Stephen Kempin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "# Lyrics King <img src=\"_github/lk-logo.gif\" width=\"80\">\n\n![](https://img.shields.io/github/license/SKempin/Lyrics-King-React-Native.svg?style=flat-square)\n![](https://img.shields.io/github/stars/SKempin/Lyrics-King-React-Native.svg?style=flat-square)\n![](https://img.shields.io/github/forks/SKempin/Lyrics-King-React-Native.svg?style=flat-square)\n[![Build Status](https://travis-ci.org/SKempin/Lyrics-King-React-Native.svg?branch=master)](https://travis-ci.org/SKempin/Lyrics-King-React-Native)\n[![Mentioned in Awesome Expo](https://awesome.re/mentioned-badge.svg)](https://github.com/expo/awesome-expo)\n\n\nA [React Native](https://facebook.github.io/react-native/) native app utilising [Expo](https://expo.io/), [React Navigation](https://reactnavigation.org) and fetching data from multiple API's ([Deezer](https://developers.deezer.com/) and [Lyrics.OVH](https://www.lyrics.ovh)). UI built with [Adobe XD](https://www.adobe.com/uk/products/xd.html).\n<br><br>\nBuilt as a personal training project for [React Native](https://facebook.github.io/react-native/). Designed in [Adobe XD](https://www.adobe.com/uk/products/xd.html). Design and development by [Stephen Kempin](https://www.stephenkempin.co.uk). This project was bootstrapped with [Create React Native App](https://github.com/react-community/create-react-native-app).\n\n### [Expo Demo Link](https://expo.io/@skempin/lyrics-king)\n\n<img src=\"https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/header-overview.jpg\" width=\"900\"  alt=\"Lyrics King - React Native Expo app\">\n\n## Contents\n\n- [App Preview](#app-preview)\n\t- [Video Preview](#video-preview)\n\t- [Search Screen](#search-screen)\n\t- [Details Screen](#details-screen)\n\t- [About Screen](#about-screen)\n\t- [Navigation (Drawer)](#navigation-drawer)\n- [Expo Project Page](#expo-project-page)\n- [Adobe XD files](#adobe-xd-files)\n- [App Features](#app-features)\n\t- [Screens](#screens)\n\t- [Components](#components)\n\t- [Config](#config)\n\t- [Lib](#lib)\n\t- [Utils](#utils)\n- [Getting Started](#getting-started)\n- [What's Included](#whats-included)\n- [API's Used](#apis-used)\n- [Contributing](#contributing)\n- [Author](#author)\n- [Google Play Store](#google-play-store)\n- [Donate](#donate)\n- [License](#license)\n\n\n## App Preview\n\n### Video Preview\n\n<a href=\"https://expo.io/@skempin/lyrics-king\">\n\t<img src=\"https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/screenshots/video.gif\" width=\"350\" >\n</a>\n\n### Search Screen\n\n<img src=\"https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/screenshots/search.jpg\" width=\"270\" alt=\"Lyrics King - Search screen\" hspace=\"5\"><img src=\"https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/screenshots/suggestions.jpg\" width=\"270\" alt=\"Lyrics King - Suggestions on search screen\">\n\n### Details Screen\n\n<img src=\"https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/screenshots/details-ariana.jpg\" width=\"270\" hspace=\"5\" alt=\"Lyrics King - Details screen, Ariana Grande\"><img src=\"https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/screenshots/details-above.jpg\" width=\"270\" hspace=\"5\" alt=\"Lyrics King - Details screen, Above and Beyond\"><img src=\"https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/screenshots/details-dua.jpg\" width=\"270\"  alt=\"Lyrics King - Details screen, Dua Lipa\">\n\n### About Screen\n\n<img src=\"https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/screenshots/about.jpg\" width=\"270\" alt=\"Lyrics King - About screen\">\n\n### Navigation (Drawer)\n\n<img src=\"https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/screenshots/navigation.jpg\" width=\"270\" alt=\"Lyrics King - Navigation drawer\">\n\n## [Expo Project Page](https://expo.io/@skempin/lyrics-king)\n\nThis project has been built using [Expo](https://expo.io/). Please install `npm install expo-cli --global` to run this project locally.\n\nScan the below QR code to open the project on Android:\n\n![](https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/qr.png)\n\n<br>\n\n## Adobe XD files\n\nDesign files for the UI can be found in `_design_assets/adobeXD` in the project root. UI design implemented with [flexbox](https://docs.expo.io/versions/latest/react-native/flexbox).\n\n## App Features\n\n### Screens\n\n`src/screens/`\n\n- `SearchScreen.js` - Search the [Deezer API](https://developers.deezer.com/) by song title (_class component_)\n- `DetailsScreen.js` - Selected song details (including [Lyrics.ovh](https://www.lyrics.ovh/) API call) (_class component_)\n- `AboutScreen.js` - About details (_functional component_)\n\n### Components\n\n`src/components/`\n\n- `Credits.js` - Development credentials template (_functional component_)\n- `SocialButton.js` - Button template for sharing links/ the app (_functional component_)\n- `Suggestions.js` - Song suggestions (_functional component_)\n\n### Config\n\n`src/config/`\n\n- `router.js` - App navigation routing (including drawer nav render method)\n- `colours.js` - Colour constants\n\n### Lib\n\n`src/lib/`\n\n- `constants.js` - Expo manifest [constants](https://docs.expo.io/versions/latest/sdk/constants#__next) and functions\n\n### Utils\n\n`src/utils/`\n\n- `shareHelper.js` - Native device [share method](https://docs.expo.io/versions/latest/react-native/share)\n\n## Getting Started\n\n1. Install the latest Node\n2. Install [Expo](https://expo.io/) - `npm install expo-cli --global`\n3. `cd` into this project directory\n4. `npm install` or `yarn install`\n5. Run `expo start`\n\n## What's Included\n\n|                                Name                                | Description                                                                                                                                      |\n| :----------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------ |\n|           [Expo (incl. React Native)](https://expo.io/)            | Expo is a free and open source toolchain built around React Native to help you build native iOS and Android projects using JavaScript and React. |\n|          [React Navigation](https://reactnavigation.org/)          | Routing and navigation for your React Native apps.                                                                                               |\n| [Format Duration](https://github.com/hypermodules/format-duration) | Convert a number in milliseconds to a standard duration string.                                                                                  |\n|    [RN-Placeholder](https://github.com/mfrachet/rn-placeholder)    | Display some placeholder stuff before rendering your text or media content in React Native.                                                      |\n\n## API's Used\n\n- [Deezer](https://developers.deezer.com/)\n- [Lyrics.OVH](https://api.lyrics.ovh)\n\n## Contributing\n\nDue to time constraints there are several features that I haven’t been able to develop yet. If you would like to develop your React Native skills and contribute any of the features below this would be hugely beneficial! :tada:\n\n- [x] [Debouncing or throttling](https://www.peterbe.com/plog/how-to-throttle-and-debounce-an-autocomplete-input-in-react) on search functionality.\n- [x] [PropTypes](https://reactjs.org/docs/typechecking-with-proptypes.html) on components.\n- [ ] Adding clear search button functionality on Android. This functionality [already exists on iOS](https://facebook.github.io/react-native/docs/textinput#clearbuttonmode).\n- [ ] [Animations](https://docs.expo.io/versions/latest/react-native/animations) would be a nice touch! Fading in the details screen background image would be priority.\n- [ ] Any general performance improvements.\n\nOther contributions and suggestions are always very welcome! [Contact me](https://www.stephenkempin.co.uk) if you wish to discuss anything.\n\n## Author\n\n[Stephen Kempin](https://www.stephenkempin.co.uk)\n\n[Lyrics King Project Github](https://github.com/SKempin/Lyrics-King-React-Native)\n\n## Google Play Store\n\nView my commercial apps on the [SK-UK Google Play Store](https://play.google.com/store/apps/developer?id=SK+-+UK)\n\n<a href='https://play.google.com/store/apps/developer?id=SK+-+UK&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='SK-UK Google Play Store' src='https://github.com/SKempin/Lyrics-King-React-Native/blob/master/_github/google-play.jpg' width='180px'></a>\n\n## Donate\n\nIf you like this project and wish to say to say thanks - I'm always open to a coffee!  :coffee:\n\n<a href=\"https://www.buymeacoffee.com/oru9CZh\" target=\"_blank\"><img src=\"https://www.buymeacoffee.com/assets/img/custom_images/black_img.png\" alt=\"Buy Me A Coffee\" width='180px' ></a>\n\n## License\n\n[MIT](https://github.com/SKempin/Lyrics-King-React-Native/blob/master/LICENSE)\n\nYou are welcome to use this however you wish within the MIT license, but please retain [my credentials](https://www.stephenkempin.co.uk/) and links back to [this repo](https://github.com/SKempin/Lyrics-King-React-Native).\n"
  },
  {
    "path": "app.json",
    "content": "{\n  \"expo\": {\n    \"name\": \"Lyrics King\",\n    \"description\": \"Lyrics King is a lyrics search app, fetching data from Deezer an Lyrics.ovh. Designed with Adobe XD and built with Expo, by Stephen Kempin. https://github.com/SKempin/Lyrics-King-React-Native\",\n    \"icon\": \"./assets/images/icon.png\",\n    \"slug\": \"lyrics-king\",\n    \"sdkVersion\": \"32.0.0\",\n    \"platforms\": [\"ios\", \"android\"],\n    \"githubUrl\":\"https://github.com/SKempin/Lyrics-King-React-Native\",\n    \"orientation\": \"portrait\",\n    \"privacy\": \"public\",\n    \"primaryColor\": \"#07CCBA\",\n    \"splash\": {\n      \"backgroundColor\": \"#191919 \",\n      \"image\": \"./assets/images/splash.png\",\n      \"resizeMode\": \"cover\"\n    },\n    \"extra\": {\n      \"appName\": \"Lyrics King\",\n      \"developerName\": \"SK-UK\",\n      \"googleAnalytics\": \"UA-131961084\",\n      \"social\": {\n        \"expoApp\": \"https://expo.io/@skempin/lyrics-king\",\n        \"github\": \"https://github.com/SKempin/Lyrics-King-React-Native\",\n        \"googlePlayStore\": \"https://play.google.com/store/apps/developer?id=SK+-+UK\",\n        \"iTunesStore\": \"https://www.stephenkempin.co.uk\",\n        \"portfolio\": \"https://www.stephenkempin.co.uk\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/Credits.js",
    "content": "import React from 'react';\nimport {\n  Text,\n  TouchableOpacity,\n  StyleSheet,\n  Linking,\n  Image\n} from 'react-native';\nimport Proptypes from 'prop-types';\nimport * as Expo from 'expo';\nimport { Analytics, Event } from 'expo-analytics';\nimport SK from '../assets/images/SK.png';\n\n// Config\nimport colours from '../config/colours';\n// Constants\nconst { portfolio } = Expo.Constants.manifest.extra.social;\nconst ID = Expo.Constants.manifest.extra.googleAnalytics;\n// GA tracking\nconst analytics = new Analytics(ID);\n\nconst Credits = props => (\n  <TouchableOpacity\n    style={styles.creditsContainer}\n    onPress={() => Linking.openURL(portfolio).then(() => {\n      Expo.Amplitude.logEvent(`BUTTON: Credits - ${props.screen} Screen`);\n      analytics.event(\n        new Event('Button', 'Tap', `Credits - ${props.screen} Screen`)\n      );\n    })\n    }\n  >\n    <Image source={SK} style={styles.creditsImage} />\n    <Text style={styles.creditsText}>\n      Design and development\n      {'\\n'}\n      {' '}\nby Stephen Kempin\n    </Text>\n  </TouchableOpacity>\n);\n\nCredits.propTypes = {\n  screen: Proptypes.string.isRequired\n};\n\nexport default Credits;\n\n//  Styles\nconst styles = StyleSheet.create({\n  creditsContainer: {\n    flexDirection: 'row',\n    alignItems: 'center'\n  },\n  creditsText: {\n    fontSize: 12,\n    color: colours.secondaryGrey,\n    textAlign: 'left',\n    paddingLeft: 20\n  },\n  creditsImage: {\n    width: 30,\n    height: 30,\n    opacity: 0.2,\n    alignSelf: 'flex-start'\n  }\n});\n"
  },
  {
    "path": "components/SocialButton.js",
    "content": "import React from 'react';\nimport {\n  Text,\n  TouchableOpacity,\n  StyleSheet,\n  Linking,\n  Image\n} from 'react-native';\nimport * as Expo from 'expo';\nimport PropTypes from 'prop-types';\n/* eslint-disable import/no-extraneous-dependencies */\nimport { Entypo, EvilIcons } from '@expo/vector-icons';\n/* eslint-enable import/no-extraneous-dependencies */\nimport { Analytics, Event } from 'expo-analytics';\nimport SK from '../assets/images/SK.png';\n// Config\nimport colours from '../config/colours';\n//  Helper functions\nimport handleShare from '../utils/shareHelper';\n// Constants\nconst { ...extra } = Expo.Constants.manifest.extra;\nconst ID = Expo.Constants.manifest.extra.googleAnalytics;\n\n// GA tracking\nconst analytics = new Analytics(ID);\n\nconst SocialButton = ({\n  label, url, screen, icon\n}) => (\n  <TouchableOpacity\n    style={styles.button}\n    onPress={() => (label !== 'Share'\n      ? Linking.openURL(url).then(() => {\n        Expo.Amplitude.logEvent(`BUTTON: ${label}`);\n        analytics.event(new Event('Button', 'Tap', `${label}`));\n      })\n      : handleShare(\n        `Check out ${extra.appName} on Expo today!`,\n        `${extra.social.expoApp}`,\n        `${extra.appName}`,\n        `${screen}`\n      ))\n    }\n  >\n    {icon ? (\n      <Entypo name={icon} size={20} style={styles.icon_left} />\n    ) : (\n      <Image source={SK} style={styles.icon_sk} />\n    )}\n    <Text style={styles.label}>\n      {label}\n    </Text>\n    <EvilIcons name=\"chevron-right\" size={34} style={styles.icon_right} />\n  </TouchableOpacity>\n);\n\nSocialButton.propTypes = {\n  icon: PropTypes.string,\n  label: PropTypes.string.isRequired,\n  url: PropTypes.string,\n  screen: PropTypes.string.isRequired\n};\n\nSocialButton.defaultProps = {\n  icon: '',\n  url: ''\n};\n\nexport default SocialButton;\n\n//  Styles\nconst styles = StyleSheet.create({\n  button: {\n    padding: 10,\n    backgroundColor: colours.tertiaryBlack,\n    flex: 1,\n    flexDirection: 'row',\n    flexWrap: 'nowrap',\n    alignItems: 'center',\n    justifyContent: 'flex-start',\n    marginBottom: 10\n  },\n  icon_left: {\n    marginRight: 15,\n    color: colours.primaryGrey\n  },\n  icon_sk: {\n    marginRight: 15,\n    opacity: 0.5,\n    width: 22,\n    height: 22\n  },\n  label: {\n    flex: 1,\n    color: colours.primaryGrey\n  },\n  icon_right: {\n    color: colours.primaryGrey,\n    justifyContent: 'flex-end',\n    opacity: 0.4\n  }\n});\n"
  },
  {
    "path": "components/Suggestions.js",
    "content": "import React from 'react';\nimport {\n  Image,\n  FlatList,\n  Text,\n  TouchableOpacity,\n  Keyboard,\n  StyleSheet,\n  View\n} from 'react-native';\nimport PropTypes from 'prop-types';\n/* eslint-disable import/no-extraneous-dependencies */\nimport { EvilIcons } from '@expo/vector-icons';\n/* eslint-enable import/no-extraneous-dependencies */\n// Config\nimport colours from '../config/colours';\n\nconst Suggestions = ({ results, navigation }) => (\n  <FlatList\n    onScrollBeginDrag={Keyboard.dismiss}\n    data={results}\n    styles={{ alignSelf: 'stretch' }}\n    renderItem={({ item }) => (\n      <TouchableOpacity\n        style={styles.suggestionItem}\n        onPress={() => navigation.navigate('Details', { ...item })}\n      >\n        <Image\n          style={styles.image}\n          source={{ uri: item.artist.picture_medium }}\n        />\n        <View numberOfLines={1} style={styles.detailsContainer}>\n          <Text numberOfLines={1} style={styles.songTitle}>\n            {item.title_short}\n          </Text>\n          <Text numberOfLines={1} style={styles.artistDetails}>\n            {item.artist.name}\n          </Text>\n          <Text numberOfLines={1} style={styles.artistDetails}>\n            {item.album.title}\n          </Text>\n        </View>\n        <EvilIcons name=\"chevron-right\" size={54} color=\"#333\" />\n      </TouchableOpacity>\n    )}\n    keyExtractor={(item, index) => index.toString()}\n  />\n);\n\nSuggestions.propTypes = {\n  results: PropTypes.array.isRequired,\n  navigation: PropTypes.object.isRequired\n};\n\nexport default Suggestions;\n\n//  Styles\nconst styles = StyleSheet.create({\n  suggestionItem: {\n    flex: 1,\n    flexDirection: 'row',\n    flexWrap: 'nowrap',\n    backgroundColor: colours.tertiaryBlack,\n    elevation: 1,\n    justifyContent: 'flex-start',\n    alignItems: 'center',\n    paddingTop: 12,\n    paddingBottom: 12,\n    paddingLeft: 18,\n    paddingRight: 12,\n    marginLeft: 14,\n    marginRight: 14,\n    marginTop: 0,\n    marginBottom: 10\n  },\n  image: {\n    width: 66,\n    height: 66,\n    borderRadius: 66 / 2,\n    alignSelf: 'center',\n    borderColor: colours.primaryWhite,\n    borderWidth: 2,\n    marginRight: 17,\n    flex: 0\n  },\n  detailsContainer: {\n    width: 145,\n    marginRight: 20\n  },\n  songTitle: {\n    color: 'white',\n    paddingBottom: 2\n  },\n  artistDetails: {\n    color: colours.primaryGrey,\n    paddingBottom: 2\n  }\n});\n"
  },
  {
    "path": "config/colours.js",
    "content": "// Colours\nconst colours = {\n  primaryBlack: '#101010',\n  secondaryBlack: '#1D1D1D',\n  tertiaryBlack: '#141414',\n  highlightBlack: '#0B0B0B',\n  primaryWhite: '#fff',\n  primaryTeal: '#07CCBA',\n  primaryGrey: '#AAAAAA',\n  secondaryGrey: '#3E3E3E'\n};\nexport default colours;\n"
  },
  {
    "path": "config/router.js",
    "content": "import React from 'react';\nimport {\n  createDrawerNavigator,\n  createStackNavigator,\n  DrawerItems\n} from 'react-navigation';\nimport * as Expo from 'expo';\n/* eslint-disable import/no-extraneous-dependencies */\nimport { Ionicons } from '@expo/vector-icons';\n/* eslint-enable import/no-extraneous-dependencies */\nimport {\n  StyleSheet,\n  Image,\n  ScrollView,\n  SafeAreaView,\n  View\n} from 'react-native';\nimport Logo from '../assets/images/lk-logo.png';\n\n//  Components\nimport SocialButton from '../components/SocialButton';\n//  Helper functions\nimport handleShare from '../utils/shareHelper';\n// Config\nimport colours from './colours';\n// Constants\nimport { socialLinks } from '../lib/constants';\n\n//  Screens\nimport SearchScreen from '../screens/SearchScreen';\nimport DetailsScreen from '../screens/DetailsScreen';\nimport AboutScreen from '../screens/AboutScreen';\n\nconst { ...extra } = Expo.Constants.manifest.extra;\n\n// Main stack\nexport const MainStack = createStackNavigator({\n  Search: {\n    screen: SearchScreen,\n    navigationOptions: ({ navigation }) => ({\n      title: null,\n      headerTransparent: true,\n      headerLeft: (\n        <Ionicons\n          name=\"md-menu\"\n          size={26}\n          style={{ marginLeft: 10, padding: 10 }}\n          color={colours.secondaryGrey}\n          onPress={() => navigation.openDrawer()}\n        />\n      )\n    })\n  },\n  Details: {\n    screen: DetailsScreen,\n    navigationOptions: ({ navigation }) => ({\n      headerStyle: {\n        borderBottomWidth: 0,\n        backgroundColor: 'rgba(0,0,0,0.2)',\n        elevation: 0\n      },\n      headerTransparent: true,\n      headerTintColor: 'rgba(255,255,255,0.7)',\n      headerRight: (\n        <Ionicons\n          name=\"md-share\"\n          title=\"Share\"\n          size={24}\n          style={{ marginRight: 10, padding: 10 }}\n          color=\"rgba(255,255,255,0.7)\"\n          onPress={() => handleShare(\n            `Check out lyrics for ${navigation.state.params.title} by ${\n              navigation.state.params.artist.name\n            } on ${extra.appName}!`,\n            `${extra.social.expoApp}`,\n            `${extra.appName}`,\n            'Details'\n          )\n          }\n        />\n      )\n    })\n  }\n});\n\n// About stack\nexport const AboutStack = createStackNavigator({\n  About: {\n    screen: AboutScreen,\n    navigationOptions: ({ navigation }) => ({\n      title: null,\n      headerTransparent: true,\n      headerLeft: (\n        <Ionicons\n          name=\"md-menu\"\n          size={26}\n          style={{ marginLeft: 10, padding: 10 }}\n          color={colours.secondaryGrey}\n          onPress={() => navigation.openDrawer()}\n        />\n      )\n    })\n  }\n});\n\n// =====================================================\n\n//  Side drawer\nexport const RootStack = createDrawerNavigator(\n  { Search: { screen: MainStack }, About: { screen: AboutStack } },\n  {\n    contentComponent: props => (\n      <ScrollView style={{ backgroundColor: colours.primaryBlack }}>\n        <SafeAreaView\n          style={styles.container}\n          forceInset={{ top: 'always', horizontal: 'never' }}\n        >\n          <Image style={styles.logo} source={Logo} />\n\n          <DrawerItems\n            {...props}\n            activeTintColor={colours.primaryWhite}\n            activeBackgroundColor={colours.highlightBlack}\n            inactiveTintColor={colours.secondaryGrey}\n            itemStyle={styles.itemStyle}\n          />\n          <View style={styles.socialLinksContainer}>\n            {socialLinks.map((socialLink, index) => (\n              <SocialButton\n                key={socialLink.label + index}\n                icon={socialLink.icon}\n                label={socialLink.label}\n                url={socialLink.url}\n                screen=\"About\"\n              />\n            ))}\n          </View>\n        </SafeAreaView>\n      </ScrollView>\n    )\n  }\n);\n\n//  Styles\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    marginTop: 50\n  },\n  logo: {\n    width: 150,\n    height: 150,\n    alignSelf: 'center',\n    marginBottom: 30\n  },\n  itemStyle: {\n    borderLeftWidth: 3,\n    borderLeftColor: colours.primaryTeal\n  },\n  socialLinksContainer: {\n    marginLeft: 20,\n    marginRight: 20,\n    marginTop: 45,\n    fontSize: 4,\n    paddingTop: 30,\n    borderTopColor: colours.secondaryGrey,\n    borderTopWidth: 1\n  }\n});\n"
  },
  {
    "path": "lib/constants.js",
    "content": "import * as Expo from 'expo';\n\nconst { ...social } = Expo.Constants.manifest.extra.social;\n\n// Expo constants\nexport const { expoVersion } = Expo.Constants;\n// export const iOSBuild = Constants.platform.ios.buildNumber;\nexport const { manifest } = Expo.Constants;\n// functions\nexport const getCurrentYear = new Date().getFullYear();\n// Social Links\nexport const socialLinks = [\n  {\n    icon: 'google-play',\n    label: 'SK-UK Play Store',\n    url: social.googlePlayStore\n  },\n  { icon: 'app-store', label: 'SK-UK iTunes Store', url: social.iTunesStore },\n  { icon: 'github', label: 'Github Project', url: social.github },\n  { icon: '', label: 'SK Portfolio', url: social.portfolio }\n];\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"lyrics-king\",\n  \"version\": \"1.0.3\",\n  \"private\": true,\n  \"author\": \"Stephen Kempin (https://stephenkempin.co.uk/)\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"expo\",\n    \"react-native\",\n    \"react\",\n    \"es6\",\n    \"android\",\n    \"ios\"\n  ],\n  \"devDependencies\": {\n    \"babel-eslint\": \"^10.0.1\",\n    \"eslint\": \"^5.3.0\",\n    \"eslint-config-airbnb\": \"^17.1.0\",\n    \"eslint-plugin-import\": \"^2.16.0\",\n    \"eslint-plugin-jest\": \"^22.2.2\",\n    \"eslint-plugin-jsx-a11y\": \"^6.2.0\",\n    \"eslint-plugin-react\": \"^7.12.4\",\n    \"jest-expo\": \"^32.0.0\",\n    \"react-test-renderer\": \"16.3.1\"\n  },\n  \"main\": \"./node_modules/expo/AppEntry.js\",\n  \"scripts\": {\n    \"start\": \"react-native-scripts start\",\n    \"eject\": \"react-native-scripts eject\",\n    \"android\": \"react-native-scripts android\",\n    \"ios\": \"react-native-scripts ios\",\n    \"lint\": \"./node_modules/.bin/eslint .\",\n    \"test\": \"jest\"\n  },\n  \"jest\": {\n    \"preset\": \"jest-expo\"\n  },\n  \"dependencies\": {\n    \"expo\": \"^32.0.0\",\n    \"expo-analytics\": \"^1.0.7\",\n    \"format-duration\": \"^1.3.1\",\n    \"prop-types\": \"^15.6.2\",\n    \"react\": \"16.14.0\",\n    \"react-native\": \"https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz\",\n    \"react-navigation\": \"^3.0.9\",\n    \"rn-placeholder\": \"^1.3.0\",\n    \"sentry-expo\": \"^1.11.0\",\n    \"throttle-debounce\": \"^2.1.0\"\n  }\n}\n"
  },
  {
    "path": "screens/AboutScreen.js",
    "content": "import React from 'react';\nimport {\n  Text,\n  View,\n  StyleSheet,\n  ScrollView,\n  Image,\n  SafeAreaView,\n  StatusBar\n} from 'react-native';\nimport * as Expo from 'expo';\n// Config\nimport { Analytics, ScreenHit } from 'expo-analytics';\nimport colours from '../config/colours';\n//  Components\nimport SocialButton from '../components/SocialButton';\nimport { getCurrentYear, socialLinks, manifest } from '../lib/constants';\n\nimport SK_LOGO from '../assets/images/lk-logo.png';\n// Constants\nconst { ...meta } = Expo.Constants.manifest;\n\n// GA tracking\nconst ID = Expo.Constants.manifest.extra.googleAnalytics;\nconst analytics = new Analytics(ID);\n\nexport default class AboutScreen extends React.Component {\n  componentDidMount() {\n    Expo.Amplitude.logEvent('SCREEN: About');\n    analytics.hit(new ScreenHit('SCREEN: About'));\n  }\n\n  render() {\n    return (\n      <SafeAreaView style={styles.safeView}>\n        <StatusBar barStyle=\"light-content\" />\n        <ScrollView style={styles.container}>\n          <View style={{ flex: 1 }}>\n            <Text style={styles.headingText}>\nSocial\n            </Text>\n\n            {socialLinks.map((socialLink, index) => (\n              <SocialButton\n                key={socialLink.label + index}\n                icon={socialLink.icon}\n                label={socialLink.label}\n                url={socialLink.url}\n                screen=\"About Screen\"\n              />\n            ))}\n\n            <Text style={styles.headingText}>\nShare\n            </Text>\n            <SocialButton icon=\"share\" label=\"Share\" screen=\"About\" />\n\n            <Text style={styles.headingText}>\nDonate\n            </Text>\n            <SocialButton\n              icon=\"heart\"\n              label=\"Buy me a coffee to say thanks!\"\n              url=\"https://www.buymeacoffee.com/oru9CZh\"\n              screen=\"About Screen\"\n            />\n\n            <Text style={styles.headingText}>\nApp Info\n            </Text>\n            <Image style={styles.logo} source={SK_LOGO} />\n            <View style={styles.detailsContainer}>\n              <Text style={styles.detailsContainerText}>\n                {`${meta.extra.appName}: ${manifest.version}`}\n              </Text>\n              <Text style={styles.detailsContainerText}>\n                ©\n                {' '}\n                {getCurrentYear}\n                {' '}\n                {meta.extra.developerName}\n. Design &\n                development by\n                {' '}\n                {meta.extra.developerName}\n.\n              </Text>\n              <Text style={styles.detailsContainerText}>\n                Expo SDK:\n                {' '}\n                {meta.sdkVersion}\n              </Text>\n              <Text style={styles.detailsContainerText}>\n                Released under MIT licence.\n              </Text>\n            </View>\n          </View>\n        </ScrollView>\n      </SafeAreaView>\n    );\n  }\n}\n\n//  Styles\nconst styles = StyleSheet.create({\n  safeView: {\n    flex: 1,\n    backgroundColor: colours.primaryBlack\n  },\n  container: {\n    flex: 1,\n    backgroundColor: colours.primaryBlacks,\n    flexDirection: 'column',\n    paddingLeft: 30,\n    paddingRight: 30,\n    paddingTop: 40\n  },\n\n  headingText: {\n    color: colours.primaryTeal,\n    fontSize: 20,\n    marginBottom: 20,\n    marginTop: 30,\n    fontWeight: '300'\n  },\n  detailsContainer: {\n    paddingBottom: 20\n  },\n  detailsContainerText: {\n    color: colours.primaryGrey,\n    fontSize: 12,\n    paddingBottom: 6\n  },\n  heading: {\n    paddingTop: 50,\n    paddingBottom: 15,\n    backgroundColor: colours.primaryBlack\n  },\n  logo: {\n    width: 76,\n    height: 76,\n    marginBottom: 20\n  }\n});\n"
  },
  {
    "path": "screens/DetailsScreen.js",
    "content": "import React from 'react';\nimport {\n  StyleSheet,\n  Text,\n  Image,\n  View,\n  ScrollView,\n  ImageBackground\n} from 'react-native';\nimport * as Expo from 'expo';\nimport PropTypes from 'prop-types';\nimport format from 'format-duration';\nimport Placeholder from 'rn-placeholder';\nimport { Analytics, ScreenHit } from 'expo-analytics';\n// Config\nimport colours from '../config/colours';\n//  Components\nimport Credits from '../components/Credits';\n\n// GA tracking\nconst ID = Expo.Constants.manifest.extra.googleAnalytics;\nconst analytics = new Analytics(ID);\n\nexport default class DetailsScreen extends React.Component {\n  static get propTypes() {\n    return {\n      navigation: PropTypes.object.isRequired\n    };\n  }\n\n  constructor(props) {\n    super(props);\n    this.state = { lyrics: null, /* err: null, */ isReady: null };\n  }\n\n  async componentDidMount() {\n    const {\n      navigation: {\n        state: {\n          params: { title, artist }\n        }\n      }\n    } = this.props;\n    Expo.Amplitude.logEvent(`SCREEN - Details: ${title} by ${artist.name}`);\n    analytics.hit(\n      new ScreenHit(`SCREEN - Details: ${title} by ${artist.name}`)\n    );\n\n    const lyricsQuery = `${artist.name}/${title}`;\n    this.getLyrics(lyricsQuery);\n  }\n\n  // fix issue #5 - setting state on unmounted component\n  componentWillUnmount() {\n    this.isCancelled = true;\n  }\n\n  getLyrics = async (lyricsQuery) => {\n    try {\n      const res = await fetch(`https://api.lyrics.ovh/v1/${lyricsQuery}`);\n      const response = await res.json();\n      if (!this.isCancelled) this.setState({ lyrics: response.lyrics, isReady: true });\n    } catch (e) {\n      console.log(e); // this.setState({ err: e.message });\n    }\n  };\n\n  displayLyrics() {\n    const { lyrics, isReady } = this.state;\n    if (!lyrics) {\n      return (\n        <Text style={{ color: colours.primaryWhite }}>\n          Sorry, no lyrics can be found for this song.\n        </Text>\n      );\n    }\n    return (\n      <Placeholder.Paragraph\n        lineNumber={4}\n        textSize={12}\n        lineSpacing={7}\n        color=\"#242424\"\n        width=\"60%\"\n        lastLineWidth=\"80%\"\n        firstLineWidth=\"30%\"\n        onReady={isReady}\n      >\n        <Text style={styles.lyrics}>\n          {lyrics}\n        </Text>\n      </Placeholder.Paragraph>\n    );\n  }\n\n  render() {\n    const {\n      navigation: {\n        state: {\n          params: {\n            title, artist, album, duration\n          }\n        }\n      }\n    } = this.props;\n\n    return (\n      <ScrollView style={styles.container}>\n        <View style={{ flex: 1 }}>\n          <ImageBackground\n            source={{ uri: artist.picture_xl }}\n            style={styles.backgroundImage}\n          >\n            <Expo.LinearGradient\n              colors={['transparent', colours.primaryBlack]}\n              locations={[0.4, 1.2]}\n              style={styles.gradient}\n            />\n            <View\n              style={{\n                flexDirection: 'column',\n                alignSelf: 'flex-end',\n                paddingBottom: 40,\n                paddingLeft: 19\n              }}\n            >\n              <Text style={styles.artistHeading}>\n                {artist.name}\n              </Text>\n              <Text style={styles.songHeading}>\n                {title}\n              </Text>\n            </View>\n          </ImageBackground>\n        </View>\n        <View style={{ flex: 1, paddingLeft: 19, paddingRight: 19 }}>\n          <View\n            style={{\n              flex: 1,\n              flexDirection: 'row',\n              justifyContent: 'flex-start',\n              marginBottom: 30\n            }}\n          >\n            <Image\n              style={styles.albumImage}\n              source={{ uri: album.cover_medium }}\n            />\n            <View\n              style={{\n                flexDirection: 'column',\n                flex: 1,\n                alignSelf: 'center',\n                paddingRight: 10\n              }}\n            >\n              <Text style={styles.detailsHeading}>\nAlbum\n              </Text>\n              <Text style={styles.details}>\n                {album.title}\n              </Text>\n              <Text style={styles.detailsHeading}>\nDuration\n              </Text>\n              <Text style={styles.details}>\n                {format(duration * 1000)}\n              </Text>\n            </View>\n          </View>\n          {this.displayLyrics()}\n        </View>\n        <View style={styles.creditsContainer}>\n          <Credits screen=\"Details\" />\n        </View>\n      </ScrollView>\n    );\n  }\n}\n\n//  Styles\nconst styles = StyleSheet.create({\n  container: {\n    backgroundColor: colours.primaryBlack,\n    flex: 1\n  },\n  backgroundImage: { flex: 1, minHeight: 360, flexDirection: 'row' },\n  gradient: {\n    backgroundColor: 'transparent',\n    position: 'absolute',\n    top: 0,\n    bottom: 0,\n    left: 0,\n    right: 0\n  },\n  artistHeading: {\n    color: colours.primaryWhite,\n    fontSize: 35,\n    lineHeight: 35,\n    fontWeight: '300',\n    paddingBottom: 7,\n    shadowOpacity: 0.6,\n    shadowRadius: 3,\n    shadowOffset: {\n      height: 0,\n      width: 0\n    }\n  },\n  songHeading: {\n    color: colours.primaryWhite,\n    fontSize: 45,\n    lineHeight: 45,\n\n    fontWeight: 'bold',\n    paddingBottom: 0,\n    shadowOpacity: 0.6,\n    shadowRadius: 3,\n    shadowOffset: {\n      height: 0,\n      width: 0\n    }\n  },\n  albumImage: {\n    width: 130,\n    height: 130,\n    borderRadius: 130 / 2,\n    borderWidth: 3,\n    borderColor: colours.primaryWhite,\n    marginRight: 25\n  },\n  detailsHeading: { color: colours.primaryGrey, marginBottom: 3 },\n  details: {\n    color: colours.primaryWhite,\n    fontWeight: 'bold',\n    marginBottom: 15,\n    fontSize: 16\n  },\n  lyrics: {\n    color: colours.primaryWhite,\n    lineHeight: 22,\n    paddingBottom: 20\n  },\n  creditsContainer: {\n    flex: 1,\n    alignSelf: 'center',\n    paddingTop: 40,\n    paddingBottom: 30\n  }\n});\n"
  },
  {
    "path": "screens/SearchScreen.js",
    "content": "import React from 'react';\nimport {\n  StyleSheet,\n  TextInput,\n  View,\n  Image,\n  Keyboard,\n  SafeAreaView,\n  StatusBar,\n  TouchableWithoutFeedback\n} from 'react-native';\nimport * as Expo from 'expo';\nimport PropTypes from 'prop-types';\n/* eslint-disable import/no-extraneous-dependencies */\nimport { EvilIcons } from '@expo/vector-icons';\n/* eslint-enable import/no-extraneous-dependencies */\nimport { Analytics, ScreenHit } from 'expo-analytics';\n// search throlle and debounce\nimport { throttle, debounce } from 'throttle-debounce';\n\nimport LK_LOGO from '../assets/images/lk-logo.png';\nimport SK from '../assets/images/SK.png';\n\n// Config\nimport colours from '../config/colours';\n//  Components\nimport Suggestions from '../components/Suggestions';\nimport Credits from '../components/Credits';\n\n// Cache images\nfunction cacheImages(images) {\n  return images.map((image) => {\n    if (typeof image === 'string') {\n      return Image.prefetch(image);\n    }\n    return Expo.Asset.fromModule(image).downloadAsync();\n  });\n}\n\n// GA tracking\nconst ID = Expo.Constants.manifest.extra.googleAnalytics;\nconst analytics = new Analytics(ID);\n\nexport default class SearchScreen extends React.Component {\n  static get propTypes() {\n    return {\n      navigation: PropTypes.object.isRequired\n    };\n  }\n\n  constructor(props) {\n    super(props);\n    this.state = { results: [], text: null, showLogo: true };\n    this.throttleSearch = throttle(400, this.getInfo);\n    this.debounceSearch = debounce(700, this.getInfo);\n    this.cache = {}; // caching autocomplete results\n  }\n\n  componentDidMount() {\n    Expo.Amplitude.initialize('6460727d017e832e2083e13916c7c9e5');\n    Expo.Amplitude.logEvent('SCREEN: Search');\n    analytics.hit(new ScreenHit('SCREEN: Search'));\n  }\n\n  componentDidUpdate(prevProps, prevState) {\n    const { text } = this.state;\n    if (text !== prevState.text) {\n      if (text.length >= 1) {\n        if (text.length < 5 || text.endsWith(' ')) this.throttleSearch(text);\n        else this.debounceSearch(text);\n      } else {\n        this.submitAndClear();\n      }\n    }\n  }\n\n  // Load logos\n  _loadAssetsAsync = async () => {\n    const imageAssets = cacheImages([LK_LOGO, SK]);\n    await Promise.all([...imageAssets]);\n  };\n\n  getInfo = () => {\n    const { text } = this.state;\n    const url = `https://api.deezer.com/search?q=track:\"${text}\"&limit=20&order=RANKING?strict=on`;\n\n    const cached = this.cache[url];\n    if (cached) {\n      this.setState({ results: cached, showLogo: false });\n      return;\n    }\n\n    fetch(url)\n      .then(response => response.json())\n      .then((data) => {\n        this.cache[url] = data.data;\n        this.setState({ results: data.data, showLogo: false });\n      });\n  };\n\n  submitAndClear = () => {\n    this.setState({ text: '', showLogo: true });\n    Keyboard.dismiss();\n  };\n\n  render() {\n    const {\n      isReady, showLogo, text, results\n    } = this.state;\n    const { navigation } = this.props;\n    if (!isReady) {\n      return (\n        <Expo.AppLoading\n          startAsync={this._loadAssetsAsync}\n          onFinish={() => this.setState({ isReady: true })}\n          onError={console.warn}\n        />\n      );\n    }\n    return (\n      <SafeAreaView style={styles.safeView}>\n        <StatusBar barStyle=\"light-content\" />\n        <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>\n          <View style={styles.container}>\n            {showLogo && <Image style={styles.logo} source={LK_LOGO} />}\n\n            <View style={{ flex: 1, alignItems: 'center' }}>\n              <View style={styles.searchContainer}>\n                <EvilIcons name=\"search\" size={30} color=\"#07CCBA\" />\n\n                <TextInput\n                  style={styles.TextInput}\n                  onChangeText={changedText => this.setState({ text: changedText })\n                  }\n                  value={text}\n                  placeholder=\"Search song\"\n                  placeholderTextColor=\"#fff\"\n                  clearButtonMode=\"always\"\n                />\n              </View>\n\n              {results.length > 0 && text.length > 0 && (\n                <Suggestions\n                  style={styles.Suggestions}\n                  results={results}\n                  navigation={navigation}\n                />\n              )}\n            </View>\n            {showLogo && <Credits screen=\"Search\" />}\n          </View>\n        </TouchableWithoutFeedback>\n      </SafeAreaView>\n    );\n  }\n}\n\n//  Styles\nconst styles = StyleSheet.create({\n  safeView: {\n    flex: 1,\n    backgroundColor: colours.primaryBlack\n  },\n  container: {\n    flex: 1,\n    backgroundColor: colours.primaryBlack,\n    alignItems: 'center',\n    justifyContent: 'center',\n    paddingTop: 40,\n    paddingBottom: 30\n  },\n  logo: {\n    width: 160,\n    height: 160,\n    marginBottom: 60,\n    marginTop: 40\n  },\n  searchContainer: {\n    flexDirection: 'row',\n    flexWrap: 'nowrap',\n    width: 280,\n    paddingTop: 18,\n    paddingBottom: 18,\n    paddingRight: 20,\n    paddingLeft: 10,\n    marginBottom: 20,\n    backgroundColor: colours.highlightBlack,\n    alignItems: 'center',\n    justifyContent: 'center'\n  },\n  TextInput: {\n    flex: 1,\n    fontSize: 16,\n    textAlign: 'center',\n    alignItems: 'center',\n    flexWrap: 'nowrap',\n    color: colours.primaryWhite\n  },\n  Suggestions: {\n    flex: 1,\n    alignItems: 'center',\n\n    color: colours.primaryWhite\n  },\n  creditsContainer: {\n    flexDirection: 'row',\n    width: 170\n  },\n  creditsText: {\n    fontSize: 12,\n    color: colours.secondaryGrey,\n    textAlign: 'left',\n    paddingLeft: 20\n  },\n  creditsImage: {\n    width: 30,\n    height: 30,\n    opacity: 0.2,\n    alignSelf: 'flex-start'\n  }\n});\n"
  },
  {
    "path": "utils/shareHelper.js",
    "content": "import { Share } from 'react-native';\nimport * as Expo from 'expo';\nimport { Analytics, Event } from 'expo-analytics';\n\n// GA tracking\nconst ID = Expo.Constants.manifest.extra.googleAnalytics;\nconst analytics = new Analytics(ID);\n\nconst handleShare = (message, url, title, screen) => {\n  Share.share(\n    {\n      message,\n      url,\n      title\n    },\n    {\n      // Android only:\n      dialogTitle: `Share ${title}`, // iOS only:\n      excludedActivityTypes: ['com.apple.UIKit.activity.PostToTwitter']\n    }\n  ).then(() => {\n    Expo.Amplitude.logEvent(`BUTTON: Share - ${screen} Screen`);\n    analytics.event(new Event('Button', 'Tap', `Share - ${screen} Screen`));\n  });\n};\n\nexport default handleShare;\n"
  }
]