@elizaos/capacitor-appblocker 1.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.
@@ -0,0 +1,65 @@
1
+ package ai.eliza.plugins.appblocker
2
+
3
+ import android.content.Context
4
+
5
+ data class SavedAppBlock(
6
+ val packageNames: List<String>,
7
+ val endsAtEpochMs: Long?,
8
+ )
9
+
10
+ object AppBlockerStateStore {
11
+ private const val PREFS_NAME = "eliza_app_blocker"
12
+ private const val KEY_PACKAGE_NAMES = "blocked_package_names"
13
+ private const val KEY_ENDS_AT = "ends_at_epoch_ms"
14
+
15
+ private fun prefs(context: Context) =
16
+ context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
17
+
18
+ fun load(context: Context): SavedAppBlock? {
19
+ val preferences = prefs(context)
20
+ val packageNames = preferences.getStringSet(KEY_PACKAGE_NAMES, null)
21
+ ?.toList()
22
+ ?.sorted()
23
+ ?: return null
24
+ if (packageNames.isEmpty()) {
25
+ return null
26
+ }
27
+
28
+ val endsAtEpochMs = if (preferences.contains(KEY_ENDS_AT)) {
29
+ preferences.getLong(KEY_ENDS_AT, 0L)
30
+ } else {
31
+ null
32
+ }
33
+
34
+ if (endsAtEpochMs != null && endsAtEpochMs <= System.currentTimeMillis()) {
35
+ clear(context)
36
+ return null
37
+ }
38
+
39
+ return SavedAppBlock(
40
+ packageNames = packageNames,
41
+ endsAtEpochMs = endsAtEpochMs,
42
+ )
43
+ }
44
+
45
+ fun save(context: Context, packageNames: List<String>, endsAtEpochMs: Long?) {
46
+ prefs(context).edit().apply {
47
+ putStringSet(KEY_PACKAGE_NAMES, packageNames.toSet())
48
+ if (endsAtEpochMs != null) {
49
+ putLong(KEY_ENDS_AT, endsAtEpochMs)
50
+ } else {
51
+ remove(KEY_ENDS_AT)
52
+ }
53
+ apply()
54
+ }
55
+ }
56
+
57
+ fun clear(context: Context) {
58
+ prefs(context).edit().clear().apply()
59
+ }
60
+
61
+ fun isBlocked(context: Context, packageName: String): Boolean {
62
+ val saved = load(context) ?: return false
63
+ return saved.packageNames.contains(packageName)
64
+ }
65
+ }
@@ -0,0 +1,53 @@
1
+ export type AppBlockerPermissionStatus = "granted" | "denied" | "not-determined" | "not-applicable";
2
+ export interface AppBlockerPermissionResult {
3
+ status: AppBlockerPermissionStatus;
4
+ canRequest: boolean;
5
+ reason?: string;
6
+ }
7
+ export interface InstalledApp {
8
+ packageName: string;
9
+ displayName: string;
10
+ tokenData?: string;
11
+ }
12
+ export interface SelectAppsResult {
13
+ apps: InstalledApp[];
14
+ cancelled: boolean;
15
+ }
16
+ export interface BlockAppsOptions {
17
+ appTokens?: string[];
18
+ packageNames?: string[];
19
+ durationMinutes?: number | null;
20
+ }
21
+ export interface BlockAppsResult {
22
+ success: boolean;
23
+ endsAt: string | null;
24
+ error?: string;
25
+ blockedCount: number;
26
+ }
27
+ export interface UnblockAppsResult {
28
+ success: boolean;
29
+ error?: string;
30
+ }
31
+ export interface AppBlockerStatus {
32
+ available: boolean;
33
+ active: boolean;
34
+ platform: string;
35
+ engine: "family-controls" | "usage-stats-overlay" | "none";
36
+ blockedCount: number;
37
+ blockedPackageNames: string[];
38
+ endsAt: string | null;
39
+ permissionStatus: AppBlockerPermissionStatus;
40
+ reason?: string;
41
+ }
42
+ export interface AppBlockerPlugin {
43
+ checkPermissions(): Promise<AppBlockerPermissionResult>;
44
+ requestPermissions(): Promise<AppBlockerPermissionResult>;
45
+ getInstalledApps(): Promise<{
46
+ apps: InstalledApp[];
47
+ }>;
48
+ selectApps(): Promise<SelectAppsResult>;
49
+ blockApps(options: BlockAppsOptions): Promise<BlockAppsResult>;
50
+ unblockApps(): Promise<UnblockAppsResult>;
51
+ getStatus(): Promise<AppBlockerStatus>;
52
+ }
53
+ //# sourceMappingURL=definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,0BAA0B,GAClC,SAAS,GACT,QAAQ,GACR,gBAAgB,GAChB,gBAAgB,CAAC;AAErB,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,0BAA0B,CAAC;IACnC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,iBAAiB,GAAG,qBAAqB,GAAG,MAAM,CAAC;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,gBAAgB,EAAE,0BAA0B,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;IACxD,kBAAkB,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC1D,gBAAgB,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC,CAAC;IACtD,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACxC,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/D,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC1C,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACxC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import type { AppBlockerPlugin } from "./definitions";
2
+ export * from "./definitions";
3
+ export declare const AppBlocker: AppBlockerPlugin;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,cAAc,eAAe,CAAC;AAK9B,eAAO,MAAM,UAAU,kBAErB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { registerPlugin } from "@capacitor/core";
2
+ export * from "./definitions";
3
+ const loadWeb = () => import("./web").then((module) => new module.AppBlockerWeb());
4
+ export const AppBlocker = registerPlugin("ElizaAppBlocker", {
5
+ web: loadWeb,
6
+ });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,cAAc,eAAe,CAAC;AAE9B,MAAM,OAAO,GAAG,GAAG,EAAE,CACnB,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;AAE/D,MAAM,CAAC,MAAM,UAAU,GAAG,cAAc,CAAmB,iBAAiB,EAAE;IAC5E,GAAG,EAAE,OAAO;CACb,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { WebPlugin } from "@capacitor/core";
2
+ import type { AppBlockerPermissionResult, AppBlockerStatus, BlockAppsOptions, BlockAppsResult, SelectAppsResult, UnblockAppsResult } from "./definitions";
3
+ export declare class AppBlockerWeb extends WebPlugin {
4
+ checkPermissions(): Promise<AppBlockerPermissionResult>;
5
+ requestPermissions(): Promise<AppBlockerPermissionResult>;
6
+ getInstalledApps(): Promise<{
7
+ apps: [];
8
+ }>;
9
+ selectApps(): Promise<SelectAppsResult>;
10
+ blockApps(_options: BlockAppsOptions): Promise<BlockAppsResult>;
11
+ unblockApps(): Promise<UnblockAppsResult>;
12
+ getStatus(): Promise<AppBlockerStatus>;
13
+ }
14
+ //# sourceMappingURL=web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,eAAe,CAAC;AAEvB,qBAAa,aAAc,SAAQ,SAAS;IACpC,gBAAgB,IAAI,OAAO,CAAC,0BAA0B,CAAC;IAQvD,kBAAkB,IAAI,OAAO,CAAC,0BAA0B,CAAC;IAQzD,gBAAgB,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,EAAE,CAAA;KAAE,CAAC;IAIzC,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAIvC,SAAS,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAS/D,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAOzC,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAa7C"}
@@ -0,0 +1,51 @@
1
+ import { WebPlugin } from "@capacitor/core";
2
+ export class AppBlockerWeb extends WebPlugin {
3
+ async checkPermissions() {
4
+ return {
5
+ status: "not-applicable",
6
+ canRequest: false,
7
+ reason: "App blocking is only available on mobile devices.",
8
+ };
9
+ }
10
+ async requestPermissions() {
11
+ return {
12
+ status: "not-applicable",
13
+ canRequest: false,
14
+ reason: "App blocking is only available on mobile devices.",
15
+ };
16
+ }
17
+ async getInstalledApps() {
18
+ return { apps: [] };
19
+ }
20
+ async selectApps() {
21
+ return { apps: [], cancelled: true };
22
+ }
23
+ async blockApps(_options) {
24
+ return {
25
+ success: false,
26
+ endsAt: null,
27
+ error: "App blocking is only available on mobile devices.",
28
+ blockedCount: 0,
29
+ };
30
+ }
31
+ async unblockApps() {
32
+ return {
33
+ success: false,
34
+ error: "App blocking is only available on mobile devices.",
35
+ };
36
+ }
37
+ async getStatus() {
38
+ return {
39
+ available: false,
40
+ active: false,
41
+ platform: "web",
42
+ engine: "none",
43
+ blockedCount: 0,
44
+ blockedPackageNames: [],
45
+ endsAt: null,
46
+ permissionStatus: "not-applicable",
47
+ reason: "App blocking is only available on mobile devices.",
48
+ };
49
+ }
50
+ }
51
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAU5C,MAAM,OAAO,aAAc,SAAQ,SAAS;IAC1C,KAAK,CAAC,gBAAgB;QACpB,OAAO;YACL,MAAM,EAAE,gBAAgB;YACxB,UAAU,EAAE,KAAK;YACjB,MAAM,EAAE,mDAAmD;SAC5D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,OAAO;YACL,MAAM,EAAE,gBAAgB;YACxB,UAAU,EAAE,KAAK;YACjB,MAAM,EAAE,mDAAmD;SAC5D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,QAA0B;QACxC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,mDAAmD;YAC1D,YAAY,EAAE,CAAC;SAChB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,mDAAmD;SAC3D,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS;QACb,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,KAAK;YACf,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,CAAC;YACf,mBAAmB,EAAE,EAAE;YACvB,MAAM,EAAE,IAAI;YACZ,gBAAgB,EAAE,gBAAgB;YAClC,MAAM,EAAE,mDAAmD;SAC5D,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+
3
+ var core = require('@capacitor/core');
4
+
5
+ const loadWeb = () => Promise.resolve().then(function () { return web; }).then((module) => new module.AppBlockerWeb());
6
+ const AppBlocker = core.registerPlugin("ElizaAppBlocker", {
7
+ web: loadWeb,
8
+ });
9
+
10
+ class AppBlockerWeb extends core.WebPlugin {
11
+ async checkPermissions() {
12
+ return {
13
+ status: "not-applicable",
14
+ canRequest: false,
15
+ reason: "App blocking is only available on mobile devices.",
16
+ };
17
+ }
18
+ async requestPermissions() {
19
+ return {
20
+ status: "not-applicable",
21
+ canRequest: false,
22
+ reason: "App blocking is only available on mobile devices.",
23
+ };
24
+ }
25
+ async getInstalledApps() {
26
+ return { apps: [] };
27
+ }
28
+ async selectApps() {
29
+ return { apps: [], cancelled: true };
30
+ }
31
+ async blockApps(_options) {
32
+ return {
33
+ success: false,
34
+ endsAt: null,
35
+ error: "App blocking is only available on mobile devices.",
36
+ blockedCount: 0,
37
+ };
38
+ }
39
+ async unblockApps() {
40
+ return {
41
+ success: false,
42
+ error: "App blocking is only available on mobile devices.",
43
+ };
44
+ }
45
+ async getStatus() {
46
+ return {
47
+ available: false,
48
+ active: false,
49
+ platform: "web",
50
+ engine: "none",
51
+ blockedCount: 0,
52
+ blockedPackageNames: [],
53
+ endsAt: null,
54
+ permissionStatus: "not-applicable",
55
+ reason: "App blocking is only available on mobile devices.",
56
+ };
57
+ }
58
+ }
59
+
60
+ var web = /*#__PURE__*/Object.freeze({
61
+ __proto__: null,
62
+ AppBlockerWeb: AppBlockerWeb
63
+ });
64
+
65
+ exports.AppBlocker = AppBlocker;
66
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((module) => new module.AppBlockerWeb());\nexport const AppBlocker = registerPlugin(\"ElizaAppBlocker\", {\n web: loadWeb,\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nexport class AppBlockerWeb extends WebPlugin {\n async checkPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async requestPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async getInstalledApps() {\n return { apps: [] };\n }\n async selectApps() {\n return { apps: [], cancelled: true };\n }\n async blockApps(_options) {\n return {\n success: false,\n endsAt: null,\n error: \"App blocking is only available on mobile devices.\",\n blockedCount: 0,\n };\n }\n async unblockApps() {\n return {\n success: false,\n error: \"App blocking is only available on mobile devices.\",\n };\n }\n async getStatus() {\n return {\n available: false,\n active: false,\n platform: \"web\",\n engine: \"none\",\n blockedCount: 0,\n blockedPackageNames: [],\n endsAt: null,\n permissionStatus: \"not-applicable\",\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AAEA,MAAM,OAAO,GAAG,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;AACtE,MAAC,UAAU,GAAGA,mBAAc,CAAC,iBAAiB,EAAE;AAC5D,IAAI,GAAG,EAAE,OAAO;AAChB,CAAC;;ACJM,MAAM,aAAa,SAASC,cAAS,CAAC;AAC7C,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,OAAO;AACf,YAAY,MAAM,EAAE,gBAAgB;AACpC,YAAY,UAAU,EAAE,KAAK;AAC7B,YAAY,MAAM,EAAE,mDAAmD;AACvE,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,OAAO;AACf,YAAY,MAAM,EAAE,gBAAgB;AACpC,YAAY,UAAU,EAAE,KAAK;AAC7B,YAAY,MAAM,EAAE,mDAAmD;AACvE,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;AAC3B,IAAI;AACJ,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;AAC5C,IAAI;AACJ,IAAI,MAAM,SAAS,CAAC,QAAQ,EAAE;AAC9B,QAAQ,OAAO;AACf,YAAY,OAAO,EAAE,KAAK;AAC1B,YAAY,MAAM,EAAE,IAAI;AACxB,YAAY,KAAK,EAAE,mDAAmD;AACtE,YAAY,YAAY,EAAE,CAAC;AAC3B,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,WAAW,GAAG;AACxB,QAAQ,OAAO;AACf,YAAY,OAAO,EAAE,KAAK;AAC1B,YAAY,KAAK,EAAE,mDAAmD;AACtE,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,SAAS,GAAG;AACtB,QAAQ,OAAO;AACf,YAAY,SAAS,EAAE,KAAK;AAC5B,YAAY,MAAM,EAAE,KAAK;AACzB,YAAY,QAAQ,EAAE,KAAK;AAC3B,YAAY,MAAM,EAAE,MAAM;AAC1B,YAAY,YAAY,EAAE,CAAC;AAC3B,YAAY,mBAAmB,EAAE,EAAE;AACnC,YAAY,MAAM,EAAE,IAAI;AACxB,YAAY,gBAAgB,EAAE,gBAAgB;AAC9C,YAAY,MAAM,EAAE,mDAAmD;AACvE,SAAS;AACT,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,69 @@
1
+ var capacitorAppBlocker = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const loadWeb = () => Promise.resolve().then(function () { return web; }).then((module) => new module.AppBlockerWeb());
5
+ const AppBlocker = core.registerPlugin("ElizaAppBlocker", {
6
+ web: loadWeb,
7
+ });
8
+
9
+ class AppBlockerWeb extends core.WebPlugin {
10
+ async checkPermissions() {
11
+ return {
12
+ status: "not-applicable",
13
+ canRequest: false,
14
+ reason: "App blocking is only available on mobile devices.",
15
+ };
16
+ }
17
+ async requestPermissions() {
18
+ return {
19
+ status: "not-applicable",
20
+ canRequest: false,
21
+ reason: "App blocking is only available on mobile devices.",
22
+ };
23
+ }
24
+ async getInstalledApps() {
25
+ return { apps: [] };
26
+ }
27
+ async selectApps() {
28
+ return { apps: [], cancelled: true };
29
+ }
30
+ async blockApps(_options) {
31
+ return {
32
+ success: false,
33
+ endsAt: null,
34
+ error: "App blocking is only available on mobile devices.",
35
+ blockedCount: 0,
36
+ };
37
+ }
38
+ async unblockApps() {
39
+ return {
40
+ success: false,
41
+ error: "App blocking is only available on mobile devices.",
42
+ };
43
+ }
44
+ async getStatus() {
45
+ return {
46
+ available: false,
47
+ active: false,
48
+ platform: "web",
49
+ engine: "none",
50
+ blockedCount: 0,
51
+ blockedPackageNames: [],
52
+ endsAt: null,
53
+ permissionStatus: "not-applicable",
54
+ reason: "App blocking is only available on mobile devices.",
55
+ };
56
+ }
57
+ }
58
+
59
+ var web = /*#__PURE__*/Object.freeze({
60
+ __proto__: null,
61
+ AppBlockerWeb: AppBlockerWeb
62
+ });
63
+
64
+ exports.AppBlocker = AppBlocker;
65
+
66
+ return exports;
67
+
68
+ })({}, capacitorExports);
69
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((module) => new module.AppBlockerWeb());\nexport const AppBlocker = registerPlugin(\"ElizaAppBlocker\", {\n web: loadWeb,\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\nexport class AppBlockerWeb extends WebPlugin {\n async checkPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async requestPermissions() {\n return {\n status: \"not-applicable\",\n canRequest: false,\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n async getInstalledApps() {\n return { apps: [] };\n }\n async selectApps() {\n return { apps: [], cancelled: true };\n }\n async blockApps(_options) {\n return {\n success: false,\n endsAt: null,\n error: \"App blocking is only available on mobile devices.\",\n blockedCount: 0,\n };\n }\n async unblockApps() {\n return {\n success: false,\n error: \"App blocking is only available on mobile devices.\",\n };\n }\n async getStatus() {\n return {\n available: false,\n active: false,\n platform: \"web\",\n engine: \"none\",\n blockedCount: 0,\n blockedPackageNames: [],\n endsAt: null,\n permissionStatus: \"not-applicable\",\n reason: \"App blocking is only available on mobile devices.\",\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;IAEA,MAAM,OAAO,GAAG,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;AACtE,UAAC,UAAU,GAAGA,mBAAc,CAAC,iBAAiB,EAAE;IAC5D,IAAI,GAAG,EAAE,OAAO;IAChB,CAAC;;ICJM,MAAM,aAAa,SAASC,cAAS,CAAC;IAC7C,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,OAAO;IACf,YAAY,MAAM,EAAE,gBAAgB;IACpC,YAAY,UAAU,EAAE,KAAK;IAC7B,YAAY,MAAM,EAAE,mDAAmD;IACvE,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,OAAO;IACf,YAAY,MAAM,EAAE,gBAAgB;IACpC,YAAY,UAAU,EAAE,KAAK;IAC7B,YAAY,MAAM,EAAE,mDAAmD;IACvE,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;IAC3B,IAAI;IACJ,IAAI,MAAM,UAAU,GAAG;IACvB,QAAQ,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;IAC5C,IAAI;IACJ,IAAI,MAAM,SAAS,CAAC,QAAQ,EAAE;IAC9B,QAAQ,OAAO;IACf,YAAY,OAAO,EAAE,KAAK;IAC1B,YAAY,MAAM,EAAE,IAAI;IACxB,YAAY,KAAK,EAAE,mDAAmD;IACtE,YAAY,YAAY,EAAE,CAAC;IAC3B,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,WAAW,GAAG;IACxB,QAAQ,OAAO;IACf,YAAY,OAAO,EAAE,KAAK;IAC1B,YAAY,KAAK,EAAE,mDAAmD;IACtE,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,SAAS,GAAG;IACtB,QAAQ,OAAO;IACf,YAAY,SAAS,EAAE,KAAK;IAC5B,YAAY,MAAM,EAAE,KAAK;IACzB,YAAY,QAAQ,EAAE,KAAK;IAC3B,YAAY,MAAM,EAAE,MAAM;IAC1B,YAAY,YAAY,EAAE,CAAC;IAC3B,YAAY,mBAAmB,EAAE,EAAE;IACnC,YAAY,MAAM,EAAE,IAAI;IACxB,YAAY,gBAAgB,EAAE,gBAAgB;IAC9C,YAAY,MAAM,EAAE,mDAAmD;IACvE,SAAS;IACT,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -0,0 +1,196 @@
1
+ import Capacitor
2
+ import FamilyControls
3
+ import Foundation
4
+ import UIKit
5
+
6
+ @objc(ElizaAppBlockerPlugin)
7
+ public class ElizaAppBlockerPlugin: CAPPlugin, CAPBridgedPlugin {
8
+ public let identifier = "ElizaAppBlockerPlugin"
9
+ public let jsName = "ElizaAppBlocker"
10
+ public let pluginMethods: [CAPPluginMethod] = [
11
+ CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: "getInstalledApps", returnType: CAPPluginReturnPromise),
14
+ CAPPluginMethod(name: "selectApps", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "blockApps", returnType: CAPPluginReturnPromise),
16
+ CAPPluginMethod(name: "unblockApps", returnType: CAPPluginReturnPromise),
17
+ CAPPluginMethod(name: "getStatus", returnType: CAPPluginReturnPromise),
18
+ ]
19
+
20
+ @objc public override func checkPermissions(_ call: CAPPluginCall) {
21
+ call.resolve(buildPermissionResult())
22
+ }
23
+
24
+ @objc public override func requestPermissions(_ call: CAPPluginCall) {
25
+ if #available(iOS 16.0, *) {
26
+ Task { @MainActor in
27
+ var reasonOverride: String?
28
+ do {
29
+ try await AuthorizationCenter.shared.requestAuthorization(for: .individual)
30
+ } catch {
31
+ reasonOverride = error.localizedDescription
32
+ }
33
+ call.resolve(buildPermissionResult(reasonOverride: reasonOverride))
34
+ }
35
+ return
36
+ }
37
+
38
+ AuthorizationCenter.shared.requestAuthorization { result in
39
+ let reasonOverride: String?
40
+ switch result {
41
+ case .success:
42
+ reasonOverride = nil
43
+ case .failure(let error):
44
+ reasonOverride = error.localizedDescription
45
+ }
46
+
47
+ call.resolve(self.buildPermissionResult(reasonOverride: reasonOverride))
48
+ }
49
+ }
50
+
51
+ @objc func getInstalledApps(_ call: CAPPluginCall) {
52
+ call.resolve([
53
+ "apps": [],
54
+ ])
55
+ }
56
+
57
+ @objc func selectApps(_ call: CAPPluginCall) {
58
+ guard let presenter = bridge?.viewController else {
59
+ call.reject("Could not present the iPhone app picker.")
60
+ return
61
+ }
62
+
63
+ Task { @MainActor in
64
+ FamilyActivityPickerBridge.present(from: presenter) { tokens, cancelled in
65
+ let apps = tokens.enumerated().compactMap { index, token -> JSObject? in
66
+ guard let tokenData = AppBlockerShared.serializeToken(token) else {
67
+ return nil
68
+ }
69
+ var object = JSObject()
70
+ object["packageName"] = ""
71
+ object["displayName"] = "Selected App \(index + 1)"
72
+ object["tokenData"] = tokenData
73
+ return object
74
+ }
75
+
76
+ call.resolve([
77
+ "apps": JSArray(apps),
78
+ "cancelled": cancelled,
79
+ ])
80
+ }
81
+ }
82
+ }
83
+
84
+ @objc func blockApps(_ call: CAPPluginCall) {
85
+ if AuthorizationCenter.shared.authorizationStatus != .approved {
86
+ call.resolve([
87
+ "success": false,
88
+ "endsAt": NSNull(),
89
+ "error": nullable(permissionReason(for: AuthorizationCenter.shared.authorizationStatus)),
90
+ "blockedCount": 0,
91
+ ])
92
+ return
93
+ }
94
+
95
+ let durationMinutes = call.getInt("durationMinutes")
96
+ if let durationMinutes, durationMinutes > 0 {
97
+ call.resolve([
98
+ "success": false,
99
+ "endsAt": NSNull(),
100
+ "error": "Timed iPhone app blocking still needs a DeviceActivity extension. Start an indefinite block for now and unblock it manually.",
101
+ "blockedCount": 0,
102
+ ])
103
+ return
104
+ }
105
+
106
+ let tokenDataArray = (call.getArray("appTokens") ?? []).compactMap { $0 as? String }
107
+ let tokens = AppBlockerShared.deserializeTokens(tokenDataArray)
108
+ guard !tokens.isEmpty else {
109
+ call.resolve([
110
+ "success": false,
111
+ "endsAt": NSNull(),
112
+ "error": "Select at least one iPhone app to block.",
113
+ "blockedCount": 0,
114
+ ])
115
+ return
116
+ }
117
+
118
+ AppBlockerShared.startBlock(tokens: tokens)
119
+ call.resolve([
120
+ "success": true,
121
+ "endsAt": NSNull(),
122
+ "blockedCount": tokens.count,
123
+ ])
124
+ }
125
+
126
+ @objc func unblockApps(_ call: CAPPluginCall) {
127
+ AppBlockerShared.stopBlock()
128
+ call.resolve([
129
+ "success": true,
130
+ ])
131
+ }
132
+
133
+ @objc func getStatus(_ call: CAPPluginCall) {
134
+ let state = AppBlockerShared.loadState()
135
+ let permission = buildPermissionResult()
136
+ let permissionStatus = permission["status"] as? String ?? "not-determined"
137
+ let reason = permission["reason"] as? String
138
+ let blockedCount = state?.tokenDataArray.count ?? 0
139
+
140
+ call.resolve([
141
+ "available": true,
142
+ "active": permissionStatus == "granted" && blockedCount > 0,
143
+ "platform": "ios",
144
+ "engine": "family-controls",
145
+ "blockedCount": blockedCount,
146
+ "blockedPackageNames": [],
147
+ "endsAt": nullable(AppBlockerShared.endsAtString(for: state)),
148
+ "permissionStatus": permissionStatus,
149
+ "reason": nullable(reason),
150
+ ])
151
+ }
152
+
153
+ private func buildPermissionResult(reasonOverride: String? = nil) -> [String: Any] {
154
+ let status = AuthorizationCenter.shared.authorizationStatus
155
+ let mappedStatus: String
156
+ let canRequest: Bool
157
+
158
+ switch status {
159
+ case .approved:
160
+ mappedStatus = "granted"
161
+ canRequest = false
162
+ case .notDetermined:
163
+ mappedStatus = "not-determined"
164
+ canRequest = true
165
+ default:
166
+ mappedStatus = "denied"
167
+ canRequest = true
168
+ }
169
+
170
+ var result: [String: Any] = [
171
+ "status": mappedStatus,
172
+ "canRequest": canRequest,
173
+ ]
174
+
175
+ if let reason = reasonOverride ?? permissionReason(for: status) {
176
+ result["reason"] = reason
177
+ }
178
+
179
+ return result
180
+ }
181
+
182
+ private func permissionReason(for status: AuthorizationStatus) -> String? {
183
+ switch status {
184
+ case .approved:
185
+ return nil
186
+ case .notDetermined:
187
+ return "Authorize Family Controls before Eliza can choose and shield apps on this iPhone."
188
+ default:
189
+ return "Family Controls access is currently denied for this app. Re-run authorization on this iPhone developer build."
190
+ }
191
+ }
192
+
193
+ private func nullable(_ value: Any?) -> Any {
194
+ value ?? NSNull()
195
+ }
196
+ }