expo-app-blocker 0.1.5 → 0.1.7
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
|
@@ -73,7 +73,8 @@ Add the plugin to your `app.json`:
|
|
|
73
73
|
"primaryButtonLabel": "Earn Free Time",
|
|
74
74
|
"secondaryButtonLabel": "Not now",
|
|
75
75
|
"primaryButtonColor": "#fb6107",
|
|
76
|
-
"
|
|
76
|
+
"backgroundColor": "#f6f6f6",
|
|
77
|
+
"backgroundBlurStyle": "systemThickMaterialLight",
|
|
77
78
|
"icon": "./assets/shield-icon.png"
|
|
78
79
|
}
|
|
79
80
|
}
|
|
@@ -95,7 +96,8 @@ Add the plugin to your `app.json`:
|
|
|
95
96
|
| `ios.shield.primaryButtonColor` | `string` | `"#fb6107"` | Primary button background color (hex) |
|
|
96
97
|
| `ios.shield.titleColor` | `string` | `"#111111"` | Title text color (hex) |
|
|
97
98
|
| `ios.shield.subtitleColor` | `string` | `"#737373"` | Subtitle text color (hex) |
|
|
98
|
-
| `ios.shield.
|
|
99
|
+
| `ios.shield.backgroundColor` | `string\|null` | `null` | Solid background color (hex). e.g. `"#f6f6f6"` for light, `"#1a1a2e"` for dark |
|
|
100
|
+
| `ios.shield.backgroundBlurStyle` | `string\|null` | `"systemThickMaterial"` | Blur style. Auto-defaults when no backgroundColor. See below for all options |
|
|
99
101
|
| `ios.shield.icon` | `string` | SF Symbol | Path to custom shield icon PNG (relative to project root, e.g. `"./assets/shield-icon.png"`) |
|
|
100
102
|
| `android.notificationTitle` | `string` | `"App Blocked"` | Notification title |
|
|
101
103
|
| `android.notificationText` | `string` | `"{appName} is blocked."` | Notification text |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-app-blocker",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Expo module for cross-platform app blocking. Android: UsageStatsManager + Overlay. iOS: Screen Time API (FamilyControls + ManagedSettings + DeviceActivity).",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
package/plugin/src/index.js
CHANGED
|
@@ -141,6 +141,36 @@ function withAppBlockerIOS(config, pluginConfig) {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
// Copy fresh target templates from node_modules before replacing placeholders
|
|
145
|
+
const targetsDir = path.join(path.dirname(platformRoot), "targets");
|
|
146
|
+
const packageTargetsDir = path.resolve(__dirname, "..", "..", "targets");
|
|
147
|
+
if (fs.existsSync(packageTargetsDir)) {
|
|
148
|
+
function copyDirSync(src, dest) {
|
|
149
|
+
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
150
|
+
for (const entry of fs.readdirSync(src)) {
|
|
151
|
+
const srcPath = path.join(src, entry);
|
|
152
|
+
const destPath = path.join(dest, entry);
|
|
153
|
+
if (fs.statSync(srcPath).isDirectory()) {
|
|
154
|
+
copyDirSync(srcPath, destPath);
|
|
155
|
+
} else {
|
|
156
|
+
fs.copyFileSync(srcPath, destPath);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Only copy Swift files and config (preserve user's assets, generated entitlements, Info.plist)
|
|
161
|
+
for (const dir of fs.readdirSync(packageTargetsDir)) {
|
|
162
|
+
const srcDir = path.join(packageTargetsDir, dir);
|
|
163
|
+
const destDir = path.join(targetsDir, dir);
|
|
164
|
+
if (!fs.statSync(srcDir).isDirectory()) continue;
|
|
165
|
+
if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
|
|
166
|
+
for (const file of fs.readdirSync(srcDir)) {
|
|
167
|
+
if (file.endsWith(".swift") || file === "expo-target.config.js") {
|
|
168
|
+
fs.copyFileSync(path.join(srcDir, file), path.join(destDir, file));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
144
174
|
// Helper: hex to RGB floats
|
|
145
175
|
function hexToRgb(hex) {
|
|
146
176
|
const h = hex.replace("#", "");
|
|
@@ -156,9 +186,35 @@ function withAppBlockerIOS(config, pluginConfig) {
|
|
|
156
186
|
const primaryColor = hexToRgb(shield.primaryButtonColor || "#fb6107");
|
|
157
187
|
const titleColor = hexToRgb(shield.titleColor || "#111111");
|
|
158
188
|
const subtitleColor = hexToRgb(shield.subtitleColor || "#737373");
|
|
159
|
-
//
|
|
160
|
-
const
|
|
161
|
-
const bgColor =
|
|
189
|
+
// Background color (solid) - separate from blur
|
|
190
|
+
const bgColorHex = shield.backgroundColor || null;
|
|
191
|
+
const bgColor = bgColorHex ? hexToRgb(bgColorHex) : null;
|
|
192
|
+
|
|
193
|
+
// Blur style mapping
|
|
194
|
+
const blurStyleMap = {
|
|
195
|
+
"systemUltraThinMaterial": ".systemUltraThinMaterial",
|
|
196
|
+
"systemThinMaterial": ".systemThinMaterial",
|
|
197
|
+
"systemMaterial": ".systemMaterial",
|
|
198
|
+
"systemThickMaterial": ".systemThickMaterial",
|
|
199
|
+
"systemChromeMaterial": ".systemChromeMaterial",
|
|
200
|
+
"systemUltraThinMaterialLight": ".systemUltraThinMaterialLight",
|
|
201
|
+
"systemThinMaterialLight": ".systemThinMaterialLight",
|
|
202
|
+
"systemMaterialLight": ".systemMaterialLight",
|
|
203
|
+
"systemThickMaterialLight": ".systemThickMaterialLight",
|
|
204
|
+
"systemChromeMaterialLight": ".systemChromeMaterialLight",
|
|
205
|
+
"systemUltraThinMaterialDark": ".systemUltraThinMaterialDark",
|
|
206
|
+
"systemThinMaterialDark": ".systemThinMaterialDark",
|
|
207
|
+
"systemMaterialDark": ".systemMaterialDark",
|
|
208
|
+
"systemThickMaterialDark": ".systemThickMaterialDark",
|
|
209
|
+
"systemChromeMaterialDark": ".systemChromeMaterialDark",
|
|
210
|
+
"regular": ".regular",
|
|
211
|
+
"prominent": ".prominent",
|
|
212
|
+
"light": ".light",
|
|
213
|
+
"dark": ".dark",
|
|
214
|
+
"extraLight": ".extraLight",
|
|
215
|
+
};
|
|
216
|
+
const blurRaw = shield.backgroundBlurStyle || (bgColorHex ? null : "systemThickMaterial");
|
|
217
|
+
const blurSwift = blurRaw && blurStyleMap[blurRaw] ? blurStyleMap[blurRaw] : null;
|
|
162
218
|
|
|
163
219
|
// All placeholder replacements
|
|
164
220
|
const replacements = {
|
|
@@ -176,13 +232,13 @@ function withAppBlockerIOS(config, pluginConfig) {
|
|
|
176
232
|
"SHIELD_SUBTITLE_R_PLACEHOLDER": subtitleColor.r,
|
|
177
233
|
"SHIELD_SUBTITLE_G_PLACEHOLDER": subtitleColor.g,
|
|
178
234
|
"SHIELD_SUBTITLE_B_PLACEHOLDER": subtitleColor.b,
|
|
179
|
-
"
|
|
235
|
+
"SHIELD_BG_COLOR_PLACEHOLDER": bgColor
|
|
180
236
|
? `UIColor(red: ${bgColor.r}, green: ${bgColor.g}, blue: ${bgColor.b}, alpha: 1.0)`
|
|
181
237
|
: "nil",
|
|
238
|
+
"SHIELD_BLUR_STYLE_PLACEHOLDER": blurSwift || "nil",
|
|
182
239
|
};
|
|
183
240
|
|
|
184
241
|
// Inject all placeholders into extension Swift files
|
|
185
|
-
const targetsDir = path.join(path.dirname(platformRoot), "targets");
|
|
186
242
|
if (fs.existsSync(targetsDir)) {
|
|
187
243
|
const dirs = fs.readdirSync(targetsDir);
|
|
188
244
|
for (const dir of dirs) {
|
|
@@ -81,11 +81,31 @@ export interface ShieldConfig {
|
|
|
81
81
|
/** Subtitle text color (hex). Default: "#737373" */
|
|
82
82
|
subtitleColor?: string;
|
|
83
83
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
84
|
+
* Solid background color (hex). Optional.
|
|
85
|
+
* When set, the shield uses this color instead of (or in addition to) a blur.
|
|
86
|
+
* Example: "#f6f6f6" for light gray, "#1a1a2e" for dark.
|
|
87
87
|
*/
|
|
88
|
-
|
|
88
|
+
backgroundColor?: string | null;
|
|
89
|
+
/**
|
|
90
|
+
* Background blur style. Default: "systemThickMaterial" (when no backgroundColor is set).
|
|
91
|
+
* Set to null to disable blur (when using backgroundColor only).
|
|
92
|
+
* Both can be combined - blur renders behind the color.
|
|
93
|
+
*
|
|
94
|
+
* Adaptive (light/dark auto):
|
|
95
|
+
* - "systemUltraThinMaterial", "systemThinMaterial", "systemMaterial",
|
|
96
|
+
* "systemThickMaterial", "systemChromeMaterial"
|
|
97
|
+
*
|
|
98
|
+
* Light only:
|
|
99
|
+
* - "systemUltraThinMaterialLight", "systemThinMaterialLight", "systemMaterialLight",
|
|
100
|
+
* "systemThickMaterialLight", "systemChromeMaterialLight"
|
|
101
|
+
*
|
|
102
|
+
* Dark only:
|
|
103
|
+
* - "systemUltraThinMaterialDark", "systemThinMaterialDark", "systemMaterialDark",
|
|
104
|
+
* "systemThickMaterialDark", "systemChromeMaterialDark"
|
|
105
|
+
*
|
|
106
|
+
* Legacy: "regular", "prominent", "light", "dark", "extraLight"
|
|
107
|
+
*/
|
|
108
|
+
backgroundBlurStyle?: string | null;
|
|
89
109
|
/** Path to shield icon image (PNG). Optional. */
|
|
90
110
|
icon?: string;
|
|
91
111
|
}
|
|
@@ -12,7 +12,8 @@ class ShieldConfigurationExtension: ShieldConfigurationDataSource {
|
|
|
12
12
|
private let shieldPrimaryButtonLabel = "SHIELD_PRIMARY_BUTTON_PLACEHOLDER"
|
|
13
13
|
private let shieldSecondaryButtonLabel = "SHIELD_SECONDARY_BUTTON_PLACEHOLDER"
|
|
14
14
|
private let shieldPrimaryButtonColor = UIColor(red: SHIELD_PRIMARY_R_PLACEHOLDER, green: SHIELD_PRIMARY_G_PLACEHOLDER, blue: SHIELD_PRIMARY_B_PLACEHOLDER, alpha: 1.0)
|
|
15
|
-
private let shieldBackgroundColor: UIColor? =
|
|
15
|
+
private let shieldBackgroundColor: UIColor? = SHIELD_BG_COLOR_PLACEHOLDER
|
|
16
|
+
private let shieldBlurStyle: UIBlurEffect.Style? = SHIELD_BLUR_STYLE_PLACEHOLDER
|
|
16
17
|
private let shieldTitleColor = UIColor(red: SHIELD_TITLE_R_PLACEHOLDER, green: SHIELD_TITLE_G_PLACEHOLDER, blue: SHIELD_TITLE_B_PLACEHOLDER, alpha: 1.0)
|
|
17
18
|
private let shieldSubtitleColor = UIColor(red: SHIELD_SUBTITLE_R_PLACEHOLDER, green: SHIELD_SUBTITLE_G_PLACEHOLDER, blue: SHIELD_SUBTITLE_B_PLACEHOLDER, alpha: 1.0)
|
|
18
19
|
|
|
@@ -40,7 +41,7 @@ class ShieldConfigurationExtension: ShieldConfigurationDataSource {
|
|
|
40
41
|
private func makeConfig(appName: String) -> ShieldConfiguration {
|
|
41
42
|
if isTemporarilyUnlocked() {
|
|
42
43
|
return ShieldConfiguration(
|
|
43
|
-
backgroundBlurStyle:
|
|
44
|
+
backgroundBlurStyle: shieldBlurStyle,
|
|
44
45
|
backgroundColor: shieldBackgroundColor,
|
|
45
46
|
icon: mascotIcon,
|
|
46
47
|
title: ShieldConfiguration.Label(text: "Almost there!", color: shieldTitleColor),
|