@greatdayhr/capacitor-datetime-setting 1.1.2 → 2.0.0

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.
package/README.md CHANGED
@@ -1,141 +1,442 @@
1
1
  # Capacitor DateTime Setting Plugin
2
2
 
3
- Capacitor plugin to get information about auto time and auto timezone settings, and open device settings if needed.
3
+ [![npm version](https://img.shields.io/npm/v/@greatdayhr/capacitor-datetime-setting.svg)](https://www.npmjs.com/package/@greatdayhr/capacitor-datetime-setting)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
5
 
5
- This plugin is a Capacitor port of the Flutter [datetime_setting](https://github.com/fuadarradhi/datetime_setting) plugin.
6
+ Capacitor plugin for comprehensive date/time management on iOS. Cloned from [date_change_checker](https://github.com/error404sushant/date_change_checker) Flutter plugin.
7
+
8
+ **Features:**
9
+ - Detect manual date/time changes with network validation
10
+ - Comprehensive change analysis (date-only, time-only, or both)
11
+ - Automatic user notifications for detected changes
12
+ - Fetch accurate internet time from time servers
13
+ - Timestamp management for change tracking
14
+ - Network-optimized with caching and offline fallback
15
+
16
+ **Platform Support:**
17
+ - ✅ **iOS**: Full implementation (10 methods)
18
+ - ❌ **Android**: Not implemented (use native Settings API directly)
19
+ - ❌ **Web**: Not supported
6
20
 
7
21
  ## Installation
8
22
 
9
23
  ```bash
10
- npm install capacitor-datetime-setting
11
- npx cap sync
24
+ npm install @greatdayhr/capacitor-datetime-setting
25
+ npx cap sync ios
12
26
  ```
13
27
 
14
28
  ## API
15
29
 
16
- ### `timeIsAuto()`
30
+ ### Date/Time Change Detection
17
31
 
18
- Check if automatic time is enabled on the device.
32
+ #### `detectDateTimeChange()`
19
33
 
20
- **Returns:** `Promise<{ value: boolean }>`
34
+ Detects if the device's date/time has been manually changed. Uses network time comparison for accuracy when available, falls back to local time comparison offline.
21
35
 
22
- **Platform Support:**
23
- - ✅ Android: Returns actual setting value using `Settings.Global.AUTO_TIME`
24
- - iOS: Returns actual setting value using `NSTimeZone.autoupdatingCurrent` comparison
36
+ **Returns:** `Promise<{ changed: boolean }>`
37
+
38
+ **Platform Support:** iOS only
25
39
 
26
40
  **Example:**
27
41
 
28
42
  ```typescript
29
- import { DateTimeSetting } from 'capacitor-datetime-setting';
43
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
30
44
 
31
- const result = await DateTimeSetting.timeIsAuto();
32
- console.log('Auto time enabled:', result.value);
45
+ const result = await DateTimeSetting.detectDateTimeChange();
46
+ if (result.changed) {
47
+ console.log('Date/time has been manually changed!');
48
+ }
33
49
  ```
34
50
 
35
51
  ---
36
52
 
37
- ### `timeZoneIsAuto()`
53
+ #### `detectComprehensiveDateTimeChange()`
38
54
 
39
- Check if automatic timezone is enabled on the device.
55
+ Comprehensive date and time change detection with detailed analysis. Distinguishes between date-only, time-only, and combined changes.
40
56
 
41
- **Returns:** `Promise<{ value: boolean }>`
57
+ **Returns:** `Promise<DateTimeChangeResult>`
42
58
 
43
- **Platform Support:**
44
- - Android: Returns actual setting value using `Settings.Global.AUTO_TIME_ZONE`
45
- - ✅ iOS: Returns actual setting value using `NSTimeZone.autoupdatingCurrent` comparison
59
+ ```typescript
60
+ interface DateTimeChangeResult {
61
+ changeType: 'noChange' | 'timeOnly' | 'dateOnly' | 'dateAndTime';
62
+ timeDifference: number;
63
+ dateChanged: boolean;
64
+ timeChanged: boolean;
65
+ isAutoDateTimeEnabled: boolean;
66
+ previousDate?: number;
67
+ currentDate: number;
68
+ }
69
+ ```
70
+
71
+ **Platform Support:** iOS only
72
+
73
+ **Example:**
74
+
75
+ ```typescript
76
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
77
+
78
+ const result = await DateTimeSetting.detectComprehensiveDateTimeChange();
79
+ console.log('Change type:', result.changeType);
80
+ console.log('Date changed:', result.dateChanged);
81
+ console.log('Time changed:', result.timeChanged);
82
+ console.log('Time difference:', result.timeDifference, 'seconds');
83
+ console.log('Auto time enabled:', result.isAutoDateTimeEnabled);
84
+ ```
85
+
86
+ ---
87
+
88
+ #### `detectDateOnlyChange()`
89
+
90
+ Detects specifically if only the date has been changed while time remains similar. Useful for detecting manual date changes when auto date/time is disabled.
91
+
92
+ **Returns:** `Promise<{ changed: boolean }>`
93
+
94
+ **Platform Support:** iOS only
95
+
96
+ **Example:**
97
+
98
+ ```typescript
99
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
100
+
101
+ const result = await DateTimeSetting.detectDateOnlyChange();
102
+ if (result.changed) {
103
+ console.log('Only the date was changed!');
104
+ }
105
+ ```
106
+
107
+ ---
108
+
109
+ #### `detectAndNotifyDateTimeChanges()`
110
+
111
+ Comprehensive date and time change detection with automatic user notifications. Shows native iOS notifications when changes are detected.
112
+
113
+ **Returns:** `Promise<DateTimeChangeResult>`
114
+
115
+ **Platform Support:** iOS only
46
116
 
47
117
  **Example:**
48
118
 
49
119
  ```typescript
50
- import { DateTimeSetting } from 'capacitor-datetime-setting';
120
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
121
+
122
+ const result = await DateTimeSetting.detectAndNotifyDateTimeChanges();
123
+ // User automatically sees notification if changes detected
124
+ console.log('Change type:', result.changeType);
125
+ ```
126
+
127
+ ---
128
+
129
+ ### Time Utilities
130
+
131
+ #### `getLocalTime()`
132
+
133
+ Get the device's current local time as Unix timestamp.
134
+
135
+ **Returns:** `Promise<{ timestamp: number }>`
136
+
137
+ **Platform Support:** iOS only
138
+
139
+ **Example:**
140
+
141
+ ```typescript
142
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
143
+
144
+ const result = await DateTimeSetting.getLocalTime();
145
+ const date = new Date(result.timestamp * 1000);
146
+ console.log('Current local time:', date);
147
+ ```
148
+
149
+ ---
150
+
151
+ #### `getInternetUTCTime()`
152
+
153
+ Fetch accurate UTC time from internet time server (WorldTimeAPI).
154
+
155
+ **Returns:** `Promise<{ timestamp: number }>`
156
+
157
+ **Platform Support:** iOS only
51
158
 
52
- const result = await DateTimeSetting.timeZoneIsAuto();
53
- console.log('Auto timezone enabled:', result.value);
159
+ **Example:**
160
+
161
+ ```typescript
162
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
163
+
164
+ try {
165
+ const result = await DateTimeSetting.getInternetUTCTime();
166
+ const date = new Date(result.timestamp * 1000);
167
+ console.log('Internet UTC time:', date);
168
+ } catch (error) {
169
+ console.error('Failed to fetch internet time:', error);
170
+ }
54
171
  ```
55
172
 
56
173
  ---
57
174
 
58
- ### `openSetting()`
175
+ #### `convertToLocalTime(options)`
59
176
 
60
- Open the device's date and time settings screen.
177
+ Convert local time to UTC.
178
+
179
+ **Parameters:**
180
+ - `options.timestamp` (number): Unix timestamp to convert
181
+
182
+ **Returns:** `Promise<{ timestamp: number }>`
183
+
184
+ **Platform Support:** iOS only
185
+
186
+ **Example:**
187
+
188
+ ```typescript
189
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
190
+
191
+ const localTimestamp = Date.now() / 1000;
192
+ const result = await DateTimeSetting.convertToLocalTime({
193
+ timestamp: localTimestamp
194
+ });
195
+ console.log('UTC timestamp:', result.timestamp);
196
+ ```
197
+
198
+ ---
199
+
200
+ ### Timestamp Management
201
+
202
+ #### `setStoredTimestamp(options)`
203
+
204
+ Set the stored timestamp for future change detection comparisons.
205
+
206
+ **Parameters:**
207
+ - `options.timestamp` (number): Unix timestamp to store
61
208
 
62
209
  **Returns:** `Promise<void>`
63
210
 
64
- **Platform Support:**
65
- - ✅ Android: Opens Date & Time settings directly
66
- - ⚠️ iOS: Opens main Settings app (cannot open specific settings page)
211
+ **Platform Support:** iOS only
212
+
213
+ **Example:**
214
+
215
+ ```typescript
216
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
217
+
218
+ const currentTimestamp = Date.now() / 1000;
219
+ await DateTimeSetting.setStoredTimestamp({
220
+ timestamp: currentTimestamp
221
+ });
222
+ ```
223
+
224
+ ---
225
+
226
+ #### `getStoredTimestamp()`
227
+
228
+ Get the currently stored timestamp used for change detection.
229
+
230
+ **Returns:** `Promise<{ timestamp: number | null }>`
231
+
232
+ **Platform Support:** iOS only
67
233
 
68
234
  **Example:**
69
235
 
70
236
  ```typescript
71
- import { DateTimeSetting } from 'capacitor-datetime-setting';
237
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
238
+
239
+ const result = await DateTimeSetting.getStoredTimestamp();
240
+ if (result.timestamp) {
241
+ const date = new Date(result.timestamp * 1000);
242
+ console.log('Stored timestamp:', date);
243
+ } else {
244
+ console.log('No timestamp stored');
245
+ }
246
+ ```
247
+
248
+ ---
249
+
250
+ #### `resetDetector()`
251
+
252
+ Reset the detector, clearing all stored data and cache.
72
253
 
73
- await DateTimeSetting.openSetting();
254
+ **Returns:** `Promise<void>`
255
+
256
+ **Platform Support:** iOS only
257
+
258
+ **Example:**
259
+
260
+ ```typescript
261
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
262
+
263
+ await DateTimeSetting.resetDetector();
264
+ console.log('Detector has been reset');
74
265
  ```
75
266
 
267
+ ---
268
+
76
269
  ## Usage Example
77
270
 
78
- Here's a complete example showing how to check settings and prompt user to enable auto time:
271
+ Here's a complete example showing how to detect and respond to date/time changes:
79
272
 
80
273
  ```typescript
81
- import { DateTimeSetting } from 'capacitor-datetime-setting';
274
+ import { DateTimeSetting } from '@greatdayhr/capacitor-datetime-setting';
82
275
  import { Capacitor } from '@capacitor/core';
83
276
 
84
- async function checkAutoTimeSettings() {
277
+ async function monitorDateTimeChanges() {
278
+ // Only works on iOS
279
+ if (Capacitor.getPlatform() !== 'ios') {
280
+ console.log('Date/time detection only available on iOS');
281
+ return;
282
+ }
283
+
85
284
  try {
86
- const timeResult = await DateTimeSetting.timeIsAuto();
87
- const timezoneResult = await DateTimeSetting.timeZoneIsAuto();
285
+ // Initialize with current timestamp
286
+ const now = Date.now() / 1000;
287
+ await DateTimeSetting.setStoredTimestamp({ timestamp: now });
88
288
 
89
- const platform = Capacitor.getPlatform();
289
+ // Detect changes with notifications
290
+ const result = await DateTimeSetting.detectAndNotifyDateTimeChanges();
90
291
 
91
- // Both Android and iOS can now detect auto time settings
92
- if (!timeResult.value || !timezoneResult.value) {
93
- // Show alert to user
94
- const shouldOpen = confirm(
95
- 'Please enable automatic date & time and timezone for accurate time tracking.'
96
- );
292
+ if (result.changeType !== 'noChange') {
293
+ console.log('Change detected!');
294
+ console.log('Type:', result.changeType);
295
+ console.log('Auto time enabled:', result.isAutoDateTimeEnabled);
97
296
 
98
- if (shouldOpen) {
99
- await DateTimeSetting.openSetting();
297
+ // Handle the change
298
+ if (!result.isAutoDateTimeEnabled) {
299
+ alert('Please enable automatic date & time in Settings');
100
300
  }
101
301
  }
102
302
  } catch (error) {
103
- console.error('Error checking time settings:', error);
303
+ console.error('Error detecting time changes:', error);
104
304
  }
105
305
  }
306
+
307
+ // Call this periodically or on app resume
308
+ monitorDateTimeChanges();
106
309
  ```
107
310
 
108
311
  ## Platform-Specific Notes
109
312
 
110
- ### Android
313
+ ### iOS
111
314
 
112
- The plugin uses Android's `Settings.Global` API to check the auto time and timezone settings. It supports Android API level 17 (Jelly Bean MR1) and above, with fallback to `Settings.System` for older versions.
315
+ The plugin uses a comprehensive multi-layered approach for reliable date/time detection:
113
316
 
114
- **Permissions:** No special permissions required.
317
+ #### Detection Method
115
318
 
116
- ### iOS
319
+ 1. **Cache Check** (Instant)
320
+ - Returns cached result if available and less than 30 seconds old
321
+ - Avoids unnecessary network calls for better performance
322
+
323
+ 2. **Quick Timezone Check** (Preliminary)
324
+ - Compares `TimeZone.autoupdatingCurrent` with `TimeZone.current`
325
+ - If they differ, auto date/time is definitely disabled
326
+ - Provides fast response for obvious cases
327
+
328
+ 3. **Network Time Comparison** (Primary)
329
+ - Fetches accurate UTC time from `https://worldtimeapi.org/api/timezone/Etc/UTC`
330
+ - Compares device time with server time
331
+ - **Threshold**: Time difference > 60 seconds indicates disabled auto date/time
332
+ - **Timeout**: 3 seconds for network request
333
+ - **Async**: Non-blocking operation with completion handler
117
334
 
118
- iOS does not provide direct public APIs to check auto date/time settings, but this plugin uses a **workaround** technique:
335
+ 4. **Offline Fallback** (When Network Unavailable)
336
+ - Uses timezone comparison method
337
+ - Considers system uptime for better accuracy
338
+ - Ensures plugin works without network connection
119
339
 
120
- **Detection Method:**
121
- - Compares `NSTimeZone.autoupdatingCurrent` with `NSTimeZone.system`
122
- - When auto date/time is **enabled**: these two timezone objects are equal
123
- - When auto date/time is **disabled**: they may differ
340
+ #### Features
124
341
 
125
- **Limitations:**
126
- - `openSetting()` opens the main Settings app instead of the specific Date & Time page (iOS restriction)
127
- - The detection method is a workaround and may not be 100% accurate in all edge cases
342
+ - ✅ **High Accuracy**: Detects manual time changes even if timezone is correct
343
+ - **Performance Optimized**: 30-second cache reduces network overhead
344
+ - **Offline Ready**: Falls back gracefully when network is unavailable
345
+ - ✅ **Battery Friendly**: Network monitoring prevents unnecessary requests
346
+ - ✅ **Non-Blocking**: Async operations don't freeze the UI
347
+ - ✅ **Automatic Cleanup**: Proper resource management on plugin deallocation
348
+ - ✅ **User Notifications**: Automatic native notifications for detected changes
128
349
 
129
- **Credit:** This technique is inspired by the Flutter [date_change_checker](https://github.com/error404sushant/date_change_checker) plugin.
350
+ #### Limitations
351
+
352
+ - First call after app launch requires network for best accuracy (cached afterward)
353
+ - Network check timeout is 3 seconds
354
+ - Assumes time difference > 60 seconds means auto-time is disabled
355
+ - Notifications require user permission
356
+
357
+ ### Android
358
+
359
+ **Not implemented.** The source plugin (date_change_checker) only has basic Settings checks on Android, which can be easily done with native code:
360
+
361
+ ```java
362
+ // Check if auto time is enabled
363
+ boolean isAutoTime = Settings.Global.getInt(
364
+ context.getContentResolver(),
365
+ Settings.Global.AUTO_TIME,
366
+ 0
367
+ ) == 1;
368
+
369
+ // Check if auto timezone is enabled
370
+ boolean isAutoTimeZone = Settings.Global.getInt(
371
+ context.getContentResolver(),
372
+ Settings.Global.AUTO_TIME_ZONE,
373
+ 0
374
+ ) == 1;
375
+ ```
376
+
377
+ Android doesn't need the complex network validation that iOS requires because it has direct Settings API access.
130
378
 
131
379
  ### Web
132
380
 
133
381
  This plugin is not supported on web. All methods will throw "Not implemented on web" errors.
134
382
 
383
+ ## Troubleshooting
384
+
385
+ ### iOS: Detection always returns true/false
386
+
387
+ **Problem**: The plugin always returns the same result regardless of actual settings.
388
+
389
+ **Solutions**:
390
+ 1. **Check network connectivity**: The plugin needs internet access for accurate detection
391
+ 2. **Wait for cache to expire**: If testing, wait 30+ seconds between tests
392
+ 3. **Check time difference**: Ensure your manual time is >60 seconds different from actual time
393
+ 4. **Verify WorldTimeAPI is accessible**: The plugin uses `https://worldtimeapi.org`
394
+
395
+ ### iOS: Slow first response
396
+
397
+ **Problem**: First call to detection methods takes 3+ seconds.
398
+
399
+ **Explanation**: This is expected behavior. The first call makes a network request to fetch accurate time. Subsequent calls within 30 seconds use cached results and return instantly.
400
+
401
+ **Solution**: Pre-warm the cache by calling a detection method during app initialization with a loading indicator.
402
+
403
+ ### iOS: Plugin doesn't work in airplane mode
404
+
405
+ **Problem**: Plugin returns unexpected results when device is offline.
406
+
407
+ **Explanation**: The plugin falls back to timezone-based detection when offline, which is less accurate.
408
+
409
+ **Solution**: This is expected behavior. For best accuracy, ensure network connectivity. The offline fallback is a compromise for offline scenarios.
410
+
411
+ ### iOS: Notifications not showing
412
+
413
+ **Problem**: No notifications appear when changes are detected.
414
+
415
+ **Solutions**:
416
+ 1. Ensure notification permissions are granted
417
+ 2. Check device notification settings
418
+ 3. The plugin requests permission on first load - user might have denied it
419
+
420
+ ## Version History
421
+
422
+ See [CHANGELOG.md](CHANGELOG.md) for detailed version history.
423
+
424
+ **Latest version (2.0.0)**:
425
+ - ✨ Cloned all iOS functionality from date_change_checker Flutter plugin
426
+ - ✨ Added comprehensive date/time change detection methods (4 methods)
427
+ - ✨ Added automatic user notifications for date/time changes (iOS)
428
+ - ✨ Added time utility methods (3 methods)
429
+ - ✨ Added timestamp management for change tracking (3 methods)
430
+ - ✨ Added `NotificationManager` for iOS notifications (259 lines)
431
+ - 🔧 Enhanced `AutoDateTimeDetector` with comprehensive 671-line implementation
432
+ - 📝 Complete TypeScript definitions for all methods
433
+ - 🎯 iOS-only implementation (matches source plugin's platform support)
434
+ - ❌ Removed Android/Web implementations (source plugin has minimal Android support)
435
+
135
436
  ## License
136
437
 
137
438
  MIT
138
439
 
139
440
  ## Credits
140
441
 
141
- This plugin is based on the Flutter [datetime_setting](https://github.com/fuadarradhi/datetime_setting) plugin by [fuadarradhi](https://github.com/fuadarradhi).
442
+ This plugin is a Capacitor port of the Flutter [date_change_checker](https://github.com/error404sushant/date_change_checker) plugin. All iOS implementation logic is cloned from the original source.
@@ -1,101 +1,20 @@
1
1
  package com.datetimesetting;
2
2
 
3
- import android.content.Intent;
4
- import android.os.Build;
5
- import android.provider.Settings;
6
-
7
- import com.getcapacitor.JSObject;
8
3
  import com.getcapacitor.Plugin;
9
- import com.getcapacitor.PluginCall;
10
- import com.getcapacitor.PluginMethod;
11
4
  import com.getcapacitor.annotation.CapacitorPlugin;
12
5
 
13
6
  /**
14
- * DateTimeSettingPlugin
7
+ * DateTimeSettingPlugin - Android Implementation
8
+ *
9
+ * Note: All date/time detection methods are iOS-only.
10
+ * Android does not implement the comprehensive features from date_change_checker
11
+ * because the source plugin itself only has basic Settings checks on Android.
15
12
  *
16
- * Capacitor plugin to check auto time/timezone settings and open device settings.
13
+ * For Android auto time detection, use native Settings API directly:
14
+ * Settings.Global.getInt(context.getContentResolver(), Settings.Global.AUTO_TIME, 0) == 1
17
15
  */
18
16
  @CapacitorPlugin(name = "DateTimeSetting")
19
17
  public class DateTimeSettingPlugin extends Plugin {
20
-
21
- /**
22
- * Check if automatic time is enabled on the device.
23
- *
24
- * @param call The plugin call
25
- */
26
- @PluginMethod
27
- public void timeIsAuto(PluginCall call) {
28
- try {
29
- boolean isAuto;
30
-
31
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
32
- isAuto = Settings.Global.getInt(
33
- getContext().getContentResolver(),
34
- Settings.Global.AUTO_TIME,
35
- 0
36
- ) == 1;
37
- } else {
38
- isAuto = Settings.System.getInt(
39
- getContext().getContentResolver(),
40
- Settings.System.AUTO_TIME,
41
- 0
42
- ) == 1;
43
- }
44
-
45
- JSObject result = new JSObject();
46
- result.put("value", isAuto);
47
- call.resolve(result);
48
- } catch (Exception e) {
49
- call.reject("Failed to check auto time setting", e);
50
- }
51
- }
52
-
53
- /**
54
- * Check if automatic timezone is enabled on the device.
55
- *
56
- * @param call The plugin call
57
- */
58
- @PluginMethod
59
- public void timeZoneIsAuto(PluginCall call) {
60
- try {
61
- boolean isAuto;
62
-
63
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
64
- isAuto = Settings.Global.getInt(
65
- getContext().getContentResolver(),
66
- Settings.Global.AUTO_TIME_ZONE,
67
- 0
68
- ) == 1;
69
- } else {
70
- isAuto = Settings.System.getInt(
71
- getContext().getContentResolver(),
72
- Settings.System.AUTO_TIME_ZONE,
73
- 0
74
- ) == 1;
75
- }
76
-
77
- JSObject result = new JSObject();
78
- result.put("value", isAuto);
79
- call.resolve(result);
80
- } catch (Exception e) {
81
- call.reject("Failed to check auto timezone setting", e);
82
- }
83
- }
84
-
85
- /**
86
- * Open the device's date and time settings screen.
87
- *
88
- * @param call The plugin call
89
- */
90
- @PluginMethod
91
- public void openSetting(PluginCall call) {
92
- try {
93
- Intent intent = new Intent(Settings.ACTION_DATE_SETTINGS);
94
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
95
- getContext().startActivity(intent);
96
- call.resolve();
97
- } catch (Exception e) {
98
- call.reject("Failed to open date/time settings", e);
99
- }
100
- }
18
+ // All methods are iOS-only
19
+ // Android implementation intentionally left minimal as per date_change_checker source
101
20
  }