diff --git a/app.json b/app.json
index c15f0bb4..2da1417b 100644
--- a/app.json
+++ b/app.json
@@ -4,7 +4,7 @@
"description": "The Stanford Daily Mobile App",
"slug": "StanfordDaily",
"privacy": "public",
- "version": "1.3.2",
+ "version": "1.4.0",
"platforms": [
"ios",
"android"
@@ -31,14 +31,14 @@
],
"ios": {
"bundleIdentifier": "com.Stanford.Daily.App",
- "buildNumber": "14",
+ "buildNumber": "15",
"appStoreUrl": "https://itunes.apple.com/app/stanford-daily/id1341270063",
"supportsTablet": true
},
"android": {
"package": "com.Stanford.Daily.App",
"googleServicesFile": "./google-services.json",
- "versionCode": 14,
+ "versionCode": 15,
"playStoreUrl": "https://play.google.com/store/apps/details?id=com.Stanford.Daily.App",
"permissions": [
"ACCESS_COARSE_LOCATION",
diff --git a/app/HTML.js b/app/HTML.js
index 78e057dc..8f52d0ca 100644
--- a/app/HTML.js
+++ b/app/HTML.js
@@ -33,7 +33,7 @@ const renderers = {
else if (typeof htmlAttribs.class !== 'undefined' && htmlAttribs.class.includes("wp-block-embed__wrapper") && typeof passProps.rawChildren[0].attribs.title !== 'undefined' && passProps.rawChildren[0].attribs.title.includes("Spotify Embed")) { // hacky way of displaying Spotify players for podcasts
let uri = passProps.rawChildren[0].attribs.src;
return (
-
+
)
}
else {
diff --git a/app/config/router.js b/app/config/router.js
index e3e514a4..21553705 100644
--- a/app/config/router.js
+++ b/app/config/router.js
@@ -85,6 +85,7 @@ export const Tabs = createBottomTabNavigator({
inactiveTintColor: '#000000',
inactiveBackgroundColor: 'white',
activeBackgroundColor: 'white',
+ keyboardHidesTabBar: true,
labelStyle: {
fontFamily: "Open Sans", // FONTS.PT_SERIF
marginBottom: labelBottomMargin
@@ -98,7 +99,7 @@ export const Tabs = createBottomTabNavigator({
marginBottom: iphone_x ? -34 : 0
}
},
- lazy: true
+ lazy: true,
});
const Root = createStackNavigator({
diff --git a/app/helper/PushNotification.js b/app/helper/PushNotification.js
index 46112df7..22c63105 100644
--- a/app/helper/PushNotification.js
+++ b/app/helper/PushNotification.js
@@ -7,7 +7,7 @@ export async function registerForPushNotificationsAsync() {
Permissions.NOTIFICATIONS
);
let finalStatus = existingStatus;
-
+
// only ask if permissions have not already been determined, because
// iOS won't necessarily prompt the user a second time.
if (existingStatus !== 'granted') {
diff --git a/app/screens/FollowInfoStorage.js b/app/screens/FollowInfoStorage.js
index 97904cc0..958ba4d5 100644
--- a/app/screens/FollowInfoStorage.js
+++ b/app/screens/FollowInfoStorage.js
@@ -1,8 +1,25 @@
-import {AsyncStorage} from "react-native"
+import { AsyncStorage, Linking, Alert } from "react-native"
import { STRINGS } from '../assets/constants.js'
import { Notifications } from "expo";
+import * as Permissions from 'expo-permissions';
export async function getToken() {
+ const { status: existingStatus } = await Permissions.getAsync(
+ Permissions.NOTIFICATIONS
+ );
+ // if push notifications aren't on, alert user and give them the option to turn them on
+ if (existingStatus !== 'granted') { // code adapted from https://stackoverflow.com/questions/59980039/permissions-askasync-not-working-as-expected
+ Alert.alert(
+ "Please turn on notifications for this app in settings",
+ "",
+ [
+ { text: "Cancel" },
+ { text: "Settings", onPress: () => Linking.openURL("app-settings:") },
+ ],
+ { cancelable: false }
+ );
+ }
+
let token = await Notifications.getExpoPushTokenAsync();
if (__DEV__) {
console.log(token);
@@ -34,7 +51,7 @@ export async function followCategory(category_id) {
}
export async function unfollowCategory(category_id) {
- let categories_followed = await getCategoriesFollowed();
+ let categories_followed = await getCategoriesFollowed();
var index = categories_followed.indexOf(category_id);
if (index !== -1) categories_followed.splice(index, 1); // remove category_id from list
await updateBackend();
@@ -42,14 +59,14 @@ export async function unfollowCategory(category_id) {
}
export async function followAuthor(author_id) {
- let authors_followed = await getAuthorsFollowed();
+ let authors_followed = await getAuthorsFollowed();
authors_followed.push(author_id); // add author_id to authors_followed
await updateBackend();
return await AsyncStorage.setItem('authors_followed', JSON.stringify(authors_followed));
}
export async function unfollowAuthor(author_id) {
- let authors_followed = await getAuthorsFollowed();
+ let authors_followed = await getAuthorsFollowed();
var index = authors_followed.indexOf(author_id);
if (index !== -1) authors_followed.splice(index, 1); // remove author_id from list
await updateBackend();
@@ -57,16 +74,16 @@ export async function unfollowAuthor(author_id) {
}
export async function followLocation(location_id) {
- let locations_followed = await getLocationsFollowed();
- locations_followed.push(location_id);
+ let locations_followed = await getLocationsFollowed();
+ locations_followed.push(location_id);
await updateBackend();
return await AsyncStorage.setItem('locations_followed', JSON.stringify(locations_followed));
}
export async function unfollowLocation(location_id) {
- let locations_followed = await getLocationsFollowed();
+ let locations_followed = await getLocationsFollowed();
var index = locations_followed.indexOf(location_id);
- if (index !== -1) locations_followed.splice(index, 1);
+ if (index !== -1) locations_followed.splice(index, 1);
await updateBackend();
return await AsyncStorage.setItem('locations_followed', JSON.stringify(locations_followed));
}
@@ -93,14 +110,14 @@ export async function isFollowingLocation(location_id) {
}
export async function addNotificationSetting(notification_id) {
- let notification_settings = await getNotificationSettings();
- notification_settings.push(notification_id);
+ let notification_settings = await getNotificationSettings();
+ notification_settings.push(notification_id);
await updateBackend();
return await AsyncStorage.setItem('notification_settings', JSON.stringify(notification_settings));
}
export async function removeNotificationSetting(notification_id) {
- let notification_settings = await getNotificationSettings();
+ let notification_settings = await getNotificationSettings();
var index = notification_settings.indexOf(notification_id);
if (index !== -1) notification_settings.splice(index, 1); // remove notification option from list
await updateBackend();
@@ -115,11 +132,11 @@ export async function isBeingNotified(notification_id) {
}
async function updateBackend() {
- let response = await fetch(STRINGS.DAILY_URL + 'wp-json/tsd/v1/push-notification/users/' + await getToken(), {
+ let response = await fetch(STRINGS.DAILY_URL + 'wp-json/tsd/v1/push-notification/users/' + await getToken(), { // test notifications at "http://stanforddaily2.staging.wpengine.com/""
method: 'PUT',
headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
},
body: JSON.stringify({
subscribing: {
diff --git a/app/screens/Headlines.js b/app/screens/Headlines.js
index bf2e6849..adcf2bbf 100644
--- a/app/screens/Headlines.js
+++ b/app/screens/Headlines.js
@@ -97,7 +97,7 @@ export default (props) => {
color: COLORS.BLACK,
marginLeft: MARGINS.ARTICLE_SIDES
}}>
- Settings
+ Notification Settings
@@ -127,8 +127,9 @@ export default (props) => {
const {posts} = await getCategoryAsync([category.slug], pageNumber);
setArticles(posts);
}
+ setRefreshing(false);
})();
- }, [pageNumber, category]);
+ }, [pageNumber, category, refreshing]);
return (
{
onCloseStart={() => StatusBar.setHidden(false)}
>
- {/* setModalVisible(!modalVisible)}
- />*/}
+ />
{
ref={listRef}
removeClippedSubviews={false}
disableVirtualization={true}
- // refreshing={refreshing}
+ refreshing={refreshing}
keyExtractor={item => `list-key-${item.id}`}
- // onRefresh={() => setRefreshing(true)}
+ onRefresh={() => setRefreshing(true)}
// onEndReached={() => setPageNumber(pageNumber + 1)}
sections={[{ data: articles, key: `category-list-${pageNumber}-${category}` }]}
renderItem={_renderRow}
diff --git a/app/screens/Post.js b/app/screens/Post.js
index c7b32bc4..14fbc1c9 100644
--- a/app/screens/Post.js
+++ b/app/screens/Post.js
@@ -111,7 +111,7 @@ class Post extends Component {
tagsStyles={{
p: { marginBottom: MARGINS.ARTICLE_SIDES },
a: { color: COLORS.CARDINAL },
- strong: { fontFamily: FONTS.PT_SERIF_BOLD },
+ strong: { fontFamily: FONTS.PT_SERIF_BOLD },
em: { fontFamily: FONTS.PT_SERIF_ITALIC },
img: { marginHorizontal: -1 * MARGINS.ARTICLE_SIDES },
figure: { marginVertical: MARGINS.ARTICLE_SIDES },
diff --git a/app/screens/SettingsPage.js b/app/screens/SettingsPage.js
index b3712208..36f8f3d0 100644
--- a/app/screens/SettingsPage.js
+++ b/app/screens/SettingsPage.js
@@ -1,21 +1,24 @@
-import {STRINGS, CATEGORIES, REFS, KEYS, ALIGNMENTS, FONTS, COLORS, PN_RECEIVER_GROUPS} from '../assets/constants.js';
-import React, {Component} from 'react';
-import {Image} from 'react-native';
+import { STRINGS, CATEGORIES, REFS, KEYS, ALIGNMENTS, MARGINS, FONTS, FONT_SIZES, COLORS, PN_RECEIVER_GROUPS } from '../assets/constants.js';
+import React, { Component } from 'react';
+import { Ionicons } from '@expo/vector-icons';
import Modal from "react-native-modal"
import ToggleSwitch from 'toggle-switch-react-native'
import {
- Alert,
- View,
- Text,
- Dimensions,
- RefreshControl,
- StatusBar,
- ActivityIndicator,
- NetInfo,
- FlatList,
- TouchableOpacity,
- TouchableHighlight,
- SectionList
+ Alert,
+ Image,
+ Platform,
+ View,
+ Text,
+ Dimensions,
+ RefreshControl,
+ StatusBar,
+ ActivityIndicator,
+ NetInfo,
+ FlatList,
+ TouchableOpacity,
+ TouchableHighlight,
+ Switch,
+ SectionList
} from 'react-native';
import _ from 'lodash';
@@ -25,176 +28,190 @@ import { isBeingNotified, addNotificationSetting, removeNotificationSetting } fr
const amplitude = Amplitude.initialize(KEYS.AMPLITUDE_API);
//A map between categories names and their codes
-const {width, height} = Dimensions.get('window');
+const { width, height } = Dimensions.get('window');
var selectedCategory = STRINGS.FEATURED_HEADLINES; //The currently selected category
const styles = {
- listItem: { flex: 1, maxHeight: 60, flexDirection: 'row', borderBottomWidth: 1, borderBottomColor: 'grey'}
+ listItem: {
+ flex: 1,
+ maxHeight: 72,
+ flexDirection: 'row',
+ alignItems: 'center',
+ borderBottomWidth: 1,
+ borderBottomColor: COLORS.LIGHT_GRAY
+ },
+ notifHeader: {
+ fontSize: FONT_SIZES.DEFAULT_MEDIUM,
+ fontFamily: FONTS.OPEN_SANS_BOLD
+ },
+ notifText: {
+ fontSize: 13,
+ fontFamily: FONTS.OPEN_SANS
+ }
}
export default class SettingsPage extends Component {
- constructor(props) {
- super(props);
- this.state = {
- isOn: {
- [PN_RECEIVER_GROUPS.BREAKING]: false,
- [PN_RECEIVER_GROUPS.DAILY]: false,
- [PN_RECEIVER_GROUPS.WEEKLY]: false
- }
- };
- }
-
- async componentDidMount() {
- this.updateNotificationSettings();
- }
-
- async updateNotificationSettings() {
- this.setState({
- isOn: {
- [PN_RECEIVER_GROUPS.BREAKING]: await isBeingNotified(PN_RECEIVER_GROUPS.BREAKING),
- [PN_RECEIVER_GROUPS.DAILY]: await isBeingNotified(PN_RECEIVER_GROUPS.DAILY),
- [PN_RECEIVER_GROUPS.WEEKLY]: await isBeingNotified(PN_RECEIVER_GROUPS.WEEKLY)
- }
- });
- }
-
- async toggleNotificationSetting(name) {
- if (this.state.isOn[name]) {
- await removeNotificationSetting(name);
+ constructor(props) {
+ super(props);
+ this.state = {
+ isOn: {
+ [PN_RECEIVER_GROUPS.BREAKING]: false,
+ [PN_RECEIVER_GROUPS.DAILY]: false,
+ [PN_RECEIVER_GROUPS.WEEKLY]: false
}
- else {
- await addNotificationSetting(name);
+ };
+ }
+
+ async componentDidMount() {
+ this.updateNotificationSettings();
+ }
+
+ async updateNotificationSettings() {
+ this.setState({
+ isOn: {
+ [PN_RECEIVER_GROUPS.BREAKING]: await isBeingNotified(PN_RECEIVER_GROUPS.BREAKING),
+ [PN_RECEIVER_GROUPS.DAILY]: await isBeingNotified(PN_RECEIVER_GROUPS.DAILY),
+ [PN_RECEIVER_GROUPS.WEEKLY]: await isBeingNotified(PN_RECEIVER_GROUPS.WEEKLY)
}
- await this.updateNotificationSettings();
- }
+ });
+ }
- ToggleSwitch = ({receiverGroup}) => {
- return {
+ return { this.toggleNotificationSetting(receiverGroup) }}
+ style={{ transform: [{ scaleX: .8 }, { scaleY: .8 }] }}
+ />
+ {/* this.toggleNotificationSetting(receiverGroup) }
- />
- }
-
- render() {
- return (
-
-
- {/* Header */}
-
-
- Notifications
+ onToggle={ () => {this.toggleNotificationSetting(receiverGroup)} }
+ />*/}
+
+ }
+
+ render() {
+ return (
+
+
+ {/* Header */}
+
+
+ Notifications
+
+ How often do you want to hear from The Daily?
+
+
+
+
+
+
+
+
- How often do you want to hear from The Daily?
+
+ Breaking News
+ Important stories, as they happen
+
+
+
+
-
-
-
-
-
-
-
-
- Breaking News
- Important stories, as they happen
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
- Every day
- Daily news roundup
-
-
-
-
-
-
+
+ Every day
+ Daily news roundup
-
-
-
-
-
-
- Every week
- Weekend roundup
-
+
+
+
+
-
-
-
+
+
+
+
+
+ Every week
+ Weekend roundup
+
+
+
+
-
- {this.props.setModalVisible(!this.props.modalVisible);
-
- }}>
- Close
-
-
-
- )
- }
+
+
+ {
+ this.props.setModalVisible(!this.props.modalVisible);
+ }}>
+ Close
+
+
+
+ )
+ }
}
diff --git a/app/screens/styles/header.js b/app/screens/styles/header.js
index 60fd678b..5832ff56 100755
--- a/app/screens/styles/header.js
+++ b/app/screens/styles/header.js
@@ -28,7 +28,7 @@ const styles = StyleSheet.create({
},
wordsTitle: {
color: COLORS.BLACK,
- fontFamily: FONTS.OPEN_SANS_BOLD,
+ fontFamily: FONTS.PT_SERIF_BOLD,
fontSize: FONT_SIZES.DEFAULT_SMALL_MEDIUM,
textAlign: ALIGNMENTS.CENTER
},
diff --git a/app/screens/styles/headlines.js b/app/screens/styles/headlines.js
index c3ea26a1..b024689c 100755
--- a/app/screens/styles/headlines.js
+++ b/app/screens/styles/headlines.js
@@ -32,7 +32,7 @@ const styles= StyleSheet.create({
},
sideBarTitleText: {
color: COLORS.BLACK,
- fontFamily: FONTS.OPEN_SANS_BOLD,
+ fontFamily: FONTS.PT_SERIF_BOLD,
fontSize: FONT_SIZES.DEFAULT_SMALL_MEDIUM,
//textAlign: 'center',
flex: 1,
diff --git a/app/screens/styles/newsfeeditem.js b/app/screens/styles/newsfeeditem.js
index 4ab17b64..54c58542 100755
--- a/app/screens/styles/newsfeeditem.js
+++ b/app/screens/styles/newsfeeditem.js
@@ -12,6 +12,7 @@ const styles = ({
},
dateAndAuthor: {
flexDirection: ALIGNMENTS.ROW,
+ flexWrap: 'wrap',
justifyContent: ALIGNMENTS.SPACE_BETWEEN,
marginTop: MARGINS.DEFAULT_MARGIN,
marginHorizontal: MARGINS.ARTICLE_SIDES,