看到有系列文是超過 30 篇,筆者可以暫時鬆口氣,不用擔心 30 天處理不完~
然而仍希望能順利在預訂的期限內完成目標,完成以下所有 Required
的項目!
今天主要著重在 1.1 實際依照星期幾來通知
。
讓我們把先前預測的結果,以常數的方式建立吧:AnnoyancePrediction/src/constants.js
export const NIGHT_PREDICTION = [
{
weekday: 'fri',
time: '21:19',
},
{
weekday: 'sat',
time: '21:19',
},
{
weekday: 'sun',
time: '21:19',
},
{
weekday: 'mon',
time: '21:15',
},
{
weekday: 'thu',
time: '21:15',
},
{
weekday: 'tue',
time: '21:14',
},
{
weekday: 'wed',
time: '21:10',
},
];
export const DAY_PREDICTION = '11:45';
另外讓我們在同一個檔案加入星期幾轉換為 ISO Weekday 的表,方便之後轉換:
export const ISO_WEEKDAY_DICT = {
mon: 1,
tue: 2,
wed: 3,
thu: 4,
fri: 5,
sat: 6,
sun: 7,
};
讓我們進到 notification.js
import moment from 'moment';
import {DAY_PREDICTION, ISO_WEEKDAY_DICT, NIGHT_PREDICTION} from './constants';
moment.js 是一款可以讓操作時間更方便的套件,讓我們安裝並 import 進我們的專案。
筆者另外建立以下三個轉換天數
、小時
、分鐘
為毫秒的 function:
export const daysToMilliseconds = days => {
return days * 24 * 60 * 60 * 1000;
};
export const hoursToMilliseconds = hours => {
return hours * 60 * 60 * 1000;
};
export const minsToMilliseconds = mins => {
return mins * 60 * 1000;
};
並且,為了每七天重新建立通知的 event,我們獨立建立一個七天以毫秒為單位的常數輸出:
export const sevenDaysInterval = daysToMilliseconds(7);
onCreateTriggerNotification
為了讓特定的時間傳入,以及支援客製化訊息,讓我們加入兩個參數 time
& message
:
export async function onCreateTriggerNotification(
time: String,
message: String,
) {
const trigger: TimestampTrigger = {
type: TriggerType.TIMESTAMP,
timestamp: time,
};
const channelId = await notifee.createChannel({
id: 'default',
name: 'Default Channel',
});
await notifee.createTriggerNotification(
{
title: '關門通知',
body: message ? message : '樓下關門即將發生',
android: {
channelId,
pressAction: {
id: 'default',
},
},
},
trigger,
);
}
onCreateTriggerNotificationByWeekday
來封裝 onCreateTriggerNotification
這個底層的功能:export const onCreateTriggerNotificationByWeekday = async (
time: String,
weekday: String,
) => {
const paramISOWeekday: Number = ISO_WEEKDAY_DICT[weekday];
const weekdayNow = moment().isoWeekday();
const weekdayDiff = weekdayNow - paramISOWeekday;
const daysDiff =
weekdayDiff === 0
? 0
: weekdayDiff < 0
? Math.abs(weekdayDiff)
: 7 - weekdayDiff;
const [hours, mins] = time.split(':');
const absoluteTime = moment()
.add(daysDiff, 'days')
// 原先以為要 +8
// UTC +8
// .subtract(1, 'days')
// .add(hoursLeft, 'hours')
// .add(hours, 'hours')
// .add(8, 'hours');
.set('hour', hours)
.set('minute', mins)
// 10 mins before
.subtract(10, 'minutes');
// 如果今天的時間已經超過,那麼就設定七天以後
const absoluteTimeInMs =
absoluteTime.valueOf() > Date.now()
? absoluteTime.valueOf()
: absoluteTime.valueOf() + sevenDaysInterval;
const message = `樓下關門即將在 ${time} 發生`;
onCreateTriggerNotification(absoluteTimeInMs, message);
};
讓我們在這層處理好時間轉換成毫秒、客製化訊息以後,再傳入 onCreateTriggerNotification
呼叫。
時區的部分,原先以為要 +8
處理,但後來筆者有想到可以在 useEffect
加入這一行:
process.env.TZ = 'Asia/Taipei';
根據筆者的理解,如此操作就會統一使用我們臺灣的時區了。
setNotificationByWeekDay
:export const setNotificationByWeekDay = () => {
const nightPrediction = NIGHT_PREDICTION;
const dayPrediction = DAY_PREDICTION;
for (const predict of nightPrediction) {
const {weekday, time} = predict;
// night notification
onCreateTriggerNotificationByWeekday(time, weekday);
// morning notification
onCreateTriggerNotificationByWeekday(dayPrediction, weekday);
}
};
包好之後放在 useEffect
:
useEffect(() => {
process.env.TZ = 'Asia/Taipei';
checkAndroidBackgroundRestrictions();
setNotificationByWeekDay();
// trigger every 7 days
setInterval(setNotificationByWeekDay, sevenDaysInterval);
}, []);
稍微改一下通知時間,讓我們看一下成果:
確實成功在十分鐘前提醒!
今天收工!