Confetti and haptics
Lat but not least, let's add some fun 🎉
We already have Expo Haptics, so let's add a haptic feedback when you mark your task as complete:
Update: app/counter/index.tsx
@@ -6,6 +6,7 @@ import { useEffect, useState } from "react";
import { intervalToDuration, isBefore } from "date-fns";
import { TimeSegment } from "../../components/TimeSegment";
import { getFromStorage, saveToStorage } from "../../utils/storage";
+import * as Haptics from "expo-haptics";
// 10 seconds in ms
const frequency = 10 * 1000;
@@ -62,6 +63,7 @@ export default function CounterScreen() {
}, [lastCompletedAt]);
const scheduleNotification = async () => {
+ Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
let pushNotificationId;
const result = await registerForPushNotificationsAsync();
if (result === "granted") {
(END)
And now, some confetti? Let's install react-native-confetti-cannon:
npx expo install react-native-confetti-cannon
And fire the confetti cannon when the notification gets scheduled:
Update: app/counter/index.tsx
+++ b/app/counter/index.tsx
@@ -1,12 +1,20 @@
-import { Text, View, StyleSheet, TouchableOpacity, Alert } from "react-native";
+import {
+ Text,
+ View,
+ StyleSheet,
+ TouchableOpacity,
+ Alert,
+ Dimensions,
+} from "react-native";
import { theme } from "../../theme";
import { registerForPushNotificationsAsync } from "../../utils/registerForPushNotificationsAsync";
import * as Notifications from "expo-notifications";
-import { useEffect, useState } from "react";
+import { useEffect, useRef, useState } from "react";
import { intervalToDuration, isBefore } from "date-fns";
import { TimeSegment } from "../../components/TimeSegment";
import { getFromStorage, saveToStorage } from "../../utils/storage";
import * as Haptics from "expo-haptics";
+import ConfettiCannon from "react-native-confetti-cannon";
// 10 seconds in ms
const frequency = 10 * 1000;
@@ -24,6 +32,7 @@ type CountdownStatus = {
};
export default function CounterScreen() {
+ const confettiRef = useRef<any>();
const [countdownState, setCountdownState] =
useState<PersistedCountdownState>();
const [status, setStatus] = useState<CountdownStatus>({
@@ -64,6 +73,7 @@ export default function CounterScreen() {
const scheduleNotification = async () => {
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
+ confettiRef?.current?.start();
let pushNotificationId;
const result = await registerForPushNotificationsAsync();
if (result === "granted") {
@@ -141,6 +151,13 @@ export default function CounterScreen() {
>
<Text style={styles.buttonText}>I've done the thing!</Text>
</TouchableOpacity>
+ <ConfettiCannon
+ ref={confettiRef}
+ count={50}
+ origin={{ x: Dimensions.get("window").width / 2, y: -30 }}
+ autoStart={false}
+ fadeOut={true}
+ />
</View>
);
}
Finally, it could be worth changing this to something you actually want to keep track of, e.g. washing your car every 2 weeks:
Update: app/counter/index.tsx
@@ -16,8 +16,8 @@ import { getFromStorage, saveToStorage } from "../../utils/storage";
import * as Haptics from "expo-haptics";
import ConfettiCannon from "react-native-confetti-cannon";
-// 10 seconds in ms
-const frequency = 10 * 1000;
+// 2 weeks in ms
+const frequency = 14 * 24 * 60 * 60 * 1000;
export const countdownStorageKey = "taskly-countdown";
@@ -79,7 +79,7 @@ export default function CounterScreen() {
if (result === "granted") {
pushNotificationId = await Notifications.scheduleNotificationAsync({
content: {
- title: "The thing is due!",
+ title: "Car wash overdue!",
},
trigger: {
seconds: frequency / 1000,
@@ -118,9 +118,11 @@ export default function CounterScreen() {
]}
>
{!status.isOverdue ? (
- <Text style={[styles.heading]}>Thing due in</Text>
+ <Text style={[styles.heading]}>Next car wash due in</Text>
) : (
- <Text style={[styles.heading, styles.whiteText]}>Thing overdue by</Text>
+ <Text style={[styles.heading, styles.whiteText]}>
+ Car wash overdue by
+ </Text>
)}
<View style={styles.row}>
<TimeSegment
@@ -149,7 +151,7 @@ export default function CounterScreen() {
style={styles.button}
activeOpacity={0.8}
>
- <Text style={styles.buttonText}>I've done the thing!</Text>
+ <Text style={styles.buttonText}>I've washed the car!</Text>
</TouchableOpacity>
<ConfettiCannon
ref={confettiRef}
Checkpoint​
Android | iOS |
---|---|