1import React from 'react';
2import { Alert, Platform, ScrollView } from 'react-native';
3import { Notifications } from 'expo';
4import * as Permissions from 'expo-permissions';
5import HeadingText from '../components/HeadingText';
6import ListButton from '../components/ListButton';
7
8import registerForPushNotificationsAsync from '../api/registerForPushNotificationsAsync';
9
10export default class NotificationScreen extends React.Component {
11  static navigationOptions = {
12    title: 'Notifications',
13  };
14
15  render() {
16    return (
17      <ScrollView style={{ padding: 10 }}>
18        <HeadingText>Local Notifications</HeadingText>
19        <ListButton
20          onPress={this._presentLocalNotificationAsync}
21          title="Present a notification immediately"
22        />
23        <ListButton
24          onPress={this._scheduleLocalNotificationAsync}
25          title="Schedule notification for 10 seconds from now"
26        />
27        <ListButton
28          onPress={this._scheduleLocalNotificationAndCancelAsync}
29          title="Schedule notification for 10 seconds from now and then cancel it immediately"
30        />
31        <ListButton
32          onPress={Notifications.cancelAllScheduledNotificationsAsync}
33          title="Cancel all scheduled notifications"
34        />
35        <ListButton
36          onPress={this._scheduleLegacyNotificationAsync}
37          title="Schedule a notification with both `time` and `repeat` (deprecated on iOS)"
38        />
39        <ListButton
40          onPress={this._scheduleAndCancelLegacyNotificationAsync}
41          title="Schedule and immediately cancel notification with both `time` and `repeat` (deprecated on iOS)"
42        />
43
44        <HeadingText>Push Notifications</HeadingText>
45        <ListButton
46          onPress={() => this._sendNotificationAsync('simple')}
47          title="Send me a push notification"
48        />
49        <ListButton
50          onPress={() => this._sendNotificationAsync('image')}
51          title="Send me a push notification with an image"
52        />
53        <ListButton
54          onPress={() => this._sendNotificationAsync('audio')}
55          title="Send me a push notification with an audio"
56        />
57        <ListButton
58          onPress={() => this._sendNotificationAsync('gif')}
59          title="Send me a push notification with an animated image"
60        />
61        <ListButton
62          onPress={() => this._sendNotificationAsync('video')}
63          title="Send me a push notification with a video"
64        />
65        <ListButton
66          onPress={() => this._sendNotificationAsync('imageWithCustomIcon')}
67          title="Send me a push notification with a image and a custom icon"
68        />
69
70        <HeadingText>Custom notification categories</HeadingText>
71        <ListButton
72          onPress={this._createCategoryAsync}
73          title="Create a custom 'message' category"
74        />
75        <ListButton
76          onPress={this._scheduleLocalNotificationWithCategoryAsync}
77          title="Schedule notification for 10 seconds from now with a 'message' category"
78        />
79        <ListButton
80          onPress={this._deleteCategoryAsync}
81          title="Delete the custom 'message' category"
82        />
83
84        <HeadingText>Badge Number</HeadingText>
85        <ListButton
86          onPress={this._incrementIconBadgeNumberAsync}
87          title="Increment the app icon's badge number"
88        />
89        <ListButton
90          onPress={this._clearIconBadgeAsync}
91          title="Clear the app icon's badge number"
92        />
93      </ScrollView>
94    );
95  }
96
97  _obtainUserFacingNotifPermissionsAsync = async () => {
98    let permission = await Permissions.getAsync(
99      Permissions.USER_FACING_NOTIFICATIONS
100    );
101    if (permission.status !== 'granted') {
102      permission = await Permissions.askAsync(
103        Permissions.USER_FACING_NOTIFICATIONS
104      );
105      if (permission.status !== 'granted') {
106        Alert.alert(`We don't have permission to present notifications.`);
107      }
108    }
109    return permission;
110  }
111
112  _obtainRemoteNotifPermissionsAsync = async () => {
113    let permission = await Permissions.getAsync(Permissions.NOTIFICATIONS);
114    if (permission.status !== 'granted') {
115      permission = await Permissions.askAsync(Permissions.NOTIFICATIONS);
116      if (permission.status !== 'granted') {
117        Alert.alert(
118          `We don't have permission to receive remote notifications.`
119        );
120      }
121    }
122    return permission;
123  }
124
125  _presentLocalNotificationAsync = async () => {
126    await this._obtainUserFacingNotifPermissionsAsync();
127    Notifications.presentLocalNotificationAsync({
128      title: 'Here is a local notification!',
129      body: 'This is the body',
130      data: {
131        hello: 'there',
132      },
133      ios: {
134        sound: true,
135      },
136    });
137  }
138
139  _scheduleLocalNotificationAsync = async () => {
140    await this._obtainUserFacingNotifPermissionsAsync();
141    Notifications.scheduleLocalNotificationAsync(
142      {
143        title: 'Here is a scheduled notifiation!',
144        body: 'This is the body',
145        data: {
146          hello: 'there',
147          future: 'self',
148        },
149        ios: {
150          sound: true,
151        },
152      },
153      {
154        time: new Date().getTime() + 10000,
155      }
156    );
157  }
158
159  _createCategoryAsync = () =>
160    Notifications.createCategoryAsync('message', [
161      {
162        actionId: 'dismiss',
163        buttonTitle: 'Dismiss notification',
164        isDestructive: true,
165        isAuthenticationRequired: false,
166      },
167      {
168        actionId: 'respond',
169        buttonTitle: 'Respond',
170        isDestructive: false,
171        isAuthenticationRequired: true,
172        textInput: {
173          submitButtonTitle: 'Send',
174          placeholder: 'Response',
175        },
176      },
177    ])
178
179  _deleteCategoryAsync = () => Notifications.deleteCategoryAsync('message');
180
181  _scheduleLocalNotificationWithCategoryAsync = async () => {
182    await this._obtainUserFacingNotifPermissionsAsync();
183
184    await Notifications.scheduleLocalNotificationAsync(
185      {
186        title: 'Expo sent you a message!',
187        body: 'Howdy, fella!',
188        ios: {
189          sound: true,
190        },
191        categoryId: 'message',
192      },
193      {
194        time: new Date().getTime() + 10000,
195      }
196    );
197  }
198
199  _scheduleLocalNotificationAndCancelAsync = async () => {
200    await this._obtainUserFacingNotifPermissionsAsync();
201    const notificationId = await Notifications.scheduleLocalNotificationAsync(
202      {
203        title: 'This notification should not appear',
204        body: 'It should have been cancelled. :(',
205        ios: {
206          sound: true,
207        },
208      },
209      {
210        time: new Date().getTime() + 10000,
211      }
212    );
213    await Notifications.cancelScheduledNotificationAsync(notificationId);
214  }
215
216  _scheduleLegacyNotificationAsync = async () => {
217    await this._obtainUserFacingNotifPermissionsAsync();
218    return Notifications.scheduleLocalNotificationAsync(
219      {
220        title: 'Repeating notification',
221        body: `I repeat every minute starting from ${new Date().toLocaleTimeString()}`,
222        data: {
223          repeatingEvery: 'minute',
224          scheduledAt: new Date().toLocaleTimeString(),
225        },
226        ios: {
227          sound: true,
228        },
229      },
230      {
231        time: new Date().getTime() + 2000,
232        repeat: 'minute',
233      }
234    );
235  }
236
237  _scheduleAndCancelLegacyNotificationAsync = async () => {
238    const notificationId = await this._scheduleLegacyNotificationAsync();
239    await Notifications.cancelScheduledNotificationAsync(notificationId);
240  }
241
242  _incrementIconBadgeNumberAsync = async () => {
243    const currentNumber = await Notifications.getBadgeNumberAsync();
244    await Notifications.setBadgeNumberAsync(currentNumber + 1);
245    const actualNumber = await Notifications.getBadgeNumberAsync();
246    Alert.alert(`Set the badge number to ${actualNumber}`);
247  }
248
249  _clearIconBadgeAsync = async () => {
250    await Notifications.setBadgeNumberAsync(0);
251    Alert.alert(`Cleared the badge`);
252  }
253
254  _sendNotificationAsync = async (type: string) => {
255    if (type !== 'simple' && type !== 'image' && Platform.OS !== 'ios') {
256      alert(
257        'While you will still receive the notification, you will not see any rich content since rich content other than images are only supported on iOS.'
258      );
259    }
260    if (type === 'imageWithCustomIcon' && Platform.OS === 'ios') {
261      alert(
262        'While you will still receive the notification, you will not see any custom icon since custom icons are not supported on iOS.'
263      );
264    }
265    const permission = await this._obtainRemoteNotifPermissionsAsync();
266    if (permission.status === 'granted') {
267      registerForPushNotificationsAsync(type);
268    }
269  }
270}
271