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
- "background": "#f6f6f6",
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.background` | `"blur"\|string` | `"blur"` | `"blur"` for frosted glass effect, or a hex color (e.g. `"#f6f6f6"`) for a solid background |
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.5",
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",
@@ -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
- // background: "blur" (default) or a hex color string
160
- const bgRaw = shield.background ?? shield.backgroundColor ?? null;
161
- const bgColor = (bgRaw && bgRaw !== "blur") ? hexToRgb(bgRaw) : null;
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
- "SHIELD_BG_PLACEHOLDER": bgColor
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
- * Background style. Two modes:
85
- * - "blur" (default): Frosted glass effect over the blocked app (iOS systemThickMaterial)
86
- * - A hex color string (e.g. "#f6f6f6"): Solid color background
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
- background?: "blur" | string;
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? = SHIELD_BG_PLACEHOLDER
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: shieldBackgroundColor == nil ? .systemThickMaterial : nil,
44
+ backgroundBlurStyle: shieldBlurStyle,
44
45
  backgroundColor: shieldBackgroundColor,
45
46
  icon: mascotIcon,
46
47
  title: ShieldConfiguration.Label(text: "Almost there!", color: shieldTitleColor),