aio-capacitor 2.2.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.d.ts +123 -36
  2. package/index.js +403 -133
  3. package/package.json +14 -2
package/index.d.ts CHANGED
@@ -1,18 +1,3 @@
1
- type I_logItem = {
2
- tags?: string[];
3
- id?: string;
4
- message: string;
5
- status?: 'error' | 'success' | 'warning' | 'info';
6
- data?: any;
7
- date?: number;
8
- };
9
- export type NotificationItem = {
10
- id: number;
11
- title: string;
12
- body: string;
13
- fireAt: number;
14
- status: 'pending' | 'scheduled' | 'done';
15
- };
16
1
  export type I_speak = {
17
2
  text: string;
18
3
  lang?: 'fa-IR' | 'en-US';
@@ -21,17 +6,35 @@ export type I_speak = {
21
6
  };
22
7
  type PermissionName = "CAMERA" | "ACCESS_FINE_LOCATION" | "ACCESS_COARSE_LOCATION" | "POST_NOTIFICATIONS";
23
8
  export declare class AIOCapacitor {
24
- onLog: ((log: I_logItem) => void) | undefined;
9
+ logs: Logs;
10
+ notif: NotificationService;
25
11
  constructor(p?: {
26
- onLog?: (log: I_logItem) => void;
12
+ notificationActionCallBack?: (actionId: string) => void;
27
13
  });
28
14
  getPlatform: () => 'web' | 'android' | 'ios';
29
15
  isNative: () => boolean;
30
- addLog: (log: I_logItem) => void;
16
+ addNotif: (_item: I_notifItem) => Promise<number>;
17
+ cancelNotif: (p: {
18
+ tags?: string[];
19
+ ids?: number[];
20
+ }) => Promise<void>;
21
+ getNotifs: (filter?: {
22
+ fired?: boolean;
23
+ tags?: string[];
24
+ }) => Promise<I_notifItem[]>;
31
25
  vibrate: (p: {
32
26
  pattern?: number[];
33
27
  density?: 'light' | 'medium' | 'heavy';
34
28
  }) => Promise<void>;
29
+ addLog: (log: Omit<I_logItem, "date">) => I_logItem[];
30
+ removeLog: (p: {
31
+ id?: number;
32
+ tags?: string[];
33
+ }) => I_logItem[];
34
+ getLogs: (filter?: {
35
+ tags?: string[];
36
+ status?: "error" | "success" | "warning" | "info";
37
+ }) => I_logItem[];
35
38
  vibratePattern: (pattern: number[]) => Promise<void>;
36
39
  vibrateImpact: (style?: 'light' | 'medium' | 'heavy') => Promise<void>;
37
40
  getPermissions: (permissionNames: PermissionName[]) => Promise<void>;
@@ -46,12 +49,34 @@ export declare class AIOCapacitor {
46
49
  storageLoad: (name: string, def: any) => Promise<any>;
47
50
  copy: (text: string) => Promise<void>;
48
51
  paste: () => Promise<string>;
49
- readFile: (path: string, directory: Directory) => Promise<any>;
52
+ getDirectory: (location?: 'Data' | 'Documents' | 'Cache') => any;
50
53
  uriToSrc: (uri: string) => Promise<any>;
51
54
  pathToUri: (path: string, directory: Directory) => Promise<any>;
52
55
  pathToSrc: (path: string, directory: Directory) => Promise<any>;
53
- writeFile: (data: string, path: string, encoding?: boolean) => Promise<any>;
54
- save: (data: string | File | Blob, path: string) => Promise<{
56
+ pickFolder: (extensions?: string[]) => Promise<{
57
+ files: {
58
+ filePath: string;
59
+ fileName: string;
60
+ }[];
61
+ folderPath: string;
62
+ }>;
63
+ getFolderFiles: (folderPath: string, extensions: string[]) => Promise<false | ({
64
+ filePath: string;
65
+ fileName: string;
66
+ }[])>;
67
+ openFile: (filePath: string) => Promise<void>;
68
+ readFile: (path: string, options?: {
69
+ location?: 'Data' | 'Documents' | 'Cache';
70
+ utf8?: boolean;
71
+ }) => Promise<any>;
72
+ writeFile: (data: string, path: string, options?: {
73
+ location?: 'Data' | 'Documents' | 'Cache';
74
+ utf8?: boolean;
75
+ }) => Promise<any>;
76
+ save: (data: string | File | Blob, path: string, options?: {
77
+ location?: 'Data' | 'Documents' | 'Cache';
78
+ utf8?: boolean;
79
+ }) => Promise<{
55
80
  success: boolean;
56
81
  message: any;
57
82
  }>;
@@ -62,6 +87,7 @@ export declare class AIOCapacitor {
62
87
  success: boolean;
63
88
  error: any;
64
89
  }>;
90
+ getExtensions: (type: 'image' | 'audio' | 'video') => string[];
65
91
  shareFile: (file: Blob | File, fileName?: string) => Promise<any>;
66
92
  getLocation: () => Promise<{
67
93
  success: boolean;
@@ -72,23 +98,38 @@ export declare class AIOCapacitor {
72
98
  error?: string;
73
99
  }>;
74
100
  awake: (state?: boolean) => Promise<any>;
75
- isAwake: () => Promise<any>;
101
+ isAwake: () => Promise<boolean>;
76
102
  }
77
- type DB = {
78
- save: (item: NotificationItem) => Promise<void>;
79
- getAll: () => Promise<NotificationItem[]>;
80
- update: (id: number, patch: Partial<NotificationItem>) => Promise<void>;
103
+ type I_logItem = {
104
+ tags: string[];
105
+ id?: number;
106
+ repeat?: number;
107
+ message: string;
108
+ status: 'error' | 'success' | 'warning' | 'info';
109
+ data?: any;
110
+ expiredByHours?: number;
111
+ date: number;
81
112
  };
82
- export declare class NotificationService {
83
- private db;
84
- constructor(db: DB);
85
- init(): Promise<void>;
86
- notifyAt(date: number, title: string, body: string): Promise<number>;
87
- private schedule;
88
- private fireNow;
89
- resync(): Promise<void>;
90
- cancel(id: number): Promise<void>;
91
- list(): Promise<any>;
113
+ declare class Logs {
114
+ logs: I_logItem[];
115
+ load: () => Promise<I_logItem[]>;
116
+ save: (logs: I_logItem[]) => Promise<void>;
117
+ constructor(p: {
118
+ load: () => Promise<I_logItem[]>;
119
+ save: (logs: I_logItem[]) => Promise<void>;
120
+ });
121
+ private removeExpiredLogs;
122
+ addLog: (log: Omit<I_logItem, 'date'>) => I_logItem[];
123
+ remove: (p: {
124
+ id?: number;
125
+ tags?: string[];
126
+ }) => I_logItem[];
127
+ private getTagsDic;
128
+ private isTagsMatch;
129
+ getLogs: (filter?: {
130
+ tags?: string[];
131
+ status?: 'error' | 'success' | 'warning' | 'info';
132
+ }) => I_logItem[];
92
133
  }
93
134
  export declare class Tracker {
94
135
  private watchId;
@@ -110,4 +151,50 @@ export declare class Tracker {
110
151
  stop(): Promise<void>;
111
152
  isTracking(): boolean;
112
153
  }
154
+ export type I_notifItem = {
155
+ id: number;
156
+ title: string;
157
+ body: string;
158
+ fireAt: number;
159
+ showInExpired?: boolean;
160
+ keepUntil?: number;
161
+ actions?: string[];
162
+ tags?: string[];
163
+ importance?: 'low' | 'default' | 'high';
164
+ sound?: string;
165
+ vibration?: boolean;
166
+ };
167
+ export declare class NotificationService {
168
+ private notificationFile;
169
+ constructor(actionCallBack?: (actionId: string) => void);
170
+ init: (actionCallBack?: (actionId: string) => void) => Promise<void>;
171
+ private handleReceived;
172
+ private getChannelId;
173
+ private registerChannel;
174
+ register: (_item: I_notifItem) => Promise<number>;
175
+ cancel: (p: {
176
+ tags?: string[];
177
+ ids?: number[];
178
+ }) => Promise<void>;
179
+ private cancelByIds;
180
+ private cancelById;
181
+ private cancelByTag;
182
+ private cancelByTags;
183
+ private resync;
184
+ private schedule;
185
+ private registerActionType;
186
+ private getActionTypeId;
187
+ private getImportance;
188
+ tagsMatch: (tagsDic: {
189
+ [tag: string]: boolean;
190
+ }, itemTags?: string[]) => boolean | string[];
191
+ getTagsDic: (tags?: string[]) => {
192
+ [tag: string]: boolean;
193
+ };
194
+ getList: (filter?: {
195
+ fired?: boolean;
196
+ tags?: string[];
197
+ }) => Promise<I_notifItem[]>;
198
+ private save;
199
+ }
113
200
  export {};
package/index.js CHANGED
@@ -7,18 +7,48 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { Capacitor, Preferences, Clipboard, Camera, Geolocation, PushNotifications, TextToSpeech, Filesystem, Directory, Encoding, Haptics, ImpactStyle, Share, LocalNotifications, KeepAwake } from 'aio-capacitor-deps';
11
- import { FileClass } from 'aio-class';
10
+ import { Capacitor } from '@capacitor/core';
11
+ import { Preferences } from '@capacitor/preferences';
12
+ import { Clipboard } from '@capacitor/clipboard';
13
+ import { Camera } from '@capacitor/camera';
14
+ import { Geolocation } from '@capacitor/geolocation';
15
+ import { PushNotifications } from '@capacitor/push-notifications';
16
+ import { TextToSpeech } from '@capacitor-community/text-to-speech';
17
+ import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
18
+ import { Haptics, ImpactStyle } from '@capacitor/haptics';
19
+ import { Share } from '@capacitor/share';
20
+ import { LocalNotifications } from '@capacitor/local-notifications';
21
+ import { KeepAwake } from '@capacitor-community/keep-awake';
22
+ import { FolderPicker } from 'aio-capacitor-folder-picker';
23
+ import { FileClass, GenerateId } from 'aio-class';
12
24
  export class AIOCapacitor {
13
25
  constructor(p) {
26
+ this.logs = new Logs({
27
+ load: () => __awaiter(this, void 0, void 0, function* () {
28
+ try {
29
+ const storageRes = yield this.readFile('logs.json', { location: "Data", utf8: true });
30
+ const res = JSON.parse(storageRes);
31
+ return res;
32
+ }
33
+ catch (err) {
34
+ return [];
35
+ }
36
+ }),
37
+ save: (logs) => __awaiter(this, void 0, void 0, function* () {
38
+ try {
39
+ yield this.writeFile(JSON.stringify(logs), 'logs.json', { location: "Data", utf8: true });
40
+ }
41
+ catch (err) {
42
+ alert(err.message);
43
+ }
44
+ })
45
+ });
46
+ this.notif = new NotificationService();
14
47
  this.getPlatform = () => Capacitor.getPlatform();
15
48
  this.isNative = () => ['android', 'ios'].indexOf(Capacitor.getPlatform()) !== -1;
16
- this.addLog = (log) => {
17
- if (!this.onLog) {
18
- return;
19
- }
20
- this.onLog(log);
21
- };
49
+ this.addNotif = this.notif.register;
50
+ this.cancelNotif = this.notif.cancel;
51
+ this.getNotifs = this.notif.getList;
22
52
  this.vibrate = (p) => __awaiter(this, void 0, void 0, function* () {
23
53
  if (p.pattern) {
24
54
  yield this.vibratePattern(p.pattern);
@@ -27,6 +57,9 @@ export class AIOCapacitor {
27
57
  this.vibrateImpact(p.density);
28
58
  }
29
59
  });
60
+ this.addLog = this.logs.addLog;
61
+ this.removeLog = this.logs.remove;
62
+ this.getLogs = this.logs.getLogs;
30
63
  this.vibratePattern = (pattern) => __awaiter(this, void 0, void 0, function* () {
31
64
  try {
32
65
  for (const duration of pattern) {
@@ -52,34 +85,34 @@ export class AIOCapacitor {
52
85
  }
53
86
  });
54
87
  this.getPermissions = (permissionNames) => __awaiter(this, void 0, void 0, function* () {
55
- var _a, _b, _c, _d, _e;
56
88
  for (const permission of permissionNames) {
57
89
  try {
58
90
  switch (permission) {
59
91
  case "CAMERA": {
60
92
  yield Camera.requestPermissions();
61
- (_a = this.addLog) === null || _a === void 0 ? void 0 : _a.call(this, { message: "CAMERA permission requested", status: "success" });
93
+ this.addLog({ message: "CAMERA permission requested", status: "success", tags: ['permission'] });
62
94
  break;
63
95
  }
64
96
  case "ACCESS_FINE_LOCATION":
65
97
  case "ACCESS_COARSE_LOCATION": {
66
98
  yield Geolocation.requestPermissions();
67
- (_b = this.addLog) === null || _b === void 0 ? void 0 : _b.call(this, { message: "LOCATION permission requested", status: "success" });
99
+ this.addLog({ message: "LOCATION permission requested", status: "success", tags: ['permission'] });
68
100
  break;
69
101
  }
70
102
  case "POST_NOTIFICATIONS": {
71
103
  yield PushNotifications.requestPermissions();
72
- (_c = this.addLog) === null || _c === void 0 ? void 0 : _c.call(this, { message: "NOTIFICATION permission requested", status: "success" });
104
+ this.addLog({ message: "NOTIFICATION permission requested", status: "success", tags: ['permission'] });
73
105
  break;
74
106
  }
75
107
  default:
76
- (_d = this.addLog) === null || _d === void 0 ? void 0 : _d.call(this, { message: `Permission not supported: ${permission}`, status: "error" });
108
+ this.addLog({ message: `Permission not supported: ${permission}`, status: "error", tags: ['permission'] });
77
109
  }
78
110
  }
79
111
  catch (err) {
80
- (_e = this.addLog) === null || _e === void 0 ? void 0 : _e.call(this, {
112
+ this.addLog({
81
113
  message: `Permission error for ${permission}: ${err === null || err === void 0 ? void 0 : err.message}`,
82
- status: "error"
114
+ status: "error",
115
+ tags: ['permission']
83
116
  });
84
117
  }
85
118
  }
@@ -137,17 +170,47 @@ export class AIOCapacitor {
137
170
  return '';
138
171
  }
139
172
  });
140
- this.readFile = (path, directory) => __awaiter(this, void 0, void 0, function* () { return yield Filesystem.readFile({ path, directory }); });
173
+ this.getDirectory = (location) => {
174
+ return { Data: Directory.Data, Documents: Directory.Documents, Cache: Directory.Cache }[location || 'Data'];
175
+ };
141
176
  this.uriToSrc = (uri) => __awaiter(this, void 0, void 0, function* () { return Capacitor.convertFileSrc(uri); });
142
177
  this.pathToUri = (path, directory) => __awaiter(this, void 0, void 0, function* () { return (yield Filesystem.getUri({ path, directory })).uri; });
143
178
  this.pathToSrc = (path, directory) => __awaiter(this, void 0, void 0, function* () { return yield this.uriToSrc(yield this.pathToUri(path, directory)); });
144
- this.writeFile = (data, path, encoding) => __awaiter(this, void 0, void 0, function* () { return yield Filesystem.writeFile({ path, data, directory: Directory.Documents, encoding: encoding ? Encoding.UTF8 : undefined }); });
145
- this.save = (data, path) => __awaiter(this, void 0, void 0, function* () {
179
+ this.pickFolder = (extensions) => __awaiter(this, void 0, void 0, function* () {
180
+ const { folderPath, files } = yield FolderPicker.pickFolder(extensions ? { extensions } : undefined);
181
+ return { folderPath, files };
182
+ });
183
+ this.getFolderFiles = (folderPath, extensions) => __awaiter(this, void 0, void 0, function* () {
184
+ try {
185
+ const res = yield FolderPicker.getFolderFiles({ folderPath, extensions });
186
+ return res.files;
187
+ }
188
+ catch (error) {
189
+ alert("updateFolder error:" + String(error));
190
+ return false;
191
+ }
192
+ });
193
+ this.openFile = (filePath) => __awaiter(this, void 0, void 0, function* () {
194
+ try {
195
+ yield FolderPicker.openFile({ filePath });
196
+ }
197
+ catch (error) {
198
+ alert(`Open file error:\n${String(error)}`);
199
+ }
200
+ });
201
+ this.readFile = (path, options) => __awaiter(this, void 0, void 0, function* () {
202
+ const res = yield Filesystem.readFile({ path, directory: this.getDirectory(options === null || options === void 0 ? void 0 : options.location), encoding: (options === null || options === void 0 ? void 0 : options.utf8) ? Encoding.UTF8 : undefined });
203
+ return res.data;
204
+ });
205
+ this.writeFile = (data, path, options) => __awaiter(this, void 0, void 0, function* () {
206
+ return Filesystem.writeFile({ path, data, directory: this.getDirectory(options === null || options === void 0 ? void 0 : options.location), encoding: (options === null || options === void 0 ? void 0 : options.utf8) ? Encoding.UTF8 : undefined });
207
+ });
208
+ this.save = (data, path, options) => __awaiter(this, void 0, void 0, function* () {
146
209
  try {
147
210
  const fs = new FileClass();
148
211
  if (typeof data === 'string' && !fs.isUrl(data)) {
149
212
  try {
150
- yield this.writeFile(data, path, true);
213
+ yield this.writeFile(data, path, options);
151
214
  return { success: true, message: '' };
152
215
  }
153
216
  catch (err) {
@@ -163,7 +226,8 @@ export class AIOCapacitor {
163
226
  if (!res2.success) {
164
227
  return { success: false, message: res2.message };
165
228
  }
166
- yield this.writeFile(res2.result, path);
229
+ alert(res2.result.slice(0, 50));
230
+ yield this.writeFile(res2.result, path, options);
167
231
  return { success: true, message: '' };
168
232
  }
169
233
  }
@@ -180,6 +244,26 @@ export class AIOCapacitor {
180
244
  return { success: false, error: (err === null || err === void 0 ? void 0 : err.message) || err };
181
245
  }
182
246
  });
247
+ this.getExtensions = (type) => {
248
+ const extensions = {
249
+ image: [
250
+ 'jpg', 'jpeg', 'png', 'gif', 'webp',
251
+ 'bmp', 'svg', 'ico', 'tiff', 'tif', 'avif'
252
+ ],
253
+ audio: [
254
+ 'mp3', 'wav', 'flac', 'aac', 'm4a',
255
+ 'ogg', 'oga', 'opus', 'wma', 'aiff', 'aif',
256
+ 'alac', 'amr', 'mid', 'midi'
257
+ ],
258
+ video: [
259
+ 'mp4', 'webm', 'mkv', 'avi', 'mov',
260
+ 'wmv', 'flv', 'm4v', '3gp', '3g2',
261
+ 'mpeg', 'mpg', 'mts', 'm2ts', 'ts',
262
+ 'ogv', 'vob'
263
+ ]
264
+ };
265
+ return extensions[type];
266
+ };
183
267
  this.shareFile = (file_1, ...args_2) => __awaiter(this, [file_1, ...args_2], void 0, function* (file, fileName = `file_${Date.now()}`) {
184
268
  try {
185
269
  const res = yield new FileClass().toDataUrl(file);
@@ -249,7 +333,7 @@ export class AIOCapacitor {
249
333
  const _isAwake = yield this.isAwake();
250
334
  _awake = !_isAwake;
251
335
  }
252
- if (_awake) {
336
+ if (!_awake) {
253
337
  yield KeepAwake.allowSleep();
254
338
  }
255
339
  else {
@@ -257,126 +341,98 @@ export class AIOCapacitor {
257
341
  }
258
342
  return _awake;
259
343
  });
260
- this.isAwake = () => __awaiter(this, void 0, void 0, function* () { return yield KeepAwake.isKeptAwake(); });
261
- this.onLog = p === null || p === void 0 ? void 0 : p.onLog;
262
- }
263
- }
264
- export class NotificationService {
265
- constructor(db) { this.db = db; }
266
- // -------------------------
267
- // INIT (CRITICAL)
268
- // -------------------------
269
- init() {
270
- return __awaiter(this, void 0, void 0, function* () {
271
- yield LocalNotifications.requestPermissions();
272
- yield this.resync();
344
+ this.isAwake = () => __awaiter(this, void 0, void 0, function* () {
345
+ const res = yield KeepAwake.isKeptAwake();
346
+ return !!res.isKeptAwake;
273
347
  });
348
+ this.notif = new NotificationService(p === null || p === void 0 ? void 0 : p.notificationActionCallBack);
274
349
  }
275
- // -------------------------
276
- // CREATE NOTIFICATION
277
- // -------------------------
278
- notifyAt(date, title, body) {
279
- return __awaiter(this, void 0, void 0, function* () {
280
- const id = Date.now();
281
- const item = {
282
- id,
283
- title,
284
- body,
285
- fireAt: date,
286
- status: 'pending'
287
- };
288
- yield this.db.save(item);
289
- yield this.schedule(item);
290
- return id;
291
- });
292
- }
293
- // -------------------------
294
- // SCHEDULE TO OS
295
- // -------------------------
296
- schedule(item) {
297
- return __awaiter(this, void 0, void 0, function* () {
298
- if (item.fireAt <= Date.now()) {
299
- yield this.fireNow(item);
300
- return;
301
- }
302
- yield LocalNotifications.schedule({
303
- notifications: [
304
- {
305
- id: item.id,
306
- title: item.title,
307
- body: item.body,
308
- schedule: {
309
- at: new Date(item.fireAt)
310
- }
311
- }
312
- ]
313
- });
314
- yield this.db.update(item.id, {
315
- status: 'scheduled'
350
+ }
351
+ class Logs {
352
+ constructor(p) {
353
+ this.logs = [];
354
+ this.removeExpiredLogs = (logs) => {
355
+ return logs.filter((o) => {
356
+ if (!o.expiredByHours) {
357
+ return true;
358
+ }
359
+ const currentTime = Date.now();
360
+ const delta = currentTime - o.date;
361
+ return delta < o.expiredByHours * 60 * 60 * 1000;
316
362
  });
317
- });
318
- }
319
- // -------------------------
320
- // IMMEDIATE NOTIFICATION
321
- // -------------------------
322
- fireNow(item) {
323
- return __awaiter(this, void 0, void 0, function* () {
324
- yield LocalNotifications.schedule({
325
- notifications: [
326
- {
327
- id: item.id,
328
- title: item.title,
329
- body: item.body,
330
- schedule: { at: new Date() }
363
+ };
364
+ this.addLog = (log) => {
365
+ let newLogs = [...this.logs, Object.assign(Object.assign({}, log), { date: Date.now(), id: log.id === undefined ? GenerateId('number') : log.id })];
366
+ if (log.repeat) {
367
+ const newReverseLogs = [];
368
+ let count = 0;
369
+ for (let i = newLogs.length - 1; i >= 0; i--) {
370
+ if (newLogs[i].id === log.id && count < log.repeat) {
371
+ newReverseLogs.push(newLogs[i]);
372
+ count++;
331
373
  }
332
- ]
333
- });
334
- yield this.db.update(item.id, {
335
- status: 'done'
336
- });
337
- });
338
- }
339
- // -------------------------
340
- // RESYNC AFTER RESTART
341
- // -------------------------
342
- resync() {
343
- return __awaiter(this, void 0, void 0, function* () {
344
- const all = yield this.db.getAll();
345
- const pending = all.filter(i => i.status !== 'done');
346
- for (const item of pending) {
347
- yield this.schedule(item);
374
+ else {
375
+ newReverseLogs.push(this.logs[i]);
376
+ }
377
+ }
378
+ newLogs = newReverseLogs.reverse();
348
379
  }
349
- });
350
- }
351
- // -------------------------
352
- // CANCEL
353
- // -------------------------
354
- cancel(id) {
355
- return __awaiter(this, void 0, void 0, function* () {
356
- yield LocalNotifications.cancel({
357
- notifications: [{ id }]
358
- });
359
- yield this.db.update(id, {
360
- status: 'done'
380
+ newLogs = this.removeExpiredLogs(newLogs);
381
+ this.logs = newLogs;
382
+ return newLogs;
383
+ };
384
+ this.remove = (p) => {
385
+ let newLogs = this.logs;
386
+ newLogs = newLogs.filter((o) => {
387
+ if (p.id !== undefined && o.id !== p.id) {
388
+ return false;
389
+ }
390
+ if (p.tags && p.tags.length) {
391
+ const dic = this.getTagsDic(p.tags);
392
+ return this.isTagsMatch(dic, o);
393
+ }
394
+ return true;
361
395
  });
362
- });
363
- }
364
- // -------------------------
365
- // LIST (DEBUG)
366
- // -------------------------
367
- list() {
368
- return __awaiter(this, void 0, void 0, function* () {
369
- return yield LocalNotifications.getPending();
370
- });
396
+ newLogs = this.removeExpiredLogs(newLogs);
397
+ this.logs = newLogs;
398
+ return newLogs;
399
+ };
400
+ this.getTagsDic = (tags) => {
401
+ const dic = {};
402
+ for (let i = 0; i < tags.length; i++) {
403
+ dic[tags[i]] = true;
404
+ }
405
+ return dic;
406
+ };
407
+ this.isTagsMatch = (tagsDic, log) => {
408
+ if (!log.tags || !log.tags.length) {
409
+ return false;
410
+ }
411
+ for (let i = 0; i < log.tags.length; i++) {
412
+ if (!tagsDic[log.tags[i]]) {
413
+ return false;
414
+ }
415
+ }
416
+ return true;
417
+ };
418
+ this.getLogs = (filter) => {
419
+ if (!filter) {
420
+ return this.logs;
421
+ }
422
+ let res = this.logs;
423
+ if (filter.tags) {
424
+ const dic = this.getTagsDic(filter.tags);
425
+ res = res.filter((o) => this.isTagsMatch(dic, o));
426
+ }
427
+ if (filter.status) {
428
+ res = res.filter((o) => o.status === filter.status);
429
+ }
430
+ return res;
431
+ };
432
+ this.load = p.load;
433
+ this.save = p.save;
371
434
  }
372
435
  }
373
- // const notifications = new NotificationService(db);
374
- // await notifications.init();
375
- // await notifications.notifyAt(
376
- // Date.now() + 10000,
377
- // "Hello",
378
- // "This is persistent notification"
379
- // );
380
436
  export class Tracker {
381
437
  constructor(p) {
382
438
  this.watchId = null;
@@ -423,3 +479,217 @@ export class Tracker {
423
479
  return !!this.watchId;
424
480
  }
425
481
  }
482
+ export class NotificationService {
483
+ constructor(actionCallBack) {
484
+ this.notificationFile = 'notifications.json';
485
+ this.init = (actionCallBack) => __awaiter(this, void 0, void 0, function* () {
486
+ yield LocalNotifications.requestPermissions();
487
+ yield LocalNotifications.addListener('localNotificationReceived', (notification) => __awaiter(this, void 0, void 0, function* () { yield this.handleReceived(notification.id); }));
488
+ yield LocalNotifications.addListener('localNotificationActionPerformed', (event) => __awaiter(this, void 0, void 0, function* () {
489
+ var _a;
490
+ const actions = (_a = event.notification.extra) === null || _a === void 0 ? void 0 : _a.actions;
491
+ const action = actions === null || actions === void 0 ? void 0 : actions.find((action) => action === event.actionId);
492
+ if (!action || !actionCallBack)
493
+ return;
494
+ actionCallBack(action);
495
+ }));
496
+ yield this.resync();
497
+ });
498
+ this.handleReceived = (id) => __awaiter(this, void 0, void 0, function* () {
499
+ const items = yield this.getList();
500
+ const item = items.find(item => item.id === id);
501
+ if (!item)
502
+ return;
503
+ item.showInExpired = false;
504
+ if (item.keepUntil === undefined) {
505
+ yield this.save(items.filter(item => item.id !== id));
506
+ return;
507
+ }
508
+ yield this.save(items);
509
+ });
510
+ this.getChannelId = (item) => {
511
+ var _a, _b;
512
+ return [
513
+ (_a = item.importance) !== null && _a !== void 0 ? _a : 'default',
514
+ (_b = item.sound) !== null && _b !== void 0 ? _b : 'none',
515
+ item.vibration ? 'vibration' : 'no-vibration'
516
+ ].join('-');
517
+ };
518
+ this.registerChannel = (channel) => __awaiter(this, void 0, void 0, function* () {
519
+ yield LocalNotifications.createChannel({
520
+ id: channel.id,
521
+ name: channel.name,
522
+ description: channel.description,
523
+ importance: this.getImportance(channel.importance),
524
+ sound: channel.sound,
525
+ vibration: channel.vibration
526
+ });
527
+ });
528
+ this.register = (_item) => __awaiter(this, void 0, void 0, function* () {
529
+ const items = yield this.getList();
530
+ const id = items.length ? Math.max(...items.map(item => item.id)) + 1 : 1;
531
+ const item = Object.assign(Object.assign({}, _item), { id });
532
+ items.push(item);
533
+ yield this.save(items);
534
+ if (item.fireAt <= Date.now()) {
535
+ if (item.showInExpired) {
536
+ yield this.schedule(item, true);
537
+ item.showInExpired = false;
538
+ yield this.save(items);
539
+ }
540
+ return id;
541
+ }
542
+ yield this.schedule(item);
543
+ return id;
544
+ });
545
+ this.cancel = (p) => __awaiter(this, void 0, void 0, function* () {
546
+ if (p.ids !== undefined) {
547
+ yield this.cancelByIds(p.ids);
548
+ }
549
+ if (p.tags !== undefined) {
550
+ yield this.cancelByTags(p.tags);
551
+ }
552
+ });
553
+ this.cancelByIds = (ids) => __awaiter(this, void 0, void 0, function* () {
554
+ for (const id of ids) {
555
+ yield this.cancelById(id);
556
+ }
557
+ });
558
+ this.cancelById = (id) => __awaiter(this, void 0, void 0, function* () {
559
+ yield LocalNotifications.cancel({ notifications: [{ id }] });
560
+ const items = yield this.getList();
561
+ const newItems = items.filter(item => item.id !== id);
562
+ if (newItems.length !== items.length) {
563
+ yield this.save(newItems);
564
+ }
565
+ });
566
+ this.cancelByTag = (tag) => __awaiter(this, void 0, void 0, function* () {
567
+ const items = yield this.getList();
568
+ const tagItems = items.filter(item => { var _a; return (_a = item.tags) === null || _a === void 0 ? void 0 : _a.includes(tag); });
569
+ for (const item of tagItems) {
570
+ yield this.cancelById(item.id);
571
+ }
572
+ });
573
+ this.cancelByTags = (tags) => __awaiter(this, void 0, void 0, function* () {
574
+ for (const tag of tags) {
575
+ yield this.cancelByTag(tag);
576
+ }
577
+ });
578
+ this.resync = () => __awaiter(this, void 0, void 0, function* () {
579
+ const items = yield this.getList();
580
+ const now = Date.now();
581
+ const pending = yield LocalNotifications.getPending();
582
+ const pendingIds = new Set(pending.notifications.map(notification => notification.id));
583
+ const validItems = [];
584
+ for (const item of items) {
585
+ if (item.keepUntil !== undefined && item.keepUntil <= now) {
586
+ yield LocalNotifications.cancel({ notifications: [{ id: item.id }] });
587
+ continue;
588
+ }
589
+ if (item.fireAt <= now) {
590
+ if (pendingIds.has(item.id)) {
591
+ validItems.push(item);
592
+ continue;
593
+ }
594
+ if (item.showInExpired) {
595
+ yield this.schedule(item, true);
596
+ item.showInExpired = false;
597
+ }
598
+ if (item.keepUntil !== undefined) {
599
+ validItems.push(item);
600
+ }
601
+ continue;
602
+ }
603
+ validItems.push(item);
604
+ if (!pendingIds.has(item.id)) {
605
+ yield this.schedule(item);
606
+ }
607
+ }
608
+ yield this.save(validItems);
609
+ });
610
+ this.schedule = (item, atNow) => __awaiter(this, void 0, void 0, function* () {
611
+ yield this.registerActionType(item);
612
+ const channelId = this.getChannelId(item);
613
+ yield this.registerChannel({ id: channelId, name: channelId, importance: item.importance, sound: item.sound, vibration: item.vibration });
614
+ yield LocalNotifications.schedule({
615
+ notifications: [{
616
+ id: item.id, title: item.title, body: item.body, channelId,
617
+ actionTypeId: this.getActionTypeId(item),
618
+ extra: { actions: item.actions },
619
+ schedule: !atNow ? { at: new Date(item.fireAt) } : undefined
620
+ }]
621
+ });
622
+ });
623
+ this.registerActionType = (item) => __awaiter(this, void 0, void 0, function* () {
624
+ var _b;
625
+ if (!((_b = item.actions) === null || _b === void 0 ? void 0 : _b.length))
626
+ return;
627
+ yield LocalNotifications.registerActionTypes({
628
+ types: [{ id: this.getActionTypeId(item), actions: item.actions.map(action => ({ id: action, title: action })) }]
629
+ });
630
+ });
631
+ this.getActionTypeId = (item) => `notification-${item.id}`;
632
+ this.getImportance = (importance) => {
633
+ switch (importance) {
634
+ case 'low': return 2;
635
+ case 'high': return 4;
636
+ default: return 3;
637
+ }
638
+ };
639
+ this.tagsMatch = (tagsDic, itemTags) => {
640
+ if (!itemTags || !itemTags.length) {
641
+ return false;
642
+ }
643
+ return itemTags.filter((itemTag) => {
644
+ if (!tagsDic[itemTag]) {
645
+ return false;
646
+ }
647
+ });
648
+ return true;
649
+ };
650
+ this.getTagsDic = (tags) => {
651
+ if (!tags) {
652
+ return {};
653
+ }
654
+ const res = {};
655
+ for (let i = 0; i < tags.length; i++) {
656
+ res[tags[i]] = true;
657
+ }
658
+ return res;
659
+ };
660
+ this.getList = (filter) => __awaiter(this, void 0, void 0, function* () {
661
+ try {
662
+ const result = yield Filesystem.readFile({ path: this.notificationFile, directory: Directory.Data, encoding: Encoding.UTF8 });
663
+ const res = JSON.parse(result.data);
664
+ if (!filter) {
665
+ return res;
666
+ }
667
+ else {
668
+ const tagsDic = this.getTagsDic(filter.tags);
669
+ const now = Date.now();
670
+ return res.filter((o) => {
671
+ if (filter.fired !== undefined) {
672
+ const fired = o.fireAt < now;
673
+ if (filter.fired && !fired) {
674
+ return false;
675
+ }
676
+ if (!filter.fired && fired) {
677
+ return false;
678
+ }
679
+ }
680
+ if (filter.tags && filter.tags.length) {
681
+ return this.tagsMatch(tagsDic, filter.tags);
682
+ }
683
+ });
684
+ }
685
+ }
686
+ catch (_c) {
687
+ return [];
688
+ }
689
+ });
690
+ this.save = (items) => __awaiter(this, void 0, void 0, function* () {
691
+ yield Filesystem.writeFile({ path: this.notificationFile, directory: Directory.Data, data: JSON.stringify(items), encoding: Encoding.UTF8 });
692
+ });
693
+ this.init(actionCallBack);
694
+ }
695
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aio-capacitor",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -8,7 +8,19 @@
8
8
  "test": "echo \"Error: no test specified\" && exit 1"
9
9
  },
10
10
  "dependencies": {
11
- "aio-capacitor-deps": "latest",
11
+ "@capacitor-community/keep-awake": "latest",
12
+ "@capacitor-community/text-to-speech": "latest",
13
+ "@capacitor/camera": "latest",
14
+ "@capacitor/clipboard": "latest",
15
+ "@capacitor/core": "latest",
16
+ "@capacitor/filesystem": "latest",
17
+ "@capacitor/geolocation": "latest",
18
+ "@capacitor/haptics": "latest",
19
+ "@capacitor/local-notifications": "latest",
20
+ "@capacitor/preferences": "latest",
21
+ "@capacitor/push-notifications": "latest",
22
+ "@capacitor/share": "latest",
23
+ "aio-capacitor-folder-picker":"latest",
12
24
  "aio-class":"latest"
13
25
  },
14
26
  "repository": {