├── .watchmanconfig
├── .gitattributes
├── .babelrc
├── app.json
├── ios
├── hnews
│ ├── LaunchImage.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-57x57@1x.png
│ │ │ ├── Icon-App-57x57@2x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.h
│ ├── main.m
│ ├── AppDelegate.m
│ └── Info.plist
├── LaunchScreen.xib
├── Launch Screen.storyboard
└── hnews.xcodeproj
│ ├── xcshareddata
│ └── xcschemes
│ │ ├── hnews.xcscheme
│ │ └── hnews-tvOS.xcscheme
│ └── project.pbxproj
├── index.ios.js
├── .buckconfig
├── js
├── index.js
├── helpers
│ ├── fetch-builder.js
│ ├── get-title.js
│ ├── story-helpers.js
│ └── comment-helpers.js
├── redux
│ ├── reducers
│ │ ├── index.js
│ │ ├── settings.js
│ │ ├── saved-stories.js
│ │ ├── thread.js
│ │ └── stories.js
│ ├── action-creators
│ │ ├── fetch-builder.js
│ │ ├── settings.js
│ │ ├── thread.js
│ │ └── stories.js
│ └── constants.js
├── components
│ ├── generic
│ │ ├── loader.js
│ │ ├── error.js
│ │ ├── splash.js
│ │ ├── list.js
│ │ ├── text.js
│ │ ├── link.js
│ │ └── button.js
│ ├── thread
│ │ ├── no-comments.js
│ │ ├── load-replies.js
│ │ ├── comments.js
│ │ ├── collapsible-comment.js
│ │ ├── head.js
│ │ └── comment.js
│ ├── stories
│ │ ├── no-saved-stories.js
│ │ ├── topic-filter.js
│ │ └── story.js
│ ├── saved-stories.js
│ ├── stories.js
│ ├── thread.js
│ ├── status-bar.js
│ └── tab-layout.js
├── store.js
├── connected
│ └── thread.connected.js
├── layout.js
└── app.container.js
├── .eslintrc
├── README.md
├── .gitignore
├── pre-.commit.sh
├── package.json
└── .flowconfig
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"]
3 | }
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hnews",
3 | "displayName": "hnews"
4 | }
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/index.ios.js:
--------------------------------------------------------------------------------
1 | import { AppRegistry } from 'react-native'
2 | import App from './js'
3 |
4 | AppRegistry.registerComponent('hnews', () => App)
5 |
--------------------------------------------------------------------------------
/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neb-b/hackernews/HEAD/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/js/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Provider } from "react-redux";
3 | import store from "./store";
4 | import App from "./app.container";
5 |
6 | const HackerNews = () => (
7 |
8 |
9 |
10 | );
11 |
12 | export default HackerNews;
13 |
--------------------------------------------------------------------------------
/js/helpers/fetch-builder.js:
--------------------------------------------------------------------------------
1 | export const postJson = (url, commentIds) =>
2 | fetch(url, {
3 | method: "POST",
4 | headers: {
5 | Accept: "application/json",
6 | "Content-Type": "application/json"
7 | },
8 | body: JSON.stringify({ commentIds })
9 | }).then(res => res.json());
10 |
--------------------------------------------------------------------------------
/js/helpers/get-title.js:
--------------------------------------------------------------------------------
1 | export const titles = {
2 | topstories: "Top Stories",
3 | beststories: "Best Stories",
4 | jobstories: "Jobs",
5 | askstories: "AskHN",
6 | showstories: "ShowHN"
7 | };
8 |
9 | export default function getTitle(topicSelected) {
10 | return titles[topicSelected];
11 | }
12 |
--------------------------------------------------------------------------------
/js/redux/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from "redux";
2 | import settings from "./settings";
3 | import stories from "./stories";
4 | import savedStories from "./saved-stories";
5 | import thread from "./thread";
6 |
7 | export default combineReducers({
8 | settings,
9 | stories,
10 | savedStories,
11 | thread
12 | });
13 |
--------------------------------------------------------------------------------
/js/components/generic/loader.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, ActivityIndicator, StyleSheet } from "react-native";
3 |
4 | const Loader = () => (
5 |
6 |
7 |
8 | );
9 |
10 | const styles = StyleSheet.create({
11 | loader: {
12 | marginTop: 100
13 | }
14 | });
15 |
16 | export default Loader;
17 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 7,
4 | "sourceType": "module",
5 | "ecmaFeatures": {
6 | "jsx": true,
7 | }
8 | },
9 | "plugins": [
10 | "react",
11 | "react-native"
12 | ],
13 | "extends": ["eslint:recommended", "plugin:react/recommended"],
14 | "rules": {
15 | "react-native/no-unused-styles": 2
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/js/helpers/story-helpers.js:
--------------------------------------------------------------------------------
1 | import moment from "moment";
2 |
3 | export const formatUrl = url => {
4 | const trimUrl = (str, start) => {
5 | return str.split("").slice(start, str.length).join("").split("/")[0];
6 | };
7 |
8 | if (url) {
9 | return url.match("http://") ? trimUrl(url, 7) : trimUrl(url, 8);
10 | }
11 |
12 | return null;
13 | };
14 |
15 | export const fromNow = time => {
16 | return moment(time * 1000).fromNow();
17 | };
18 |
--------------------------------------------------------------------------------
/js/components/thread/no-comments.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, StyleSheet } from "react-native";
3 | import Text from "../generic/text";
4 |
5 | const NoComments = () => (
6 |
7 | No comments
8 |
9 | );
10 |
11 | const styles = StyleSheet.create({
12 | container: {
13 | justifyContent: "center",
14 | alignItems: "center",
15 | height: 300
16 | }
17 | });
18 |
19 | export default NoComments;
20 |
--------------------------------------------------------------------------------
/ios/hnews/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (nonatomic, strong) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/js/store.js:
--------------------------------------------------------------------------------
1 | import { applyMiddleware, createStore } from "redux";
2 | import thunk from "redux-thunk";
3 | import promise from "redux-promise";
4 | import { createLogger } from "redux-logger";
5 | import reducers from "./redux/reducers";
6 |
7 | const isDev = __DEV__; // eslint-disable-line no-undef
8 | const logger = createLogger();
9 |
10 | const middleware = isDev
11 | ? applyMiddleware(thunk, promise, logger)
12 | : applyMiddleware(thunk);
13 |
14 | const store = createStore(reducers, middleware);
15 |
16 | export default store;
17 |
--------------------------------------------------------------------------------
/ios/hnews/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[]) {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### hNews
2 |
3 | A Hacker News reader built with React Native
4 |
5 | Checkout the Node.js server [here](https://github.com/seanyesmunt/hackernews-server)
6 |
7 | ~~Download the iOS app here~~ (Currently trying to get v2 published.)
8 |
9 |
10 | ### Installation
11 |
12 | 1. Clone this repo
13 |
14 | 2. `npm i`
15 |
16 | 3. `react-native link`
17 |
18 | 4. `react-native run-ios`
19 |
20 |
21 | ### Contributing
22 |
23 | If you find an issue, feel free to let me know by opening an issue or making a pull request.
24 |
25 | You can also talk to me on Twitter [@seanyesmunt](https://twitter.com/seanyesmunt)
26 |
--------------------------------------------------------------------------------
/js/redux/action-creators/fetch-builder.js:
--------------------------------------------------------------------------------
1 | import { ROOT_URL } from "../constants";
2 |
3 | export const getJson = (endpoint, topic, query = "") => {
4 | let url = `${ROOT_URL}/${endpoint}`;
5 | url += topic ? `/${topic}` : "";
6 | url += query ? `?${query}` : "";
7 |
8 | return fetch(url, {
9 | method: "GET",
10 | headers: {
11 | Accept: "application/json",
12 | "Content-Type": "application/json"
13 | }
14 | })
15 | .then(res => res.json())
16 | .then(storyObj => {
17 | // TODO: only send stories when being called by changeTopic
18 | return storyObj;
19 | });
20 | };
21 |
--------------------------------------------------------------------------------
/js/components/stories/no-saved-stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, StyleSheet } from "react-native";
3 | import Icon from "react-native-vector-icons/MaterialCommunityIcons";
4 | import Text from "../generic/text";
5 |
6 | const NoSavedStories = () => (
7 |
8 |
9 | No saved stories...
10 |
11 | );
12 |
13 | const styles = StyleSheet.create({
14 | container: {
15 | justifyContent: "center",
16 | alignItems: "center",
17 | height: 300
18 | }
19 | });
20 |
21 | export default NoSavedStories;
22 |
--------------------------------------------------------------------------------
/js/components/generic/error.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, StyleSheet } from "react-native";
3 | import Text from "./text";
4 | import Button from "./button";
5 |
6 | const Error = ({ refresh }) => (
7 |
14 | );
15 |
16 | const styles = StyleSheet.create({
17 | error: {
18 | flexDirection: "row",
19 | justifyContent: "center",
20 | backgroundColor: "#fe462c",
21 | padding: 20
22 | }
23 | });
24 |
25 | export default Error;
26 |
--------------------------------------------------------------------------------
/js/components/generic/splash.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ActivityIndicator, StyleSheet, View } from "react-native";
3 | import Text from "./text";
4 |
5 | const Splash = () => (
6 |
7 |
8 |
9 | Loading stories...
10 |
11 |
12 | );
13 |
14 | const styles = StyleSheet.create({
15 | splash: {
16 | flex: 1,
17 | paddingTop: 250,
18 | alignItems: "center",
19 | backgroundColor: "#009688"
20 | },
21 | message: {
22 | paddingTop: 30
23 | }
24 | });
25 |
26 | export default Splash;
27 |
--------------------------------------------------------------------------------
/js/components/generic/list.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { FlatList, RefreshControl, View, StyleSheet } from "react-native";
3 |
4 | const List = ({
5 | items,
6 | renderItem,
7 | refresh,
8 | refreshing,
9 | header: Header,
10 | _style
11 | }) => {
12 | return (
13 |
14 | item.id}
18 | ListHeaderComponent={Header}
19 | renderItem={renderItem}
20 | data={items}
21 | />
22 |
23 | );
24 | };
25 |
26 | const styles = StyleSheet.create({
27 | list: {
28 | // flex: 1
29 | }
30 | });
31 |
32 | export default List;
33 |
--------------------------------------------------------------------------------
/js/components/generic/text.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Text as NativeText, StyleSheet } from "react-native";
3 |
4 | const Text = ({
5 | children,
6 | bold,
7 | size,
8 | _style,
9 | alignRight,
10 | alignCenter,
11 | color,
12 | paddedTop
13 | }) => (
14 |
26 | {children}
27 |
28 | );
29 |
30 | const styles = StyleSheet.create({
31 | font: {
32 | fontFamily: "AppleSDGothicNeo-Medium"
33 | },
34 | bold: {
35 | fontFamily: "AppleSDGothicNeo-Bold"
36 | }
37 | });
38 |
39 | export default Text;
40 |
--------------------------------------------------------------------------------
/js/connected/thread.connected.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { View, ActivityIndicator } from "react-native";
3 | import { connect } from "react-redux";
4 | import {
5 | loadComments,
6 | refreshThread,
7 | loadReplies,
8 | toggleComment
9 | } from "../redux/action-creators/thread";
10 | import Thread from "../components/thread";
11 |
12 | class ThreadView extends Component {
13 | componentDidMount() {
14 | const { comments, story: { id, kids }, loadComments } = this.props;
15 | if (!comments.length || comments[0].parent !== id) {
16 | loadComments(kids);
17 | }
18 | }
19 |
20 | render() {
21 | return ;
22 | }
23 | }
24 |
25 | const mapStateToProps = ({ thread }) => ({ ...thread });
26 | export default connect(mapStateToProps, {
27 | loadComments,
28 | refreshThread,
29 | loadReplies,
30 | toggleComment
31 | })(ThreadView);
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
50 |
51 | fastlane/report.xml
52 | fastlane/Preview.html
53 | fastlane/screenshots
54 |
--------------------------------------------------------------------------------
/pre-.commit.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #husky 0.13.3
3 |
4 | command_exists () {
5 | command -v "$1" >/dev/null 2>&1
6 | }
7 |
8 | load_nvm () {
9 | export $1=$2
10 | [ -s "$2/nvm.sh" ] && . $2/nvm.sh
11 | command_exists nvm && [ -f .nvmrc ] && nvm use
12 | }
13 |
14 | has_hook_script () {
15 | [ -f package.json ] && cat package.json | grep -q "\"$1\"[[:space:]]*:"
16 | }
17 |
18 | cd .
19 |
20 | has_hook_script precommit || exit 0
21 |
22 | export PATH=$PATH:/usr/local/bin:/usr/local
23 | load_nvm BREW_NVM_DIR /usr/local/opt/nvm
24 |
25 | load_nvm NVM_DIR /Users/seanyesmunt/.nvm
26 |
27 | command_exists npm || {
28 | echo >&2 "> husky - Can't find npm in PATH. Skipping precommit script in package.json"
29 | exit 0
30 | }
31 |
32 | echo
33 | echo "> husky - npm run -s precommit"
34 | echo
35 |
36 | export GIT_PARAMS="$*"
37 | npm run -s precommit || {
38 | echo
39 | echo "> husky - pre-commit hook failed (add --no-verify to bypass)"
40 | echo "> husky - to debug, use 'npm run precommit'"
41 | exit 1
42 | }
43 |
--------------------------------------------------------------------------------
/js/components/generic/link.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { StyleSheet, View, TouchableHighlight } from "react-native";
3 | import Thread from "../../connected/thread.connected";
4 |
5 | const getScene = (title, linkProps) => {
6 | const components = {
7 | Thread
8 | };
9 |
10 | return {
11 | title: "Comments",
12 | linkProps,
13 | component: components[title]
14 | };
15 | };
16 |
17 | const Link = ({
18 | navigator,
19 | children,
20 | to: newView,
21 | viewIndex,
22 | linkProps,
23 | _style,
24 | underlayColor
25 | }) => (
26 |
30 | navigator.push(
31 | Object.assign({}, getScene(newView, linkProps), {
32 | index: viewIndex + 1
33 | })
34 | )}
35 | >
36 |
37 | {children}
38 |
39 |
40 | );
41 |
42 | const styles = StyleSheet.create({});
43 |
44 | export default Link;
45 |
--------------------------------------------------------------------------------
/js/components/thread/load-replies.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, StyleSheet } from "react-native";
3 | import Text from "../generic/text";
4 | import Button from "../generic/button";
5 |
6 | const LoadReplies = props => {
7 | const { loadReplies, kids, isLoading, id, commentChain } = props;
8 | return (
9 |
10 |
19 |
20 | );
21 | };
22 |
23 | const styles = StyleSheet.create({
24 | container: {
25 | marginTop: 15
26 | },
27 | button: {
28 | paddingTop: 5,
29 | paddingBottom: 5
30 | },
31 | buttonText: {
32 | textAlign: "center",
33 | color: "#19467a"
34 | }
35 | });
36 |
37 | export default LoadReplies;
38 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hnews",
3 | "version": "2.0.2",
4 | "scripts": {
5 | "start": "node node_modules/react-native/local-cli/cli.js start",
6 | "lint": "eslint ./src/components/**.js",
7 | "precommit": "lint-staged"
8 | },
9 | "lint-staged": {
10 | "js/**/*.js": [
11 | "prettier --write",
12 | "git add"
13 | ]
14 | },
15 | "dependencies": {
16 | "moment": "^2.18.1",
17 | "prop-types": "^15.5.8",
18 | "react": "16.0.0-alpha.6",
19 | "react-native": "0.43",
20 | "react-native-collapsible": "^0.8.0",
21 | "react-native-deprecated-custom-components": "^0.1.0",
22 | "react-native-htmlview": "^0.9.0",
23 | "react-native-safari-view": "^2.0.0",
24 | "react-native-tab-view": "0.0.58",
25 | "react-native-vector-icons": "^4.4.0",
26 | "react-redux": "^5.0.3",
27 | "redux": "^3.6.0",
28 | "redux-actions": "^2.0.1",
29 | "redux-logger": "^3.0.0",
30 | "redux-promise": "^0.5.3",
31 | "redux-thunk": "^2.2.0"
32 | },
33 | "devDependencies": {
34 | "babel-eslint": "^6.1.0",
35 | "eslint": "2.7.0",
36 | "eslint-plugin-react": "4.3.0",
37 | "eslint-plugin-react-native": "1.0.0",
38 | "husky": "^0.13.3",
39 | "lint-staged": "^3.4.2",
40 | "prettier": "^1.3.1"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/js/components/thread/comments.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, Text, StyleSheet, Dimensions } from "react-native";
3 | import List from "../generic/list";
4 | import Comment from "./comment";
5 |
6 | const Comments = ({
7 | comments,
8 | refreshing,
9 | refreshThread,
10 | renderHeader,
11 | loadComments,
12 | fetchingReplies,
13 | fetchingRepliesFor,
14 | loadReplies,
15 | toggleComment,
16 | openSafari,
17 | height
18 | }) => {
19 | return (
20 |
21 | refreshThread(comments.map(comment => comment.id))}
26 | items={comments}
27 | renderItem={({ item: comment }) => (
28 |
37 | )}
38 | />
39 |
40 | );
41 | };
42 |
43 | const styles = StyleSheet.create({
44 | comments: {}
45 | });
46 |
47 | export default Comments;
48 |
--------------------------------------------------------------------------------
/js/layout.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Dimensions, View, Text, StyleSheet } from "react-native";
3 | import StatusBar from "./components/status-bar";
4 | import TabLayout from "./components/tab-layout";
5 |
6 | const window = Dimensions.get("window");
7 | const HEIGHT = window.height;
8 | const WIDTH = window.width;
9 |
10 | const Layout = props => {
11 | const {
12 | title,
13 | navigator,
14 | isHome,
15 | component: NewView,
16 | linkProps,
17 | openSafari,
18 | saveStory,
19 | unSaveStory
20 | } = props;
21 |
22 | return (
23 |
24 |
30 | {isHome &&
31 | }
32 | {!isHome &&
33 | }
39 |
40 | );
41 | };
42 |
43 | const styles = StyleSheet.create({
44 | layout: {
45 | height: HEIGHT,
46 | width: WIDTH
47 | },
48 | statusBar: {
49 | alignSelf: "flex-start"
50 | },
51 | tabLayout: {
52 | alignSelf: "flex-end"
53 | }
54 | });
55 |
56 | export default Layout;
57 |
--------------------------------------------------------------------------------
/js/components/saved-stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View } from "react-native";
3 | import TopicFilter from "./stories/topic-filter";
4 | import List from "./generic/list";
5 | import Story from "./stories/story";
6 | import NoSavedStories from "./stories/no-saved-stories";
7 |
8 | const Stories = ({
9 | savedStories,
10 | unSaveStory,
11 | refreshing,
12 | refreshSavedStories,
13 | navigator,
14 | viewIndex,
15 | openSafari,
16 | height,
17 | error
18 | }) => {
19 | return (
20 |
21 | {error &&
22 |
24 | refreshSavedStories(savedStories.map(story => story.id))}
25 | />}
26 | {!!savedStories.length &&
27 |
32 | savedStories.length &&
33 | refreshSavedStories(savedStories.map(story => story.id))}
34 | renderItem={({ item: story }) => (
35 |
44 | )}
45 | />}
46 | {!savedStories.length && }
47 |
48 | );
49 | };
50 |
51 | export default Stories;
52 |
--------------------------------------------------------------------------------
/ios/hnews/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "AppDelegate.h"
11 |
12 | #import
13 | #import
14 |
15 | @implementation AppDelegate
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
18 | {
19 | NSURL *jsCodeLocation;
20 |
21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
22 |
23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
24 | moduleName:@"hnews"
25 | initialProperties:nil
26 | launchOptions:launchOptions];
27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
28 |
29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
30 | UIViewController *rootViewController = [UIViewController new];
31 | rootViewController.view = rootView;
32 | self.window.rootViewController = rootViewController;
33 | [self.window makeKeyAndVisible];
34 | return YES;
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/js/components/stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, StyleSheet } from "react-native";
3 | import TopicFilter from "./stories/topic-filter";
4 | import List from "./generic/list";
5 | import Error from "./generic/error";
6 | import Loader from "./generic/loader";
7 | import Story from "./stories/story";
8 |
9 | const Stories = ({
10 | viewIndex,
11 | error,
12 | loading,
13 | stories,
14 | saveStory,
15 | unSaveStory,
16 | topics,
17 | navigator,
18 | changeTopic,
19 | refreshStories,
20 | refreshing,
21 | openSafari,
22 | height
23 | }) => {
24 | return (
25 |
26 | {error &&
27 | refreshStories(topics.currentlySelected)} />}
28 | {!loading &&
29 | (
32 |
33 | )}
34 | items={stories}
35 | refresh={() => refreshStories(topics.currentlySelected)}
36 | refreshing={refreshing}
37 | renderItem={({ item: story }) => (
38 |
46 | )}
47 | />}
48 | {loading && }
49 |
50 | );
51 | };
52 |
53 | export default Stories;
54 |
--------------------------------------------------------------------------------
/ios/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore unexpected extra "@providesModule"
9 | .*/node_modules/.*/node_modules/fbjs/.*
10 |
11 | ; Ignore duplicate module providers
12 | ; For RN Apps installed via npm, "Libraries" folder is inside
13 | ; "node_modules/react-native" but in the source repo it is in the root
14 | .*/Libraries/react-native/React.js
15 | .*/Libraries/react-native/ReactNative.js
16 |
17 | [include]
18 |
19 | [libs]
20 | node_modules/react-native/Libraries/react-native/react-native-interface.js
21 | node_modules/react-native/flow
22 | flow/
23 |
24 | [options]
25 | emoji=true
26 |
27 | module.system=haste
28 |
29 | experimental.strict_type_args=true
30 |
31 | munge_underscores=true
32 |
33 | 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'
34 |
35 | suppress_type=$FlowIssue
36 | suppress_type=$FlowFixMe
37 | suppress_type=$FixMe
38 |
39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-0]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
40 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-0]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
41 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
42 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
43 |
44 | unsafe.enable_getters_and_setters=true
45 |
46 | [version]
47 | ^0.40.0
48 |
--------------------------------------------------------------------------------
/js/components/generic/button.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import { TouchableHighlight, View, StyleSheet } from "react-native";
4 |
5 | const Button = ({
6 | _style,
7 | height,
8 | children,
9 | onPress,
10 | paddedLeft,
11 | paddedRight,
12 | paddedTop,
13 | paddedBottom,
14 | padded,
15 | flex,
16 | underlayColor
17 | }) => {
18 | return (
19 |
33 |
34 | {children}
35 |
36 |
37 | );
38 | };
39 |
40 | Button.defaultProps = {
41 | row: true
42 | };
43 |
44 | Button.propTypes = {
45 | row: PropTypes.bool
46 | };
47 |
48 | const styles = StyleSheet.create({
49 | button: {
50 | // flexDirection: 'row',
51 | // justifyContent: 'center'
52 | },
53 | row: {
54 | flexDirection: "row"
55 | },
56 | column: {
57 | flexDirection: "column"
58 | },
59 | flex: {
60 | flex: 1
61 | },
62 | padded: {
63 | padding: 10
64 | },
65 | paddedLeft: {
66 | paddingLeft: 10
67 | },
68 | paddedRight: {
69 | paddingRight: 10
70 | },
71 | paddedTop: {
72 | paddingTop: 10
73 | },
74 | paddedBottom: {
75 | paddingBottom: 10
76 | }
77 | });
78 |
79 | export default Button;
80 |
--------------------------------------------------------------------------------
/js/helpers/comment-helpers.js:
--------------------------------------------------------------------------------
1 | export const appendReplies = (comments, commentChain, replies) => {
2 | const updateComments = (comments, commentChainCopy) => {
3 | if (commentChainCopy.length === 1) {
4 | return comments.map(comment => {
5 | if (comment.id === commentChainCopy[0]) {
6 | return Object.assign(comment, {
7 | kids: replies.map(reply =>
8 | Object.assign(reply, {
9 | showComment: true,
10 | commentChain: commentChain.concat([reply.id])
11 | })
12 | )
13 | });
14 | } else {
15 | return comment;
16 | }
17 | });
18 | } else {
19 | return comments.map(comment => {
20 | if (comment.id === commentChainCopy[0]) {
21 | const kids = updateComments(comment.kids, commentChainCopy.slice(1));
22 | return Object.assign(comment, { kids });
23 | } else {
24 | return comment;
25 | }
26 | });
27 | }
28 | };
29 |
30 | return updateComments(comments, commentChain);
31 | };
32 |
33 | export const toggleViewComment = (comments, commentChain = [], id) => {
34 | if (commentChain.length === 1) {
35 | return comments.map(comment => {
36 | return comment.id === id
37 | ? Object.assign(comment, { showComment: !comment.showComment })
38 | : comment;
39 | });
40 | } else {
41 | return comments.map(comment => {
42 | if (comment.id === commentChain[0]) {
43 | const showComment = toggleViewComment(
44 | comment.kids,
45 | commentChain.slice(1),
46 | id
47 | );
48 | return Object.assign(comment, { showComment });
49 | } else {
50 | return comment;
51 | }
52 | });
53 | }
54 | };
55 |
--------------------------------------------------------------------------------
/ios/hnews/LaunchImage.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "57x57",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-57x57@1x.png",
49 | "scale" : "1x"
50 | },
51 | {
52 | "size" : "57x57",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-57x57@2x.png",
55 | "scale" : "2x"
56 | },
57 | {
58 | "size" : "60x60",
59 | "idiom" : "iphone",
60 | "filename" : "Icon-App-60x60@2x.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "60x60",
65 | "idiom" : "iphone",
66 | "filename" : "Icon-App-60x60@3x.png",
67 | "scale" : "3x"
68 | }
69 | ],
70 | "info" : {
71 | "version" : 1,
72 | "author" : "xcode"
73 | }
74 | }
--------------------------------------------------------------------------------
/js/components/thread.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ActivityIndicator, View, StyleSheet } from "react-native";
3 | import Loader from "./generic/loader";
4 | import Head from "./thread/head";
5 | import Comments from "./thread/comments";
6 | import Error from "./generic/error";
7 |
8 | const Thread = ({
9 | loading,
10 | story,
11 | comments,
12 | refreshThread,
13 | refreshing,
14 | loadComments,
15 | fetchingReplies,
16 | fetchingRepliesFor,
17 | loadReplies,
18 | toggleComment,
19 | saveStory,
20 | unSaveStory,
21 | openSafari,
22 | height,
23 | error
24 | }) => {
25 | const { saved, title, score, time, descendants, url } = story;
26 |
27 | const _renderHead = () => (
28 |
39 | );
40 |
41 | return (
42 |
43 | {error &&
44 | refreshThread(comments.map(comment => comment.id))}
46 | />}
47 | {loading && _renderHead()}
48 | {loading && }
49 | {!loading &&
50 | }
63 |
64 | );
65 | };
66 |
67 | const styles = StyleSheet.create({
68 | thread: {
69 | flex: 1,
70 | backgroundColor: "white"
71 | }
72 | });
73 |
74 | export default Thread;
75 |
--------------------------------------------------------------------------------
/js/components/status-bar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Text, View, StyleSheet, StatusBar } from "react-native";
3 | import Icon from "react-native-vector-icons/MaterialCommunityIcons";
4 | import Button from "./generic/button";
5 | import SafariView from "react-native-safari-view";
6 |
7 | class StatusBarWrapper extends Component {
8 | componentDidMount() {
9 | SafariView.addEventListener("onShow", () =>
10 | StatusBar.setBarStyle("dark-content")
11 | );
12 | SafariView.addEventListener("onDismiss", () =>
13 | StatusBar.setBarStyle("light-content")
14 | );
15 | }
16 |
17 | render() {
18 | const { title, showBackArrow, navigator, isHome } = this.props;
19 | return (
20 |
21 |
22 |
23 |
24 | {!isHome &&
25 | }
33 |
34 |
35 | {title}
36 |
37 |
38 |
39 |
40 | );
41 | }
42 | }
43 |
44 | const styles = StyleSheet.create({
45 | statusBar: {
46 | height: 64,
47 | paddingTop: 25,
48 | backgroundColor: "#009688"
49 | },
50 | row: {
51 | flexDirection: "row"
52 | },
53 | item: {
54 | width: 50
55 | },
56 | titleContainer: {
57 | flex: 1
58 | },
59 | title: {
60 | fontSize: 20,
61 | color: "white",
62 | textAlign: "center"
63 | },
64 | icon: {
65 | paddingTop: 3
66 | }
67 | });
68 |
69 | export default StatusBarWrapper;
70 |
--------------------------------------------------------------------------------
/js/components/tab-layout.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, TabBarIOS } from "react-native";
3 | import Icon from "react-native-vector-icons/MaterialCommunityIcons";
4 | import Stories from "../components/stories";
5 | import SavedStories from "../components/saved-stories";
6 |
7 | const TabBarLayout = ({
8 | viewIndex,
9 | changeView,
10 | viewingStories,
11 | navigator,
12 | topics,
13 | stories,
14 | savedStories,
15 | saveStory,
16 | unSaveStory,
17 | changeTopic,
18 | refreshStories,
19 | refreshSavedStories,
20 | openSafari,
21 | height
22 | }) => {
23 | return (
24 |
30 | viewingStories && changeView()}
35 | >
36 |
46 |
47 | !viewingStories && changeView()}
52 | >
53 |
65 |
66 |
67 | );
68 | };
69 |
70 | export default TabBarLayout;
71 |
--------------------------------------------------------------------------------
/js/components/thread/collapsible-comment.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, StyleSheet } from "react-native";
3 | import HTMLView from "react-native-htmlview";
4 | import LoadReplies from "./load-replies";
5 | import { fromNow } from "../../helpers/story-helpers";
6 | import Collapsible from "react-native-collapsible";
7 | import Comment from "./comment";
8 |
9 | const CollapsibleComment = ({
10 | expanded,
11 | text,
12 | kids,
13 | fetchingRepliesFor,
14 | id,
15 | commentChain,
16 | loadReplies,
17 | openSafari
18 | }) => {
19 | const replies = kids && kids.length;
20 | return (
21 |
22 |
23 |
24 | ${text}`}
26 | onLinkPress={url => openSafari(url)}
27 | stylesheet={styles}
28 | />
29 | {replies &&
30 | typeof kids[0] === "number" &&
31 | }
38 | {replies &&
39 | typeof kids[0] === "object" &&
40 |
41 | {kids.map(comment => (
42 |
49 | ))}
50 | }
51 |
52 |
53 |
54 | );
55 | };
56 |
57 | const styles = StyleSheet.create({
58 | container: {
59 | // paddingBottom: 10
60 | },
61 | repliesContainer: {
62 | marginTop: 10
63 | },
64 | custom: {
65 | // lineHeight: 1
66 | },
67 | p: {
68 | lineHeight: 18,
69 | fontSize: 14
70 | }
71 | });
72 |
73 | export default CollapsibleComment;
74 |
--------------------------------------------------------------------------------
/js/components/thread/head.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, StyleSheet } from "react-native";
3 | import Text from "../generic/text";
4 | import Button from "../generic/button";
5 | import { formatUrl, fromNow } from "../../helpers/story-helpers";
6 |
7 | const Thread = ({
8 | loading,
9 | title,
10 | score,
11 | time,
12 | url,
13 | descendants,
14 | saved,
15 | saveAction,
16 | story,
17 | openSafari
18 | }) => {
19 | return (
20 |
53 | );
54 | };
55 |
56 | const styles = StyleSheet.create({
57 | container: {
58 | padding: 10,
59 | borderBottomWidth: 1,
60 | borderBottomColor: "#e0e0e0"
61 | },
62 | row: {
63 | flexDirection: "row",
64 | paddingTop: 10
65 | },
66 | space: {
67 | justifyContent: "space-between"
68 | },
69 | save: {
70 | backgroundColor: "#8e44ad",
71 | borderRadius: 10
72 | },
73 | blue: {
74 | backgroundColor: "#2980b9"
75 | },
76 | time: {
77 | paddingLeft: 10
78 | }
79 | });
80 |
81 | export default Thread;
82 |
--------------------------------------------------------------------------------
/ios/Launch Screen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/js/redux/action-creators/settings.js:
--------------------------------------------------------------------------------
1 | import { AsyncStorage } from "react-native";
2 | import { createAction } from "redux-actions";
3 | import {
4 | LOAD_SETTINGS_SUCCESS,
5 | LOAD_SETTINGS_ERROR,
6 | CHANGE_VIEW,
7 | CHANGE_TOPIC_REQUEST,
8 | CHANGE_TOPIC_SUCCESS,
9 | CHANGE_TOPIC_ERROR
10 | } from "../constants";
11 | import { getJson } from "./fetch-builder";
12 |
13 | const onLoadSettingsSuccess = createAction(LOAD_SETTINGS_SUCCESS);
14 | const onLoadSettingsError = createAction(LOAD_SETTINGS_ERROR);
15 | const onChangeView = createAction(CHANGE_VIEW);
16 |
17 | const onChangeTopicRequest = createAction(CHANGE_TOPIC_REQUEST);
18 | const onChangeTopicSuccess = createAction(CHANGE_TOPIC_SUCCESS);
19 | const onChangeTopicError = createAction(CHANGE_TOPIC_ERROR);
20 |
21 | export const fetchInitialData = selectedTopic => {
22 | return dispatch => {
23 | AsyncStorage.multiGet(["settings", "savedStories"])
24 | .then(res => {
25 | const settingsRes = res[0][1];
26 | const settings = (settingsRes && JSON.parse(settingsRes)) || {};
27 | const savedStoriesRes = res[1][1];
28 | const savedStoryIds = (savedStoriesRes &&
29 | JSON.parse(savedStoriesRes)) || [];
30 |
31 | let query = "";
32 | if (savedStoryIds.length) {
33 | query += `savedStories=${savedStoryIds.join(",")}`;
34 | }
35 |
36 | getJson("stories", selectedTopic, query)
37 | .then((initialStories = []) => {
38 | dispatch(onLoadSettingsSuccess({ settings, initialStories }));
39 | })
40 | .catch(err => {
41 | dispatch(onLoadSettingsError(err));
42 | });
43 | })
44 | .catch(err => {
45 | dispatch(onLoadSettingsError(err));
46 | });
47 | };
48 | };
49 |
50 | export function changeView() {
51 | return dispatch => dispatch(onChangeView());
52 | }
53 |
54 | export function changeTopic(newTopic) {
55 | return dispatch => {
56 | dispatch(onChangeTopicRequest({ newTopic }));
57 |
58 | getJson("stories", newTopic)
59 | .then(({ stories }) => {
60 | dispatch(onChangeTopicSuccess({ stories }));
61 | })
62 | .catch(err => dispatch(onChangeTopicError(err)));
63 | };
64 | }
65 |
--------------------------------------------------------------------------------
/ios/hnews/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | hnews
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSExceptionDomains
30 |
31 | localhost
32 |
33 | NSExceptionAllowsInsecureHTTPLoads
34 |
35 |
36 |
37 |
38 | NSLocationWhenInUseUsageDescription
39 |
40 | UIAppFonts
41 |
42 | Entypo.ttf
43 | EvilIcons.ttf
44 | Feather.ttf
45 | FontAwesome.ttf
46 | Foundation.ttf
47 | Ionicons.ttf
48 | MaterialCommunityIcons.ttf
49 | MaterialIcons.ttf
50 | Octicons.ttf
51 | SimpleLineIcons.ttf
52 | Zocial.ttf
53 |
54 | UILaunchStoryboardName
55 | LaunchScreen
56 | UIRequiredDeviceCapabilities
57 |
58 | armv7
59 |
60 | UIStatusBarStyle
61 | UIStatusBarStyleLightContent
62 | UISupportedInterfaceOrientations
63 |
64 | UIInterfaceOrientationPortrait
65 | UIInterfaceOrientationPortraitUpsideDown
66 |
67 | UIViewControllerBasedStatusBarAppearance
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/js/redux/constants.js:
--------------------------------------------------------------------------------
1 | export const ROOT_URL = "https://hackernews-server-igvdaqfamu.now.sh";
2 | // export const ROOT_URL = 'http://localhost:5000'
3 |
4 | export const LOAD_SETTINGS_SUCCESS = "LOAD_SETTINGS_SUCCESS";
5 | export const LOAD_SETTINGS_ERROR = "LOAD_SETTINGS_ERROR";
6 |
7 | export const CHANGE_VIEW = "CHANGE_VIEW";
8 |
9 | export const FETCH_TOPIC_STORIES_REQUEST = "FETCH_TOPIC_STORIES_REQUEST";
10 | export const FETCH_TOPIC_STORIES_SUCCESS = "FETCH_TOPIC_STORIES_SUCCESS";
11 | export const FETCH_TOPIC_STORIES_ERROR = "FETCH_TOPIC_STORIES_ERROR";
12 |
13 | export const FETCH_SAVED_STORIES_REQUEST = "FETCH_SAVED_STORIES_REQUEST";
14 | export const FETCH_SAVED_STORIES_SUCCESS = "FETCH_SAVED_STORIES_SUCCESS";
15 | export const FETCH_SAVED_STORIES_ERROR = "FETCH_SAVED_STORIES_ERROR";
16 |
17 | export const SAVE_STORY_SUCCESS = "SAVE_STORY_SUCCESS";
18 | export const SAVE_STORY_ERROR = "SAVE_STORY_ERROR";
19 |
20 | export const UN_SAVE_STORY_SUCCESS = "UN_SAVE_STORY_SUCCESS";
21 | export const UN_SAVE_STORY_ERROR = "UN_SAVE_STORY_ERROR";
22 |
23 | export const FETCH_COMMENTS_REQUEST = "FETCH_COMMENTS_REQUEST";
24 | export const FETCH_COMMENTS_SUCCESS = "FETCH_COMMENTS_SUCCESS";
25 | export const FETCH_COMMENTS_ERROR = "FETCH_COMMENTS_ERROR";
26 |
27 | export const CHANGE_TOPIC_REQUEST = "CHANGE_TOPIC_REQUEST";
28 | export const CHANGE_TOPIC_SUCCESS = "CHANGE_TOPIC_SUCCESS";
29 | export const CHANGE_TOPIC_ERROR = "CHANGE_TOPIC_ERROR";
30 |
31 | export const REFRESH_STORIES_REQUEST = "REFRESH_STORIES_REQUEST";
32 | export const REFRESH_STORIES_SUCCESS = "REFRESH_STORIES_SUCCESS";
33 | export const REFRESH_STORIES_ERROR = "REFRESH_STORIES_ERROR";
34 |
35 | export const REFRESH_SAVED_STORIES_REQUEST = "REFRESH_SAVED_STORIES_REQUEST";
36 | export const REFRESH_SAVED_STORIES_SUCCESS = "REFRESH_SAVED_STORIES_SUCCESS";
37 | export const REFRESH_SAVED_STORIES_ERROR = "REFRESH_SAVED_STORIES_ERROR";
38 |
39 | export const REFRESH_THREAD_REQUEST = "REFRESH_THREAD_REQUEST";
40 | export const REFRESH_THREAD_SUCCESS = "REFRESH_THREAD_SUCCESS";
41 | export const REFRESH_THREAD_ERROR = "REFRESH_THREAD_ERROR";
42 |
43 | export const FETCH_REPLIES_REQUEST = "FETCH_REPLIES_REQUEST";
44 | export const FETCH_REPLIES_SUCCESS = "FETCH_REPLIES_SUCCESS";
45 | export const FETCH_REPLIES_ERROR = "FETCH_REPLIES_ERROR";
46 |
47 | export const TOGGLE_COMMENT = "TOGGLE_COMMENT";
48 |
--------------------------------------------------------------------------------
/js/redux/reducers/settings.js:
--------------------------------------------------------------------------------
1 | import { handleActions } from "redux-actions";
2 | import {
3 | LOAD_SETTINGS_SUCCESS,
4 | LOAD_SETTINGS_ERROR,
5 | CHANGE_VIEW,
6 | SAVE_STORY_SUCCESS,
7 | UN_SAVE_STORY_SUCCESS,
8 | CHANGE_TOPIC_REQUEST
9 | } from "../constants";
10 | import getTitle from "../../helpers/get-title";
11 |
12 | const initialState = {
13 | loading: true,
14 | error: false,
15 | viewingStories: true,
16 | title: "Top Stories",
17 | topics: {
18 | currentlySelected: "topstories",
19 | available: [
20 | "topstories",
21 | "askstories",
22 | "showstories",
23 | "beststories",
24 | "jobstories"
25 | ]
26 | },
27 | savedStoryIds: [],
28 | settings: {
29 | darkMode: {
30 | id: "darkmode",
31 | name: "Dark mode",
32 | active: false
33 | }
34 | }
35 | };
36 |
37 | export default handleActions(
38 | {
39 | [LOAD_SETTINGS_SUCCESS]: (
40 | state,
41 | { payload: { settings, savedStoryIds = [] } }
42 | ) => {
43 | return {
44 | ...state,
45 | loading: false,
46 | settings: settings,
47 | savedStoryIds: savedStoryIds
48 | };
49 | },
50 | [LOAD_SETTINGS_ERROR]: (state, { payload }) => ({
51 | ...state,
52 | loading: false,
53 | error: payload
54 | }),
55 | [CHANGE_VIEW]: (state, { payload }) => {
56 | const { viewingStories, topics: { currentlySelected } } = state;
57 | const newViewingStoriesBool = !state.viewingStories;
58 |
59 | const title = newViewingStoriesBool
60 | ? getTitle(currentlySelected)
61 | : "Read it later";
62 | return {
63 | ...state,
64 | viewingStories: !state.viewingStories,
65 | title
66 | };
67 | },
68 | [SAVE_STORY_SUCCESS]: (state, { payload }) => {
69 | return {
70 | ...state,
71 | savedStoryIds: payload.savedStoryIds
72 | };
73 | },
74 | [UN_SAVE_STORY_SUCCESS]: (state, { payload }) => {
75 | return {
76 | ...state,
77 | savedStoryIds: payload.savedStoryIds
78 | };
79 | },
80 | [CHANGE_TOPIC_REQUEST]: (state, { payload: { newTopic } }) => ({
81 | ...state,
82 | title: getTitle(newTopic),
83 | topics: { available: state.topics.available, currentlySelected: newTopic }
84 | })
85 | },
86 | initialState
87 | );
88 |
--------------------------------------------------------------------------------
/js/app.container.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { View } from "react-native";
3 | import { Navigator } from "react-native-deprecated-custom-components";
4 | import { connect, Provider } from "react-redux";
5 | import {
6 | fetchInitialData,
7 | changeView,
8 | changeTopic
9 | } from "./redux/action-creators/settings";
10 | import {
11 | refreshStories,
12 | refreshSavedStories,
13 | saveStory,
14 | unSaveStory
15 | } from "./redux/action-creators/stories";
16 | import SplashScreen from "./components/generic/splash";
17 | import Error from "./components/generic/error";
18 | import Layout from "./layout";
19 | import SafariView from "react-native-safari-view";
20 |
21 | class App extends Component {
22 | componentDidMount() {
23 | const { fetchInitialData, topics: { currentlySelected } } = this.props;
24 | fetchInitialData(currentlySelected);
25 | }
26 |
27 | openSafari(url) {
28 | SafariView.show({
29 | url
30 | });
31 | }
32 |
33 | render() {
34 | const {
35 | loading,
36 | title,
37 | error,
38 | fetchInitialData,
39 | topics: { currentlySelected }
40 | } = this.props;
41 |
42 | return (
43 |
44 | {error && fetchInitialData(currentlySelected)} />}
45 | {loading && }
46 | {!loading &&
47 | {
50 | const { component, title: routeTitle, index, linkProps } = route;
51 | return (
52 | SafariView.show({ url })}
61 | />
62 | );
63 | }}
64 | />}
65 |
66 | );
67 | }
68 | }
69 |
70 | const mapStateToProps = ({ settings, stories, savedStories }) => ({
71 | stories,
72 | savedStories,
73 | ...settings
74 | });
75 |
76 | export default connect(mapStateToProps, {
77 | fetchInitialData,
78 | changeView,
79 | changeTopic,
80 | refreshStories,
81 | saveStory,
82 | unSaveStory,
83 | refreshStories,
84 | refreshSavedStories
85 | })(App);
86 |
--------------------------------------------------------------------------------
/js/redux/reducers/saved-stories.js:
--------------------------------------------------------------------------------
1 | import { handleActions } from "redux-actions";
2 | import {
3 | LOAD_SETTINGS_SUCCESS,
4 | FETCH_SAVED_STORIES_REQUEST,
5 | FETCH_SAVED_STORIES_SUCCESS,
6 | FETCH_SAVED_STORIES_ERROR,
7 | SAVE_STORY_SUCCESS,
8 | UN_SAVE_STORY_SUCCESS,
9 | REFRESH_SAVED_STORIES_REQUEST,
10 | REFRESH_SAVED_STORIES_SUCCESS,
11 | REFRESH_SAVED_STORIES_ERROR
12 | } from "../constants";
13 |
14 | const initialState = {
15 | loading: false,
16 | refreshing: false,
17 | error: null,
18 | savedStories: []
19 | };
20 |
21 | export default handleActions(
22 | {
23 | [LOAD_SETTINGS_SUCCESS]: (state, { payload }) => {
24 | const savedStories = payload.initialStories.savedStories || [];
25 | const newStories = savedStories.map(story =>
26 | Object.assign(story, { saved: true })
27 | );
28 |
29 | return {
30 | ...state,
31 | loading: false,
32 | savedStories: newStories
33 | };
34 | },
35 | [FETCH_SAVED_STORIES_REQUEST]: (state, { payload }) => ({
36 | ...state,
37 | error: null,
38 | loading: true
39 | }),
40 | [FETCH_SAVED_STORIES_SUCCESS]: (state, { payload }) => {
41 | return {
42 | ...state,
43 | loading: false,
44 | savedStories: payload.stories.map(story =>
45 | Object.assign(story, { saved: true })
46 | )
47 | };
48 | },
49 | [FETCH_SAVED_STORIES_ERROR]: (state, { payload }) => {
50 | return {
51 | ...state,
52 | loading: false,
53 | error: payload.error
54 | };
55 | },
56 | [SAVE_STORY_SUCCESS]: (state, { payload: { story } }) => {
57 | let newStories = state.savedStories.slice();
58 | newStories.unshift(story);
59 |
60 | return {
61 | ...state,
62 | savedStories: newStories
63 | };
64 | },
65 | [UN_SAVE_STORY_SUCCESS]: (state, { payload: { story: activeStory } }) => {
66 | const newStories = state.savedStories.filter(story => {
67 | return story.id !== activeStory.id;
68 | });
69 | return {
70 | ...state,
71 | savedStories: newStories
72 | };
73 | },
74 | [REFRESH_SAVED_STORIES_REQUEST]: (state, { payload }) => ({
75 | ...state,
76 | loading: false,
77 | refreshing: true
78 | }),
79 | [REFRESH_SAVED_STORIES_SUCCESS]: (state, { payload: { stories } }) => ({
80 | ...state,
81 | refreshing: false,
82 | stories
83 | }),
84 | [REFRESH_SAVED_STORIES_ERROR]: (state, { payload }) => ({
85 | ...state,
86 | loading: false,
87 | error: payload
88 | })
89 | },
90 | initialState
91 | );
92 |
--------------------------------------------------------------------------------
/js/components/thread/comment.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Animated, View, StyleSheet } from "react-native";
3 | import HTMLView from "react-native-htmlview";
4 | import moment from "moment";
5 | import Button from "../generic/button";
6 | import Text from "../generic/text";
7 | import LoadReplies from "./load-replies";
8 | import { fromNow } from "../../helpers/story-helpers";
9 | import CollapsibleComment from "./collapsible-comment";
10 | import Collapsible from "react-native-collapsible";
11 |
12 | class Comment extends Component {
13 | constructor(props) {
14 | super(props);
15 |
16 | this.state = {
17 | expanded: true
18 | };
19 | }
20 |
21 | _toggleComment() {
22 | this.setState({
23 | expanded: !this.state.expanded
24 | });
25 | }
26 |
27 | render() {
28 | const {
29 | text,
30 | by,
31 | id,
32 | time,
33 | deleted,
34 | kids,
35 | showComment,
36 | loadComments,
37 | fetchingReplies,
38 | fetchingRepliesFor,
39 | loadReplies,
40 | commentChain,
41 | reply,
42 | openSafari
43 | } = this.props;
44 | return (
45 |
46 | {!deleted &&
47 |
48 |
49 |
50 | {`${by} `}
51 | {moment(time * 1000).fromNow()}
52 | {` [${this.state.expanded ? "-" : "+"}]`}
53 |
54 |
64 |
65 | }
66 | {deleted &&
67 |
68 | deleted - {moment(time * 1000).fromNow()}
69 | }
70 |
71 | );
72 | }
73 | }
74 |
75 | const styles = StyleSheet.create({
76 | comment: {
77 | padding: 10,
78 | borderBottomWidth: 1,
79 | borderBottomColor: "#e2e2e2"
80 | },
81 | reply: {
82 | paddingTop: 10,
83 | paddingBottom: 10,
84 | marginLeft: 5,
85 | paddingLeft: 10,
86 | borderLeftWidth: 1,
87 | borderLeftColor: "#d5d5d5"
88 | },
89 | paddingTop: {
90 | paddingTop: 5
91 | }
92 | });
93 |
94 | export default Comment;
95 |
--------------------------------------------------------------------------------
/js/redux/action-creators/thread.js:
--------------------------------------------------------------------------------
1 | import { AsyncStorage } from "react-native";
2 | import { createAction } from "redux-actions";
3 | import {
4 | FETCH_COMMENTS_REQUEST,
5 | FETCH_COMMENTS_SUCCESS,
6 | FETCH_COMMENTS_ERROR,
7 | REFRESH_THREAD_REQUEST,
8 | REFRESH_THREAD_SUCCESS,
9 | REFRESH_THREAD_ERROR,
10 | FETCH_REPLIES_REQUEST,
11 | FETCH_REPLIES_SUCCESS,
12 | FETCH_REPLIES_ERROR,
13 | TOGGLE_COMMENT
14 | } from "../constants";
15 | import { getJson } from "./fetch-builder";
16 |
17 | const onFetchCommentsRequest = createAction(FETCH_COMMENTS_REQUEST);
18 | const onFetchCommentsSuccess = createAction(FETCH_COMMENTS_SUCCESS);
19 | const onFetchCommentsError = createAction(FETCH_COMMENTS_ERROR);
20 | const onRefreshThreadRequest = createAction(REFRESH_THREAD_REQUEST);
21 | const onRefreshThreadSuccess = createAction(REFRESH_THREAD_SUCCESS);
22 | const onRefreshThreadError = createAction(REFRESH_THREAD_ERROR);
23 | const onFetchRepliesRequest = createAction(FETCH_REPLIES_REQUEST);
24 | const onFetchRepliesSuccess = createAction(FETCH_REPLIES_SUCCESS);
25 | const onFetchRepliesError = createAction(FETCH_REPLIES_ERROR);
26 | const onToggleComment = createAction(TOGGLE_COMMENT);
27 |
28 | export function loadComments(commentIds = [], head) {
29 | return dispatch => {
30 | if (!commentIds.length) {
31 | return dispatch(onFetchCommentsSuccess({ comments: [] }));
32 | }
33 |
34 | const query = `comments=${commentIds.join(",")}`;
35 |
36 | dispatch(onFetchCommentsRequest({ head }));
37 | getJson("comments", null, query)
38 | .then(comments => dispatch(onFetchCommentsSuccess(comments)))
39 | .catch(err => dispatch(onFetchCommentsError({ err })));
40 | };
41 | }
42 |
43 | export function refreshThread(commentIds, head) {
44 | const query = `comments=${commentIds.join(",")}`;
45 |
46 | return dispatch => {
47 | dispatch(onRefreshThreadRequest({ head }));
48 |
49 | getJson("comments", null, query)
50 | .then(({ comments }) => {
51 | dispatch(onRefreshThreadSuccess({ comments }));
52 | })
53 | .catch(err => dispatch(onRefreshThreadError(err)));
54 | };
55 | }
56 |
57 | export function loadReplies(opId, commentChain, commentIds) {
58 | const query = `comments=${commentIds.join(",")}`;
59 |
60 | return dispatch => {
61 | dispatch(onFetchRepliesRequest({ opId }));
62 |
63 | getJson("comments", null, query)
64 | .then(({ comments }) => {
65 | dispatch(onFetchRepliesSuccess({ comments, commentChain, opId }));
66 | })
67 | .catch(err => dispatch(onFetchRepliesError(err)));
68 | };
69 | }
70 |
71 | export function toggleComment(id, commentChain) {
72 | return dispatch => {
73 | dispatch(onToggleComment({ id, commentChain }));
74 | };
75 | }
76 |
--------------------------------------------------------------------------------
/js/redux/reducers/thread.js:
--------------------------------------------------------------------------------
1 | import { handleActions } from "redux-actions";
2 | import {
3 | FETCH_COMMENTS_REQUEST,
4 | FETCH_COMMENTS_SUCCESS,
5 | FETCH_COMMENTS_ERROR,
6 | REFRESH_THREAD_REQUEST,
7 | REFRESH_THREAD_SUCCESS,
8 | REFRESH_THREAD_ERROR,
9 | FETCH_REPLIES_REQUEST,
10 | FETCH_REPLIES_SUCCESS,
11 | FETCH_REPLIES_ERROR,
12 | TOGGLE_COMMENT
13 | } from "../constants";
14 | import {
15 | toggleViewComment,
16 | appendReplies
17 | } from "../../helpers/comment-helpers";
18 |
19 | const initialState = {
20 | loading: true,
21 | refreshing: false,
22 | error: null,
23 | fetchingReplies: false,
24 | fetchingRepliesFor: null,
25 | comments: []
26 | };
27 |
28 | export default handleActions(
29 | {
30 | [FETCH_COMMENTS_REQUEST]: state => {
31 | return {
32 | ...state,
33 | error: null,
34 | comments: []
35 | };
36 | },
37 | [FETCH_COMMENTS_SUCCESS]: (state, { payload: { comments } }) => {
38 | return {
39 | ...state,
40 | error: null,
41 | loading: false,
42 | comments: comments.map(comment =>
43 | Object.assign({}, comment, {
44 | commentChain: [comment.id],
45 | showComment: true
46 | })
47 | )
48 | };
49 | },
50 | [FETCH_COMMENTS_ERROR]: (state, { payload }) => {
51 | return {
52 | ...state,
53 | error: payload.err
54 | };
55 | },
56 | [REFRESH_THREAD_REQUEST]: (state, { payload }) => ({
57 | ...state,
58 | loading: false,
59 | refreshing: true
60 | }),
61 | [REFRESH_THREAD_SUCCESS]: (state, { payload: { comments } }) => ({
62 | ...state,
63 | refreshing: false,
64 | comments
65 | }),
66 | [REFRESH_THREAD_ERROR]: (state, { payload }) => ({
67 | ...state,
68 | loading: false,
69 | error: payload
70 | }),
71 | [FETCH_REPLIES_REQUEST]: (state, { payload: { opId } }) => ({
72 | ...state,
73 | fetchingReplies: true,
74 | fetchingRepliesFor: opId
75 | }),
76 | [FETCH_REPLIES_SUCCESS]: (
77 | state,
78 | { payload: { comments: replies, commentChain } }
79 | ) => {
80 | return {
81 | ...state,
82 | loading: false,
83 | fetchingReplies: false,
84 | fetchingRepliesFor: null,
85 | comments: appendReplies(state.comments, commentChain, replies)
86 | };
87 | },
88 | [FETCH_REPLIES_ERROR]: (state, { payload }) => ({
89 | ...state,
90 | loading: false,
91 | error: payload
92 | }),
93 | [TOGGLE_COMMENT]: (state, { payload: { id, commentChain } }) => ({
94 | ...state,
95 | comments: toggleViewComment(state.comments, commentChain, id)
96 | })
97 | },
98 | initialState
99 | );
100 |
--------------------------------------------------------------------------------
/js/components/stories/topic-filter.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { View, StyleSheet } from "react-native";
3 | import Icon from "react-native-vector-icons/MaterialCommunityIcons";
4 | import Button from "../generic/button";
5 | import Text from "../generic/text";
6 | import { titles } from "../../helpers/get-title";
7 | import Collapsible from "react-native-collapsible";
8 |
9 | class TopicFilter extends Component {
10 | constructor(props) {
11 | super(props);
12 |
13 | this.state = { isCollapsed: true };
14 | }
15 |
16 | render() {
17 | const { topics, changeTopic } = this.props;
18 | const { currentlySelected } = topics;
19 |
20 | return (
21 |
22 |
25 | this.setState({ isCollapsed: !this.state.isCollapsed })}
26 | >
27 |
28 | {titles[topics.currentlySelected]}
29 |
30 |
35 |
36 |
37 |
38 |
39 |
40 | {topics.available.map(topic => {
41 | const isSelected = topic === currentlySelected;
42 | return (
43 |
47 |
51 | !isSelected
52 | ? changeTopic(topic)
53 | : this.setState({ isCollapsed: true })}
54 | >
55 |
60 | {titles[topic]}
61 |
62 |
63 |
64 | );
65 | })}
66 |
67 |
68 |
69 | );
70 | }
71 | }
72 |
73 | const styles = StyleSheet.create({
74 | container: {
75 | flexDirection: "row"
76 | },
77 | buttonText: {
78 | alignSelf: "flex-end",
79 | flexDirection: "row",
80 | paddingTop: 5
81 | },
82 | dropDownIcon: {
83 | marginTop: -1
84 | },
85 | topic: {
86 | textAlign: "right"
87 | },
88 | selectedContainer: {
89 | backgroundColor: "#169f8430"
90 | },
91 | selected: {
92 | color: "#16a085"
93 | }
94 | });
95 |
96 | export default TopicFilter;
97 |
--------------------------------------------------------------------------------
/js/components/stories/story.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { View, StyleSheet, TouchableHighlight } from "react-native";
3 | import Text from "../generic/text";
4 | import Link from "../generic/link";
5 | import Button from "../generic/button";
6 | import Icon from "react-native-vector-icons/MaterialCommunityIcons";
7 | import { formatUrl, fromNow } from "../../helpers/story-helpers";
8 |
9 | const Story = ({
10 | story,
11 | isSavedView,
12 | saveAction,
13 | navigator,
14 | viewIndex,
15 | openSafari,
16 | height
17 | }) => {
18 | const { title, time, score, descendants, url, saved } = story;
19 |
20 | const WrapperEl = url ? Button : Link;
21 |
22 | return (
23 | url && openSafari(url)}
25 | to="Thread"
26 | linkProps={{ story, height }}
27 | navigator={navigator}
28 | viewIndex={viewIndex}
29 | >
30 |
31 |
32 | {title}
33 | saveAction(story)}
38 | >
39 |
44 |
45 |
46 |
47 |
48 |
49 | {formatUrl(url)}
50 | {fromNow(time)}
51 |
52 | {score || 0} points
53 |
54 |
55 |
56 |
63 |
64 | {descendants || 0} comments
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | );
74 | };
75 |
76 | const styles = StyleSheet.create({
77 | story: {
78 | paddingLeft: 10,
79 | paddingTop: 15,
80 | paddingBottom: 15,
81 | minHeight: 150,
82 | borderTopWidth: 1,
83 | borderTopColor: "#ebebeb"
84 | },
85 | row: {
86 | flexDirection: "row",
87 | justifyContent: "space-between"
88 | },
89 | title: {
90 | flex: 1,
91 | flexWrap: "wrap"
92 | },
93 | saveAction: {
94 | paddingLeft: 20,
95 | marginTop: -10
96 | },
97 | postInfo: {
98 | paddingTop: 30
99 | },
100 | comments: {
101 | padding: 10,
102 | marginTop: -10,
103 | flexDirection: "row"
104 | },
105 | chevronRight: {
106 | marginTop: -1
107 | // marginRight: -15,
108 | // marginLeft: -20
109 | }
110 | });
111 |
112 | export default Story;
113 |
--------------------------------------------------------------------------------
/js/redux/action-creators/stories.js:
--------------------------------------------------------------------------------
1 | import { AsyncStorage } from "react-native";
2 | import { createAction } from "redux-actions";
3 | import {
4 | SAVE_STORY_SUCCESS,
5 | SAVE_STORY_ERROR,
6 | UN_SAVE_STORY_SUCCESS,
7 | UN_SAVE_STORY_ERROR,
8 | REFRESH_STORIES_REQUEST,
9 | REFRESH_STORIES_SUCCESS,
10 | REFRESH_STORIES_ERROR,
11 | REFRESH_SAVED_STORIES_REQUEST,
12 | REFRESH_SAVED_STORIES_SUCCESS,
13 | REFRESH_SAVED_STORIES_ERROR
14 | } from "../constants";
15 | import { getJson } from "./fetch-builder";
16 |
17 | const onSaveStorySuccess = createAction(SAVE_STORY_SUCCESS);
18 | const onSaveStoryError = createAction(SAVE_STORY_ERROR);
19 | const onUnSaveStorySuccess = createAction(UN_SAVE_STORY_SUCCESS);
20 | const onUnSaveStoryError = createAction(UN_SAVE_STORY_ERROR);
21 | const onRefreshStoriesRequest = createAction(REFRESH_STORIES_REQUEST);
22 | const onRefreshStoriesSuccess = createAction(REFRESH_STORIES_SUCCESS);
23 | const onRefreshStoriesError = createAction(REFRESH_STORIES_ERROR);
24 | const onRefreshSavedStoriesRequest = createAction(
25 | REFRESH_SAVED_STORIES_REQUEST
26 | );
27 | const onRefreshSavedStoriesSuccess = createAction(
28 | REFRESH_SAVED_STORIES_SUCCESS
29 | );
30 | const onRefreshSavedStoriesError = createAction(REFRESH_SAVED_STORIES_ERROR);
31 |
32 | const getSavedStories = () => {
33 | return AsyncStorage.getItem("savedStories").then(savedStoriesRes => {
34 | const savedStories = (savedStoriesRes && JSON.parse(savedStoriesRes)) || [];
35 | return savedStories;
36 | });
37 | };
38 |
39 | const setSavedStories = (dispatch, stories, story, unSaving) => {
40 | const toggleSaveAction = unSaving ? onUnSaveStorySuccess : onSaveStorySuccess;
41 | const toggleSaveActionErr = unSaving ? onUnSaveStoryError : onSaveStoryError;
42 | AsyncStorage.setItem("savedStories", JSON.stringify(stories))
43 | .then(() => dispatch(toggleSaveAction({ storyIds: stories, story })))
44 | .catch(err => dispatch(toggleSaveActionErr(err)));
45 | };
46 |
47 | export function saveStory(story) {
48 | return dispatch => {
49 | getSavedStories().then(stories => {
50 | if (!stories.length) {
51 | return setSavedStories(dispatch, [story.id], story);
52 | }
53 |
54 | const newStories = stories.slice();
55 | newStories.unshift(story.id);
56 | setSavedStories(dispatch, newStories, story);
57 | });
58 | };
59 | }
60 |
61 | export function unSaveStory(story) {
62 | return dispatch => {
63 | getSavedStories().then(stories => {
64 | const newStories = stories.filter(storyId => {
65 | return storyId !== story.id;
66 | });
67 | return setSavedStories(dispatch, newStories, story, true);
68 | });
69 | };
70 | }
71 |
72 | export function refreshStories(endpoint) {
73 | return (dispatch, getState) => {
74 | const state = getState();
75 | // hmm...
76 | const { savedStories: { savedStories } } = state;
77 | const slimSavedStories = savedStories.map(s => s.id);
78 |
79 | dispatch(onRefreshStoriesRequest());
80 |
81 | getJson("stories", endpoint)
82 | .then(({ stories }) => {
83 | const newStories = stories.map(
84 | story =>
85 | slimSavedStories.indexOf(story.id) === -1
86 | ? story
87 | : Object.assign(story, { saved: true })
88 | );
89 | dispatch(onRefreshStoriesSuccess({ newStories }));
90 | })
91 | .catch(err => dispatch(onRefreshStoriesError(err)));
92 | };
93 | }
94 |
95 | export function refreshSavedStories(storyIds) {
96 | const query = `stories=${storyIds.join(",")}`;
97 |
98 | return dispatch => {
99 | dispatch(onRefreshSavedStoriesRequest());
100 |
101 | getJson("saved", null, query)
102 | .then(({ stories }) => {
103 | dispatch(onRefreshSavedStoriesSuccess({ stories }));
104 | })
105 | .catch(err => dispatch(onRefreshSavedStoriesError(err)));
106 | };
107 | }
108 |
--------------------------------------------------------------------------------
/js/redux/reducers/stories.js:
--------------------------------------------------------------------------------
1 | import { handleActions } from "redux-actions";
2 | import {
3 | LOAD_SETTINGS_SUCCESS,
4 | FETCH_TOPIC_STORIES_REQUEST,
5 | FETCH_TOPIC_STORIES_SUCCESS,
6 | FETCH_TOPIC_STORIES_ERROR,
7 | SAVE_STORY_SUCCESS,
8 | UN_SAVE_STORY_SUCCESS,
9 | CHANGE_TOPIC_REQUEST,
10 | CHANGE_TOPIC_SUCCESS,
11 | CHANGE_TOPIC_ERROR,
12 | REFRESH_STORIES_REQUEST,
13 | REFRESH_STORIES_SUCCESS,
14 | REFRESH_STORIES_ERROR
15 | } from "../constants";
16 |
17 | const initialState = {
18 | loading: true,
19 | refreshing: false,
20 | error: null,
21 | stories: []
22 | };
23 |
24 | export default handleActions(
25 | {
26 | [LOAD_SETTINGS_SUCCESS]: (state, { payload }) => {
27 | const stories = payload.initialStories.stories || [];
28 | const savedStories = payload.initialStories.savedStories || [];
29 |
30 | const isSavedStory = storyIdInQuestion => {
31 | for (var i = 0; i < savedStories.length; i++) {
32 | if (savedStories[i].id === storyIdInQuestion) {
33 | return true;
34 | }
35 | }
36 | };
37 |
38 | const storiesWithAttrs = stories.map(story => {
39 | if (isSavedStory(story.id)) {
40 | return Object.assign(story, { saved: true });
41 | } else {
42 | return story;
43 | }
44 | });
45 |
46 | return {
47 | ...state,
48 | loading: false,
49 | stories: storiesWithAttrs
50 | };
51 | },
52 | [FETCH_TOPIC_STORIES_REQUEST]: (state, { payload }) => ({
53 | ...state,
54 | error: null
55 | }),
56 | [FETCH_TOPIC_STORIES_SUCCESS]: (state, { payload }) => {
57 | return {
58 | ...state,
59 | loading: false,
60 | stories: payload.stories.map(story => {
61 | if (payload.savedStoryIds.indexOf(story.id) !== -1) {
62 | return Object.assign(story, { saved: true });
63 | }
64 | return story;
65 | })
66 | };
67 | },
68 | [FETCH_TOPIC_STORIES_ERROR]: (state, { payload }) => {
69 | return {
70 | ...state,
71 | loading: false,
72 | error: payload.err
73 | };
74 | },
75 | [SAVE_STORY_SUCCESS]: (state, { payload }) => {
76 | // load new storeis with correct "saved" attr
77 | const savedStories = payload.savedStoryIds;
78 | const newStories = state.stories.map(story => {
79 | return story.id === payload.story.id
80 | ? Object.assign(story, { saved: true })
81 | : story;
82 | });
83 | return {
84 | ...state,
85 | stories: newStories
86 | };
87 | },
88 | [UN_SAVE_STORY_SUCCESS]: (state, { payload }) => {
89 | const savedStories = payload.savedStoryIds;
90 | const newStories = state.stories.map(story => {
91 | return story.id === payload.story.id
92 | ? Object.assign(story, { saved: false })
93 | : story;
94 | });
95 | return {
96 | ...state,
97 | stories: newStories
98 | };
99 | },
100 | [CHANGE_TOPIC_REQUEST]: state => ({
101 | ...state,
102 | loading: true,
103 | stories: []
104 | }),
105 | [CHANGE_TOPIC_SUCCESS]: (state, { payload: { stories } }) => ({
106 | ...state,
107 | loading: false,
108 | stories
109 | }),
110 | [CHANGE_TOPIC_ERROR]: (state, { payload }) => ({
111 | ...state,
112 | loading: false,
113 | error: payload
114 | }),
115 | [REFRESH_STORIES_REQUEST]: (state, { payload }) => ({
116 | ...state,
117 | error: null,
118 | loading: false,
119 | refreshing: true
120 | }),
121 | [REFRESH_STORIES_SUCCESS]: (state, { payload: { newStories } }) => {
122 | return {
123 | ...state,
124 | refreshing: false,
125 | stories: newStories
126 | };
127 | },
128 | [REFRESH_STORIES_ERROR]: (state, { payload }) => ({
129 | ...state,
130 | loading: false,
131 | error: payload
132 | })
133 | },
134 | initialState
135 | );
136 |
--------------------------------------------------------------------------------
/ios/hnews.xcodeproj/xcshareddata/xcschemes/hnews.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
62 |
68 |
69 |
70 |
71 |
72 |
78 |
79 |
80 |
81 |
82 |
83 |
94 |
96 |
102 |
103 |
104 |
105 |
106 |
107 |
113 |
115 |
121 |
122 |
123 |
124 |
126 |
127 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/ios/hnews.xcodeproj/xcshareddata/xcschemes/hnews-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
62 |
68 |
69 |
70 |
71 |
72 |
78 |
79 |
80 |
81 |
82 |
83 |
94 |
96 |
102 |
103 |
104 |
105 |
106 |
107 |
113 |
115 |
121 |
122 |
123 |
124 |
126 |
127 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/ios/hnews.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
11 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
12 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
13 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
14 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
15 | 04E204B946984AD69EDAAD46 /* libSafariViewManager.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C2913F7B76847FE9FD284A5 /* libSafariViewManager.a */; };
16 | 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
17 | 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
18 | 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
19 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
20 | 13B07FBF1A68108700A75B9A /* LaunchImage.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* LaunchImage.xcassets */; };
21 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
22 | 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
23 | 1ABDD5212F4E49D1990224A5 /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = CEBA0AE944364CD4A696AEB4 /* FontAwesome.ttf */; };
24 | 2861A8759BBB4ED2879B1FF0 /* MaterialCommunityIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 4C97DBDFD1A64B50A580623C /* MaterialCommunityIcons.ttf */; };
25 | 2958AA422E2B479E9C18657B /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 728F18C99AEB481DB6ED7939 /* SimpleLineIcons.ttf */; };
26 | 2EC329B4155B4821BB20F8E8 /* MaterialIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C35103E179E04102B210A345 /* MaterialIcons.ttf */; };
27 | 77ACA9CA169844B1802773ED /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 56B5660782AF4158856DC69B /* Foundation.ttf */; };
28 | 7DA1FC1ABB0943D0B60DCE7A /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A7407BF86C6F417A88BFC411 /* libRNVectorIcons.a */; };
29 | 804C8D731F777B6B00AEDE04 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
30 | 804C8DD31F77875500AEDE04 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 804C8DD21F77875500AEDE04 /* LaunchScreen.xib */; };
31 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
32 | ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; };
33 | BA4B7F1A8BFE4B8784C92365 /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5CD9E153B22741959470A798 /* Entypo.ttf */; };
34 | C81E7DAA4C424D14B300ECCB /* Feather.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F26A2AB4722E4348A2CBDE52 /* Feather.ttf */; };
35 | CBEF897CA02D4C888FD8B41F /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9362CA914B9F436299812AA0 /* EvilIcons.ttf */; };
36 | DF1084446B9942C7973E2D11 /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E8CCE983828B479689319781 /* Ionicons.ttf */; };
37 | E318B91F7F064A74AFE19902 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1643C8BF65724071A2E88BAD /* Zocial.ttf */; };
38 | FC598745CF9E45EBBDF4AA1B /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 8074F37DC0E0408F8318CCE5 /* Octicons.ttf */; };
39 | /* End PBXBuildFile section */
40 |
41 | /* Begin PBXContainerItemProxy section */
42 | 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = {
43 | isa = PBXContainerItemProxy;
44 | containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
45 | proxyType = 2;
46 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
47 | remoteInfo = RCTActionSheet;
48 | };
49 | 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {
50 | isa = PBXContainerItemProxy;
51 | containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
52 | proxyType = 2;
53 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
54 | remoteInfo = RCTGeolocation;
55 | };
56 | 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = {
57 | isa = PBXContainerItemProxy;
58 | containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
59 | proxyType = 2;
60 | remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
61 | remoteInfo = RCTImage;
62 | };
63 | 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = {
64 | isa = PBXContainerItemProxy;
65 | containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
66 | proxyType = 2;
67 | remoteGlobalIDString = 58B511DB1A9E6C8500147676;
68 | remoteInfo = RCTNetwork;
69 | };
70 | 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = {
71 | isa = PBXContainerItemProxy;
72 | containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
73 | proxyType = 2;
74 | remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
75 | remoteInfo = RCTVibration;
76 | };
77 | 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = {
78 | isa = PBXContainerItemProxy;
79 | containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
80 | proxyType = 2;
81 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
82 | remoteInfo = RCTSettings;
83 | };
84 | 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = {
85 | isa = PBXContainerItemProxy;
86 | containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
87 | proxyType = 2;
88 | remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
89 | remoteInfo = RCTWebSocket;
90 | };
91 | 146834031AC3E56700842450 /* PBXContainerItemProxy */ = {
92 | isa = PBXContainerItemProxy;
93 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
94 | proxyType = 2;
95 | remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
96 | remoteInfo = React;
97 | };
98 | 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = {
99 | isa = PBXContainerItemProxy;
100 | containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
101 | proxyType = 2;
102 | remoteGlobalIDString = 2D2A283A1D9B042B00D4039D;
103 | remoteInfo = "RCTImage-tvOS";
104 | };
105 | 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = {
106 | isa = PBXContainerItemProxy;
107 | containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
108 | proxyType = 2;
109 | remoteGlobalIDString = 2D2A28471D9B043800D4039D;
110 | remoteInfo = "RCTLinking-tvOS";
111 | };
112 | 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
113 | isa = PBXContainerItemProxy;
114 | containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
115 | proxyType = 2;
116 | remoteGlobalIDString = 2D2A28541D9B044C00D4039D;
117 | remoteInfo = "RCTNetwork-tvOS";
118 | };
119 | 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
120 | isa = PBXContainerItemProxy;
121 | containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
122 | proxyType = 2;
123 | remoteGlobalIDString = 2D2A28611D9B046600D4039D;
124 | remoteInfo = "RCTSettings-tvOS";
125 | };
126 | 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = {
127 | isa = PBXContainerItemProxy;
128 | containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
129 | proxyType = 2;
130 | remoteGlobalIDString = 2D2A287B1D9B048500D4039D;
131 | remoteInfo = "RCTText-tvOS";
132 | };
133 | 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = {
134 | isa = PBXContainerItemProxy;
135 | containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
136 | proxyType = 2;
137 | remoteGlobalIDString = 2D2A28881D9B049200D4039D;
138 | remoteInfo = "RCTWebSocket-tvOS";
139 | };
140 | 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = {
141 | isa = PBXContainerItemProxy;
142 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
143 | proxyType = 2;
144 | remoteGlobalIDString = 2D2A28131D9B038B00D4039D;
145 | remoteInfo = "React-tvOS";
146 | };
147 | 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = {
148 | isa = PBXContainerItemProxy;
149 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
150 | proxyType = 2;
151 | remoteGlobalIDString = 3D3C059A1DE3340900C268FA;
152 | remoteInfo = yoga;
153 | };
154 | 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = {
155 | isa = PBXContainerItemProxy;
156 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
157 | proxyType = 2;
158 | remoteGlobalIDString = 3D3C06751DE3340C00C268FA;
159 | remoteInfo = "yoga-tvOS";
160 | };
161 | 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = {
162 | isa = PBXContainerItemProxy;
163 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
164 | proxyType = 2;
165 | remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4;
166 | remoteInfo = cxxreact;
167 | };
168 | 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
169 | isa = PBXContainerItemProxy;
170 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
171 | proxyType = 2;
172 | remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4;
173 | remoteInfo = "cxxreact-tvOS";
174 | };
175 | 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
176 | isa = PBXContainerItemProxy;
177 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
178 | proxyType = 2;
179 | remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4;
180 | remoteInfo = jschelpers;
181 | };
182 | 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = {
183 | isa = PBXContainerItemProxy;
184 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
185 | proxyType = 2;
186 | remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4;
187 | remoteInfo = "jschelpers-tvOS";
188 | };
189 | 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
190 | isa = PBXContainerItemProxy;
191 | containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
192 | proxyType = 2;
193 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
194 | remoteInfo = RCTAnimation;
195 | };
196 | 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = {
197 | isa = PBXContainerItemProxy;
198 | containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
199 | proxyType = 2;
200 | remoteGlobalIDString = 2D2A28201D9B03D100D4039D;
201 | remoteInfo = "RCTAnimation-tvOS";
202 | };
203 | 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
204 | isa = PBXContainerItemProxy;
205 | containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
206 | proxyType = 2;
207 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
208 | remoteInfo = RCTLinking;
209 | };
210 | 804C8D931F777B6B00AEDE04 /* PBXContainerItemProxy */ = {
211 | isa = PBXContainerItemProxy;
212 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
213 | proxyType = 2;
214 | remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7;
215 | remoteInfo = "third-party";
216 | };
217 | 804C8D951F777B6B00AEDE04 /* PBXContainerItemProxy */ = {
218 | isa = PBXContainerItemProxy;
219 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
220 | proxyType = 2;
221 | remoteGlobalIDString = 3D383D3C1EBD27B6005632C8;
222 | remoteInfo = "third-party-tvOS";
223 | };
224 | 804C8D971F777B6B00AEDE04 /* PBXContainerItemProxy */ = {
225 | isa = PBXContainerItemProxy;
226 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
227 | proxyType = 2;
228 | remoteGlobalIDString = 139D7E881E25C6D100323FB7;
229 | remoteInfo = "double-conversion";
230 | };
231 | 804C8D991F777B6B00AEDE04 /* PBXContainerItemProxy */ = {
232 | isa = PBXContainerItemProxy;
233 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
234 | proxyType = 2;
235 | remoteGlobalIDString = 3D383D621EBD27B9005632C8;
236 | remoteInfo = "double-conversion-tvOS";
237 | };
238 | 80B945101F77799500DD3A8B /* PBXContainerItemProxy */ = {
239 | isa = PBXContainerItemProxy;
240 | containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
241 | proxyType = 2;
242 | remoteGlobalIDString = ADD01A681E09402E00F6D226;
243 | remoteInfo = "RCTBlob-tvOS";
244 | };
245 | 80B945211F77799500DD3A8B /* PBXContainerItemProxy */ = {
246 | isa = PBXContainerItemProxy;
247 | containerPortal = 38946690799D41649226945C /* RNVectorIcons.xcodeproj */;
248 | proxyType = 2;
249 | remoteGlobalIDString = 5DBEB1501B18CEA900B34395;
250 | remoteInfo = RNVectorIcons;
251 | };
252 | 80B945241F77799500DD3A8B /* PBXContainerItemProxy */ = {
253 | isa = PBXContainerItemProxy;
254 | containerPortal = 36D428198DDE45749C94B68F /* SafariViewManager.xcodeproj */;
255 | proxyType = 2;
256 | remoteGlobalIDString = 134814201AA4EA6300B7C361;
257 | remoteInfo = SafariViewManager;
258 | };
259 | 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
260 | isa = PBXContainerItemProxy;
261 | containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
262 | proxyType = 2;
263 | remoteGlobalIDString = 58B5119B1A9E6C1200147676;
264 | remoteInfo = RCTText;
265 | };
266 | ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */ = {
267 | isa = PBXContainerItemProxy;
268 | containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
269 | proxyType = 2;
270 | remoteGlobalIDString = 358F4ED71D1E81A9004DF814;
271 | remoteInfo = RCTBlob;
272 | };
273 | /* End PBXContainerItemProxy section */
274 |
275 | /* Begin PBXFileReference section */
276 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; };
277 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; };
278 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; };
279 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; };
280 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; };
281 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; };
282 | 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; };
283 | 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; };
284 | 13B07F961A680F5B00A75B9A /* hnews.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = hnews.app; sourceTree = BUILT_PRODUCTS_DIR; };
285 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = hnews/AppDelegate.h; sourceTree = ""; };
286 | 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = hnews/AppDelegate.m; sourceTree = ""; };
287 | 13B07FB51A68108700A75B9A /* LaunchImage.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = LaunchImage.xcassets; path = hnews/LaunchImage.xcassets; sourceTree = ""; };
288 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = hnews/Info.plist; sourceTree = ""; };
289 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = hnews/main.m; sourceTree = ""; };
290 | 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; };
291 | 1643C8BF65724071A2E88BAD /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = ""; };
292 | 36D428198DDE45749C94B68F /* SafariViewManager.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = SafariViewManager.xcodeproj; path = "../node_modules/react-native-safari-view/SafariViewManager.xcodeproj"; sourceTree = ""; };
293 | 38946690799D41649226945C /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = ""; };
294 | 4C97DBDFD1A64B50A580623C /* MaterialCommunityIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialCommunityIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf"; sourceTree = ""; };
295 | 56B5660782AF4158856DC69B /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = ""; };
296 | 5CD9E153B22741959470A798 /* Entypo.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = ""; };
297 | 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; };
298 | 728F18C99AEB481DB6ED7939 /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = SimpleLineIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf"; sourceTree = ""; };
299 | 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; };
300 | 7C2913F7B76847FE9FD284A5 /* libSafariViewManager.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libSafariViewManager.a; sourceTree = ""; };
301 | 804C8DD21F77875500AEDE04 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; };
302 | 8074F37DC0E0408F8318CCE5 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = ""; };
303 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; };
304 | 9362CA914B9F436299812AA0 /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = ""; };
305 | A7407BF86C6F417A88BFC411 /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = ""; };
306 | ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = ""; };
307 | C35103E179E04102B210A345 /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = ""; };
308 | CEBA0AE944364CD4A696AEB4 /* FontAwesome.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf"; sourceTree = ""; };
309 | E8CCE983828B479689319781 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = ""; };
310 | F26A2AB4722E4348A2CBDE52 /* Feather.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Feather.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Feather.ttf"; sourceTree = ""; };
311 | /* End PBXFileReference section */
312 |
313 | /* Begin PBXFrameworksBuildPhase section */
314 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
315 | isa = PBXFrameworksBuildPhase;
316 | buildActionMask = 2147483647;
317 | files = (
318 | ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */,
319 | 804C8D731F777B6B00AEDE04 /* libRCTAnimation.a in Frameworks */,
320 | 146834051AC3E58100842450 /* libReact.a in Frameworks */,
321 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
322 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
323 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
324 | 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
325 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
326 | 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,
327 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
328 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
329 | 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
330 | 04E204B946984AD69EDAAD46 /* libSafariViewManager.a in Frameworks */,
331 | 7DA1FC1ABB0943D0B60DCE7A /* libRNVectorIcons.a in Frameworks */,
332 | );
333 | runOnlyForDeploymentPostprocessing = 0;
334 | };
335 | /* End PBXFrameworksBuildPhase section */
336 |
337 | /* Begin PBXGroup section */
338 | 00C302A81ABCB8CE00DB3ED1 /* Products */ = {
339 | isa = PBXGroup;
340 | children = (
341 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */,
342 | );
343 | name = Products;
344 | sourceTree = "";
345 | };
346 | 00C302B61ABCB90400DB3ED1 /* Products */ = {
347 | isa = PBXGroup;
348 | children = (
349 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */,
350 | );
351 | name = Products;
352 | sourceTree = "";
353 | };
354 | 00C302BC1ABCB91800DB3ED1 /* Products */ = {
355 | isa = PBXGroup;
356 | children = (
357 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,
358 | 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */,
359 | );
360 | name = Products;
361 | sourceTree = "";
362 | };
363 | 00C302D41ABCB9D200DB3ED1 /* Products */ = {
364 | isa = PBXGroup;
365 | children = (
366 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,
367 | 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */,
368 | );
369 | name = Products;
370 | sourceTree = "";
371 | };
372 | 00C302E01ABCB9EE00DB3ED1 /* Products */ = {
373 | isa = PBXGroup;
374 | children = (
375 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */,
376 | );
377 | name = Products;
378 | sourceTree = "";
379 | };
380 | 139105B71AF99BAD00B5F7CC /* Products */ = {
381 | isa = PBXGroup;
382 | children = (
383 | 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */,
384 | 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */,
385 | );
386 | name = Products;
387 | sourceTree = "";
388 | };
389 | 139FDEE71B06529A00C62182 /* Products */ = {
390 | isa = PBXGroup;
391 | children = (
392 | 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
393 | 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */,
394 | );
395 | name = Products;
396 | sourceTree = "";
397 | };
398 | 13B07FAE1A68108700A75B9A /* hnews */ = {
399 | isa = PBXGroup;
400 | children = (
401 | 804C8DD21F77875500AEDE04 /* LaunchScreen.xib */,
402 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */,
403 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
404 | 13B07FB01A68108700A75B9A /* AppDelegate.m */,
405 | 13B07FB51A68108700A75B9A /* LaunchImage.xcassets */,
406 | 13B07FB61A68108700A75B9A /* Info.plist */,
407 | 13B07FB71A68108700A75B9A /* main.m */,
408 | );
409 | name = hnews;
410 | sourceTree = "";
411 | };
412 | 146834001AC3E56700842450 /* Products */ = {
413 | isa = PBXGroup;
414 | children = (
415 | 146834041AC3E56700842450 /* libReact.a */,
416 | 3DAD3EA31DF850E9000B6D8A /* libReact.a */,
417 | 3DAD3EA51DF850E9000B6D8A /* libyoga.a */,
418 | 3DAD3EA71DF850E9000B6D8A /* libyoga.a */,
419 | 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */,
420 | 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */,
421 | 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */,
422 | 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */,
423 | 804C8D941F777B6B00AEDE04 /* libthird-party.a */,
424 | 804C8D961F777B6B00AEDE04 /* libthird-party.a */,
425 | 804C8D981F777B6B00AEDE04 /* libdouble-conversion.a */,
426 | 804C8D9A1F777B6B00AEDE04 /* libdouble-conversion.a */,
427 | );
428 | name = Products;
429 | sourceTree = "";
430 | };
431 | 5E91572E1DD0AC6500FF2AA8 /* Products */ = {
432 | isa = PBXGroup;
433 | children = (
434 | 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */,
435 | 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */,
436 | );
437 | name = Products;
438 | sourceTree = "";
439 | };
440 | 66051CFE206D4A0E8A134B4B /* Resources */ = {
441 | isa = PBXGroup;
442 | children = (
443 | 5CD9E153B22741959470A798 /* Entypo.ttf */,
444 | 9362CA914B9F436299812AA0 /* EvilIcons.ttf */,
445 | F26A2AB4722E4348A2CBDE52 /* Feather.ttf */,
446 | CEBA0AE944364CD4A696AEB4 /* FontAwesome.ttf */,
447 | 56B5660782AF4158856DC69B /* Foundation.ttf */,
448 | E8CCE983828B479689319781 /* Ionicons.ttf */,
449 | 4C97DBDFD1A64B50A580623C /* MaterialCommunityIcons.ttf */,
450 | C35103E179E04102B210A345 /* MaterialIcons.ttf */,
451 | 8074F37DC0E0408F8318CCE5 /* Octicons.ttf */,
452 | 728F18C99AEB481DB6ED7939 /* SimpleLineIcons.ttf */,
453 | 1643C8BF65724071A2E88BAD /* Zocial.ttf */,
454 | );
455 | name = Resources;
456 | sourceTree = "";
457 | };
458 | 78C398B11ACF4ADC00677621 /* Products */ = {
459 | isa = PBXGroup;
460 | children = (
461 | 78C398B91ACF4ADC00677621 /* libRCTLinking.a */,
462 | 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */,
463 | );
464 | name = Products;
465 | sourceTree = "";
466 | };
467 | 80B945071F77799400DD3A8B /* Products */ = {
468 | isa = PBXGroup;
469 | children = (
470 | 80B945251F77799500DD3A8B /* libSafariViewManager.a */,
471 | );
472 | name = Products;
473 | sourceTree = "";
474 | };
475 | 80B945091F77799400DD3A8B /* Products */ = {
476 | isa = PBXGroup;
477 | children = (
478 | 80B945221F77799500DD3A8B /* libRNVectorIcons.a */,
479 | );
480 | name = Products;
481 | sourceTree = "";
482 | };
483 | 80FD076A1F78662500D8507E /* Recovered References */ = {
484 | isa = PBXGroup;
485 | children = (
486 | 7C2913F7B76847FE9FD284A5 /* libSafariViewManager.a */,
487 | A7407BF86C6F417A88BFC411 /* libRNVectorIcons.a */,
488 | );
489 | name = "Recovered References";
490 | sourceTree = "";
491 | };
492 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
493 | isa = PBXGroup;
494 | children = (
495 | 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */,
496 | 146833FF1AC3E56700842450 /* React.xcodeproj */,
497 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
498 | ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */,
499 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
500 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,
501 | 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */,
502 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */,
503 | 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */,
504 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
505 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
506 | 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
507 | 36D428198DDE45749C94B68F /* SafariViewManager.xcodeproj */,
508 | 38946690799D41649226945C /* RNVectorIcons.xcodeproj */,
509 | );
510 | name = Libraries;
511 | sourceTree = "";
512 | };
513 | 832341B11AAA6A8300B99B32 /* Products */ = {
514 | isa = PBXGroup;
515 | children = (
516 | 832341B51AAA6A8300B99B32 /* libRCTText.a */,
517 | 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */,
518 | );
519 | name = Products;
520 | sourceTree = "";
521 | };
522 | 83CBB9F61A601CBA00E9B192 = {
523 | isa = PBXGroup;
524 | children = (
525 | 13B07FAE1A68108700A75B9A /* hnews */,
526 | 832341AE1AAA6A7D00B99B32 /* Libraries */,
527 | 83CBBA001A601CBA00E9B192 /* Products */,
528 | 66051CFE206D4A0E8A134B4B /* Resources */,
529 | 80FD076A1F78662500D8507E /* Recovered References */,
530 | );
531 | indentWidth = 2;
532 | sourceTree = "";
533 | tabWidth = 2;
534 | usesTabs = 0;
535 | };
536 | 83CBBA001A601CBA00E9B192 /* Products */ = {
537 | isa = PBXGroup;
538 | children = (
539 | 13B07F961A680F5B00A75B9A /* hnews.app */,
540 | );
541 | name = Products;
542 | sourceTree = "";
543 | };
544 | ADBDB9201DFEBF0600ED6528 /* Products */ = {
545 | isa = PBXGroup;
546 | children = (
547 | ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */,
548 | 80B945111F77799500DD3A8B /* libRCTBlob-tvOS.a */,
549 | );
550 | name = Products;
551 | sourceTree = "";
552 | };
553 | /* End PBXGroup section */
554 |
555 | /* Begin PBXNativeTarget section */
556 | 13B07F861A680F5B00A75B9A /* hnews */ = {
557 | isa = PBXNativeTarget;
558 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "hnews" */;
559 | buildPhases = (
560 | 13B07F871A680F5B00A75B9A /* Sources */,
561 | 13B07F8C1A680F5B00A75B9A /* Frameworks */,
562 | 13B07F8E1A680F5B00A75B9A /* Resources */,
563 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
564 | );
565 | buildRules = (
566 | );
567 | dependencies = (
568 | );
569 | name = hnews;
570 | productName = "Hello World";
571 | productReference = 13B07F961A680F5B00A75B9A /* hnews.app */;
572 | productType = "com.apple.product-type.application";
573 | };
574 | /* End PBXNativeTarget section */
575 |
576 | /* Begin PBXProject section */
577 | 83CBB9F71A601CBA00E9B192 /* Project object */ = {
578 | isa = PBXProject;
579 | attributes = {
580 | LastUpgradeCheck = 0900;
581 | ORGANIZATIONNAME = Facebook;
582 | TargetAttributes = {
583 | 13B07F861A680F5B00A75B9A = {
584 | DevelopmentTeam = 348S7987BH;
585 | };
586 | };
587 | };
588 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "hnews" */;
589 | compatibilityVersion = "Xcode 3.2";
590 | developmentRegion = English;
591 | hasScannedForEncodings = 0;
592 | knownRegions = (
593 | en,
594 | Base,
595 | );
596 | mainGroup = 83CBB9F61A601CBA00E9B192;
597 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
598 | projectDirPath = "";
599 | projectReferences = (
600 | {
601 | ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
602 | ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
603 | },
604 | {
605 | ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */;
606 | ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */;
607 | },
608 | {
609 | ProductGroup = ADBDB9201DFEBF0600ED6528 /* Products */;
610 | ProjectRef = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */;
611 | },
612 | {
613 | ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
614 | ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
615 | },
616 | {
617 | ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;
618 | ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
619 | },
620 | {
621 | ProductGroup = 78C398B11ACF4ADC00677621 /* Products */;
622 | ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
623 | },
624 | {
625 | ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;
626 | ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
627 | },
628 | {
629 | ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */;
630 | ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
631 | },
632 | {
633 | ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
634 | ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
635 | },
636 | {
637 | ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
638 | ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
639 | },
640 | {
641 | ProductGroup = 139FDEE71B06529A00C62182 /* Products */;
642 | ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
643 | },
644 | {
645 | ProductGroup = 146834001AC3E56700842450 /* Products */;
646 | ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
647 | },
648 | {
649 | ProductGroup = 80B945091F77799400DD3A8B /* Products */;
650 | ProjectRef = 38946690799D41649226945C /* RNVectorIcons.xcodeproj */;
651 | },
652 | {
653 | ProductGroup = 80B945071F77799400DD3A8B /* Products */;
654 | ProjectRef = 36D428198DDE45749C94B68F /* SafariViewManager.xcodeproj */;
655 | },
656 | );
657 | projectRoot = "";
658 | targets = (
659 | 13B07F861A680F5B00A75B9A /* hnews */,
660 | );
661 | };
662 | /* End PBXProject section */
663 |
664 | /* Begin PBXReferenceProxy section */
665 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = {
666 | isa = PBXReferenceProxy;
667 | fileType = archive.ar;
668 | path = libRCTActionSheet.a;
669 | remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;
670 | sourceTree = BUILT_PRODUCTS_DIR;
671 | };
672 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {
673 | isa = PBXReferenceProxy;
674 | fileType = archive.ar;
675 | path = libRCTGeolocation.a;
676 | remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */;
677 | sourceTree = BUILT_PRODUCTS_DIR;
678 | };
679 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = {
680 | isa = PBXReferenceProxy;
681 | fileType = archive.ar;
682 | path = libRCTImage.a;
683 | remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */;
684 | sourceTree = BUILT_PRODUCTS_DIR;
685 | };
686 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = {
687 | isa = PBXReferenceProxy;
688 | fileType = archive.ar;
689 | path = libRCTNetwork.a;
690 | remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */;
691 | sourceTree = BUILT_PRODUCTS_DIR;
692 | };
693 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = {
694 | isa = PBXReferenceProxy;
695 | fileType = archive.ar;
696 | path = libRCTVibration.a;
697 | remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */;
698 | sourceTree = BUILT_PRODUCTS_DIR;
699 | };
700 | 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = {
701 | isa = PBXReferenceProxy;
702 | fileType = archive.ar;
703 | path = libRCTSettings.a;
704 | remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */;
705 | sourceTree = BUILT_PRODUCTS_DIR;
706 | };
707 | 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = {
708 | isa = PBXReferenceProxy;
709 | fileType = archive.ar;
710 | path = libRCTWebSocket.a;
711 | remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */;
712 | sourceTree = BUILT_PRODUCTS_DIR;
713 | };
714 | 146834041AC3E56700842450 /* libReact.a */ = {
715 | isa = PBXReferenceProxy;
716 | fileType = archive.ar;
717 | path = libReact.a;
718 | remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
719 | sourceTree = BUILT_PRODUCTS_DIR;
720 | };
721 | 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = {
722 | isa = PBXReferenceProxy;
723 | fileType = archive.ar;
724 | path = "libRCTImage-tvOS.a";
725 | remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */;
726 | sourceTree = BUILT_PRODUCTS_DIR;
727 | };
728 | 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = {
729 | isa = PBXReferenceProxy;
730 | fileType = archive.ar;
731 | path = "libRCTLinking-tvOS.a";
732 | remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */;
733 | sourceTree = BUILT_PRODUCTS_DIR;
734 | };
735 | 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = {
736 | isa = PBXReferenceProxy;
737 | fileType = archive.ar;
738 | path = "libRCTNetwork-tvOS.a";
739 | remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */;
740 | sourceTree = BUILT_PRODUCTS_DIR;
741 | };
742 | 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = {
743 | isa = PBXReferenceProxy;
744 | fileType = archive.ar;
745 | path = "libRCTSettings-tvOS.a";
746 | remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */;
747 | sourceTree = BUILT_PRODUCTS_DIR;
748 | };
749 | 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = {
750 | isa = PBXReferenceProxy;
751 | fileType = archive.ar;
752 | path = "libRCTText-tvOS.a";
753 | remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */;
754 | sourceTree = BUILT_PRODUCTS_DIR;
755 | };
756 | 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = {
757 | isa = PBXReferenceProxy;
758 | fileType = archive.ar;
759 | path = "libRCTWebSocket-tvOS.a";
760 | remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */;
761 | sourceTree = BUILT_PRODUCTS_DIR;
762 | };
763 | 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = {
764 | isa = PBXReferenceProxy;
765 | fileType = archive.ar;
766 | path = libReact.a;
767 | remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */;
768 | sourceTree = BUILT_PRODUCTS_DIR;
769 | };
770 | 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = {
771 | isa = PBXReferenceProxy;
772 | fileType = archive.ar;
773 | path = libyoga.a;
774 | remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */;
775 | sourceTree = BUILT_PRODUCTS_DIR;
776 | };
777 | 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = {
778 | isa = PBXReferenceProxy;
779 | fileType = archive.ar;
780 | path = libyoga.a;
781 | remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */;
782 | sourceTree = BUILT_PRODUCTS_DIR;
783 | };
784 | 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = {
785 | isa = PBXReferenceProxy;
786 | fileType = archive.ar;
787 | path = libcxxreact.a;
788 | remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */;
789 | sourceTree = BUILT_PRODUCTS_DIR;
790 | };
791 | 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = {
792 | isa = PBXReferenceProxy;
793 | fileType = archive.ar;
794 | path = libcxxreact.a;
795 | remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */;
796 | sourceTree = BUILT_PRODUCTS_DIR;
797 | };
798 | 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = {
799 | isa = PBXReferenceProxy;
800 | fileType = archive.ar;
801 | path = libjschelpers.a;
802 | remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */;
803 | sourceTree = BUILT_PRODUCTS_DIR;
804 | };
805 | 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = {
806 | isa = PBXReferenceProxy;
807 | fileType = archive.ar;
808 | path = libjschelpers.a;
809 | remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */;
810 | sourceTree = BUILT_PRODUCTS_DIR;
811 | };
812 | 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
813 | isa = PBXReferenceProxy;
814 | fileType = archive.ar;
815 | path = libRCTAnimation.a;
816 | remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
817 | sourceTree = BUILT_PRODUCTS_DIR;
818 | };
819 | 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
820 | isa = PBXReferenceProxy;
821 | fileType = archive.ar;
822 | path = libRCTAnimation.a;
823 | remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */;
824 | sourceTree = BUILT_PRODUCTS_DIR;
825 | };
826 | 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
827 | isa = PBXReferenceProxy;
828 | fileType = archive.ar;
829 | path = libRCTLinking.a;
830 | remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */;
831 | sourceTree = BUILT_PRODUCTS_DIR;
832 | };
833 | 804C8D941F777B6B00AEDE04 /* libthird-party.a */ = {
834 | isa = PBXReferenceProxy;
835 | fileType = archive.ar;
836 | path = "libthird-party.a";
837 | remoteRef = 804C8D931F777B6B00AEDE04 /* PBXContainerItemProxy */;
838 | sourceTree = BUILT_PRODUCTS_DIR;
839 | };
840 | 804C8D961F777B6B00AEDE04 /* libthird-party.a */ = {
841 | isa = PBXReferenceProxy;
842 | fileType = archive.ar;
843 | path = "libthird-party.a";
844 | remoteRef = 804C8D951F777B6B00AEDE04 /* PBXContainerItemProxy */;
845 | sourceTree = BUILT_PRODUCTS_DIR;
846 | };
847 | 804C8D981F777B6B00AEDE04 /* libdouble-conversion.a */ = {
848 | isa = PBXReferenceProxy;
849 | fileType = archive.ar;
850 | path = "libdouble-conversion.a";
851 | remoteRef = 804C8D971F777B6B00AEDE04 /* PBXContainerItemProxy */;
852 | sourceTree = BUILT_PRODUCTS_DIR;
853 | };
854 | 804C8D9A1F777B6B00AEDE04 /* libdouble-conversion.a */ = {
855 | isa = PBXReferenceProxy;
856 | fileType = archive.ar;
857 | path = "libdouble-conversion.a";
858 | remoteRef = 804C8D991F777B6B00AEDE04 /* PBXContainerItemProxy */;
859 | sourceTree = BUILT_PRODUCTS_DIR;
860 | };
861 | 80B945111F77799500DD3A8B /* libRCTBlob-tvOS.a */ = {
862 | isa = PBXReferenceProxy;
863 | fileType = archive.ar;
864 | path = "libRCTBlob-tvOS.a";
865 | remoteRef = 80B945101F77799500DD3A8B /* PBXContainerItemProxy */;
866 | sourceTree = BUILT_PRODUCTS_DIR;
867 | };
868 | 80B945221F77799500DD3A8B /* libRNVectorIcons.a */ = {
869 | isa = PBXReferenceProxy;
870 | fileType = archive.ar;
871 | path = libRNVectorIcons.a;
872 | remoteRef = 80B945211F77799500DD3A8B /* PBXContainerItemProxy */;
873 | sourceTree = BUILT_PRODUCTS_DIR;
874 | };
875 | 80B945251F77799500DD3A8B /* libSafariViewManager.a */ = {
876 | isa = PBXReferenceProxy;
877 | fileType = archive.ar;
878 | path = libSafariViewManager.a;
879 | remoteRef = 80B945241F77799500DD3A8B /* PBXContainerItemProxy */;
880 | sourceTree = BUILT_PRODUCTS_DIR;
881 | };
882 | 832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
883 | isa = PBXReferenceProxy;
884 | fileType = archive.ar;
885 | path = libRCTText.a;
886 | remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
887 | sourceTree = BUILT_PRODUCTS_DIR;
888 | };
889 | ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */ = {
890 | isa = PBXReferenceProxy;
891 | fileType = archive.ar;
892 | path = libRCTBlob.a;
893 | remoteRef = ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */;
894 | sourceTree = BUILT_PRODUCTS_DIR;
895 | };
896 | /* End PBXReferenceProxy section */
897 |
898 | /* Begin PBXResourcesBuildPhase section */
899 | 13B07F8E1A680F5B00A75B9A /* Resources */ = {
900 | isa = PBXResourcesBuildPhase;
901 | buildActionMask = 2147483647;
902 | files = (
903 | 13B07FBF1A68108700A75B9A /* LaunchImage.xcassets in Resources */,
904 | BA4B7F1A8BFE4B8784C92365 /* Entypo.ttf in Resources */,
905 | CBEF897CA02D4C888FD8B41F /* EvilIcons.ttf in Resources */,
906 | C81E7DAA4C424D14B300ECCB /* Feather.ttf in Resources */,
907 | 1ABDD5212F4E49D1990224A5 /* FontAwesome.ttf in Resources */,
908 | 77ACA9CA169844B1802773ED /* Foundation.ttf in Resources */,
909 | DF1084446B9942C7973E2D11 /* Ionicons.ttf in Resources */,
910 | 2861A8759BBB4ED2879B1FF0 /* MaterialCommunityIcons.ttf in Resources */,
911 | 2EC329B4155B4821BB20F8E8 /* MaterialIcons.ttf in Resources */,
912 | 804C8DD31F77875500AEDE04 /* LaunchScreen.xib in Resources */,
913 | FC598745CF9E45EBBDF4AA1B /* Octicons.ttf in Resources */,
914 | 2958AA422E2B479E9C18657B /* SimpleLineIcons.ttf in Resources */,
915 | E318B91F7F064A74AFE19902 /* Zocial.ttf in Resources */,
916 | );
917 | runOnlyForDeploymentPostprocessing = 0;
918 | };
919 | /* End PBXResourcesBuildPhase section */
920 |
921 | /* Begin PBXShellScriptBuildPhase section */
922 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
923 | isa = PBXShellScriptBuildPhase;
924 | buildActionMask = 2147483647;
925 | files = (
926 | );
927 | inputPaths = (
928 | );
929 | name = "Bundle React Native code and images";
930 | outputPaths = (
931 | );
932 | runOnlyForDeploymentPostprocessing = 0;
933 | shellPath = /bin/sh;
934 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
935 | };
936 | /* End PBXShellScriptBuildPhase section */
937 |
938 | /* Begin PBXSourcesBuildPhase section */
939 | 13B07F871A680F5B00A75B9A /* Sources */ = {
940 | isa = PBXSourcesBuildPhase;
941 | buildActionMask = 2147483647;
942 | files = (
943 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
944 | 13B07FC11A68108700A75B9A /* main.m in Sources */,
945 | );
946 | runOnlyForDeploymentPostprocessing = 0;
947 | };
948 | /* End PBXSourcesBuildPhase section */
949 |
950 | /* Begin XCBuildConfiguration section */
951 | 13B07F941A680F5B00A75B9A /* Debug */ = {
952 | isa = XCBuildConfiguration;
953 | buildSettings = {
954 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
955 | CURRENT_PROJECT_VERSION = 1;
956 | DEAD_CODE_STRIPPING = NO;
957 | DEVELOPMENT_TEAM = 348S7987BH;
958 | HEADER_SEARCH_PATHS = (
959 | "$(inherited)",
960 | "$(SRCROOT)/../node_modules/react-native-safari-view",
961 | "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
962 | );
963 | INFOPLIST_FILE = hnews/Info.plist;
964 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
965 | OTHER_LDFLAGS = (
966 | "$(inherited)",
967 | "-ObjC",
968 | "-lc++",
969 | );
970 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
971 | PRODUCT_NAME = hnews;
972 | VERSIONING_SYSTEM = "apple-generic";
973 | };
974 | name = Debug;
975 | };
976 | 13B07F951A680F5B00A75B9A /* Release */ = {
977 | isa = XCBuildConfiguration;
978 | buildSettings = {
979 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
980 | CURRENT_PROJECT_VERSION = 1;
981 | DEVELOPMENT_TEAM = 348S7987BH;
982 | HEADER_SEARCH_PATHS = (
983 | "$(inherited)",
984 | "$(SRCROOT)/../node_modules/react-native-safari-view",
985 | "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
986 | );
987 | INFOPLIST_FILE = hnews/Info.plist;
988 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
989 | OTHER_LDFLAGS = (
990 | "$(inherited)",
991 | "-ObjC",
992 | "-lc++",
993 | );
994 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
995 | PRODUCT_NAME = hnews;
996 | VERSIONING_SYSTEM = "apple-generic";
997 | };
998 | name = Release;
999 | };
1000 | 83CBBA201A601CBA00E9B192 /* Debug */ = {
1001 | isa = XCBuildConfiguration;
1002 | buildSettings = {
1003 | ALWAYS_SEARCH_USER_PATHS = NO;
1004 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
1005 | CLANG_CXX_LIBRARY = "libc++";
1006 | CLANG_ENABLE_MODULES = YES;
1007 | CLANG_ENABLE_OBJC_ARC = YES;
1008 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
1009 | CLANG_WARN_BOOL_CONVERSION = YES;
1010 | CLANG_WARN_COMMA = YES;
1011 | CLANG_WARN_CONSTANT_CONVERSION = YES;
1012 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
1013 | CLANG_WARN_EMPTY_BODY = YES;
1014 | CLANG_WARN_ENUM_CONVERSION = YES;
1015 | CLANG_WARN_INFINITE_RECURSION = YES;
1016 | CLANG_WARN_INT_CONVERSION = YES;
1017 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
1018 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
1019 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
1020 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
1021 | CLANG_WARN_STRICT_PROTOTYPES = YES;
1022 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
1023 | CLANG_WARN_UNREACHABLE_CODE = YES;
1024 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
1025 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
1026 | COPY_PHASE_STRIP = NO;
1027 | ENABLE_STRICT_OBJC_MSGSEND = YES;
1028 | ENABLE_TESTABILITY = YES;
1029 | GCC_C_LANGUAGE_STANDARD = gnu99;
1030 | GCC_DYNAMIC_NO_PIC = NO;
1031 | GCC_NO_COMMON_BLOCKS = YES;
1032 | GCC_OPTIMIZATION_LEVEL = 0;
1033 | GCC_PREPROCESSOR_DEFINITIONS = (
1034 | "DEBUG=1",
1035 | "$(inherited)",
1036 | );
1037 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
1038 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
1039 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
1040 | GCC_WARN_UNDECLARED_SELECTOR = YES;
1041 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
1042 | GCC_WARN_UNUSED_FUNCTION = YES;
1043 | GCC_WARN_UNUSED_VARIABLE = YES;
1044 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
1045 | MTL_ENABLE_DEBUG_INFO = YES;
1046 | ONLY_ACTIVE_ARCH = YES;
1047 | SDKROOT = iphoneos;
1048 | };
1049 | name = Debug;
1050 | };
1051 | 83CBBA211A601CBA00E9B192 /* Release */ = {
1052 | isa = XCBuildConfiguration;
1053 | buildSettings = {
1054 | ALWAYS_SEARCH_USER_PATHS = NO;
1055 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
1056 | CLANG_CXX_LIBRARY = "libc++";
1057 | CLANG_ENABLE_MODULES = YES;
1058 | CLANG_ENABLE_OBJC_ARC = YES;
1059 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
1060 | CLANG_WARN_BOOL_CONVERSION = YES;
1061 | CLANG_WARN_COMMA = YES;
1062 | CLANG_WARN_CONSTANT_CONVERSION = YES;
1063 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
1064 | CLANG_WARN_EMPTY_BODY = YES;
1065 | CLANG_WARN_ENUM_CONVERSION = YES;
1066 | CLANG_WARN_INFINITE_RECURSION = YES;
1067 | CLANG_WARN_INT_CONVERSION = YES;
1068 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
1069 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
1070 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
1071 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
1072 | CLANG_WARN_STRICT_PROTOTYPES = YES;
1073 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
1074 | CLANG_WARN_UNREACHABLE_CODE = YES;
1075 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
1076 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
1077 | COPY_PHASE_STRIP = YES;
1078 | ENABLE_NS_ASSERTIONS = NO;
1079 | ENABLE_STRICT_OBJC_MSGSEND = YES;
1080 | GCC_C_LANGUAGE_STANDARD = gnu99;
1081 | GCC_NO_COMMON_BLOCKS = YES;
1082 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
1083 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
1084 | GCC_WARN_UNDECLARED_SELECTOR = YES;
1085 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
1086 | GCC_WARN_UNUSED_FUNCTION = YES;
1087 | GCC_WARN_UNUSED_VARIABLE = YES;
1088 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
1089 | MTL_ENABLE_DEBUG_INFO = NO;
1090 | SDKROOT = iphoneos;
1091 | VALIDATE_PRODUCT = YES;
1092 | };
1093 | name = Release;
1094 | };
1095 | /* End XCBuildConfiguration section */
1096 |
1097 | /* Begin XCConfigurationList section */
1098 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "hnews" */ = {
1099 | isa = XCConfigurationList;
1100 | buildConfigurations = (
1101 | 13B07F941A680F5B00A75B9A /* Debug */,
1102 | 13B07F951A680F5B00A75B9A /* Release */,
1103 | );
1104 | defaultConfigurationIsVisible = 0;
1105 | defaultConfigurationName = Release;
1106 | };
1107 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "hnews" */ = {
1108 | isa = XCConfigurationList;
1109 | buildConfigurations = (
1110 | 83CBBA201A601CBA00E9B192 /* Debug */,
1111 | 83CBBA211A601CBA00E9B192 /* Release */,
1112 | );
1113 | defaultConfigurationIsVisible = 0;
1114 | defaultConfigurationName = Release;
1115 | };
1116 | /* End XCConfigurationList section */
1117 | };
1118 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
1119 | }
1120 |
--------------------------------------------------------------------------------