-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbackground.js
More file actions
110 lines (95 loc) · 2.9 KB
/
Copy pathbackground.js
File metadata and controls
110 lines (95 loc) · 2.9 KB
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// === background.js ===
// 保存された課題を監視して期限前に通知
class NotificationScheduler {
constructor(storageArea, storageEvents, alarms, notifications, runtime) {
this.storageArea = storageArea;
this.storageEvents = storageEvents;
this.alarms = alarms;
this.notifications = notifications;
this.runtime = runtime;
this.offsets = [
{ hours: 24, label: "24時間前" },
{ hours: 12, label: "12時間前" },
{ hours: 3, label: "3時間前" },
{ hours: 1, label: "1時間前" },
];
}
createNotification(task, remainingHours = null) {
const title =
remainingHours === null
? `締切間近:${task.title}`
: `${task.title}の締切まであと${remainingHours}時間です!!`;
this.notifications.create({
type: "basic",
iconUrl: "icon.png",
title,
message: `${task.course} (${task.contentType})\n締切:${new Date(
task.due
).toLocaleString()}`,
priority: 2,
});
}
scheduleForTask(task) {
const dueTime = new Date(task.due).getTime();
const now = Date.now();
if (dueTime <= now) {
return;
}
const immediateThresholdMs = 60 * 1000;
if (dueTime - now <= immediateThresholdMs) {
this.createNotification(task, 0);
return;
}
for (const { hours } of this.offsets) {
const when = dueTime - hours * 60 * 60 * 1000;
if (when > now) {
const alarmName = `notify-${btoa(task.url)}-${hours}`;
this.alarms.create(alarmName, { when });
}
}
}
handleAlarm(alarm) {
if (!alarm.name.startsWith("notify-")) return;
const matches = alarm.name.match(/^notify-(.*)-(\d+)$/);
if (!matches) return;
const [, encodedUrl, hours] = matches;
const url = atob(encodedUrl);
this.storageArea.get("tasks", (data) => {
const task = (data.tasks || []).find((t) => t.url === url);
if (task) {
this.createNotification(task, Number(hours));
}
});
}
rescheduleFromStorage() {
this.storageArea.get("tasks", (data) => {
(data.tasks || []).forEach((task) => this.scheduleForTask(task));
});
}
handleStorageChange(changes) {
if (!changes.tasks?.newValue) return;
const tasks = changes.tasks.newValue;
this.alarms.clearAll(() => {
tasks.forEach((task) => this.scheduleForTask(task));
});
}
registerListeners() {
this.alarms.onAlarm.addListener((alarm) => this.handleAlarm(alarm));
this.storageEvents.onChanged.addListener((changes) => this.handleStorageChange(changes));
["onStartup", "onInstalled"].forEach((evt) => {
this.runtime[evt].addListener(() => {
this.rescheduleFromStorage();
});
});
}
}
(() => {
const scheduler = new NotificationScheduler(
chrome.storage.local,
chrome.storage,
chrome.alarms,
chrome.notifications,
chrome.runtime
);
scheduler.registerListeners();
})();