Skip to content

Commit 7ad6efb

Browse files
Added sound notification assets + build copy files script.
1 parent 74e7362 commit 7ad6efb

File tree

8 files changed

+149
-130
lines changed

8 files changed

+149
-130
lines changed

assets/sounds/notification.aiff

685 KB
Binary file not shown.

assets/sounds/notification.caf

685 KB
Binary file not shown.

assets/sounds/notification.mp3

88 KB
Binary file not shown.

assets/sounds/notification.ogg

54.4 KB
Binary file not shown.

scripts/bumpVersion.cjs

Lines changed: 0 additions & 45 deletions
This file was deleted.

scripts/notificationSounds.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const fs = require("fs-extra");
2+
const path = require("path");
3+
4+
const SOUNDS_SRC = path.resolve(__dirname, "../assets/sounds");
5+
const ANDROID_SOUNDS_DEST = path.resolve(
6+
__dirname,
7+
"../android/app/src/main/res/raw"
8+
);
9+
const IOS_SOUNDS_DEST = path.resolve(
10+
__dirname,
11+
"../ios/CodeBuilderAdmin/Sounds"
12+
); // Replace "YourAppName"
13+
14+
async function copySounds() {
15+
try {
16+
// Copy to Android (filter for Android-supported formats)
17+
await fs.ensureDir(ANDROID_SOUNDS_DEST);
18+
await fs.copy(SOUNDS_SRC, ANDROID_SOUNDS_DEST, {
19+
filter: (src) => {
20+
const ext = path.extname(src).toLowerCase();
21+
return [".mp3", ".wav", ".ogg"].includes(ext); // Android formats
22+
},
23+
});
24+
console.log("✅ Sounds copied to Android");
25+
26+
// Copy to iOS (filter for iOS-supported formats)
27+
await fs.ensureDir(IOS_SOUNDS_DEST);
28+
await fs.copy(SOUNDS_SRC, IOS_SOUNDS_DEST, {
29+
filter: (src) => {
30+
const ext = path.extname(src).toLowerCase();
31+
return [".aiff", ".caf", ".wav"].includes(ext); // iOS formats
32+
},
33+
});
34+
console.log("✅ Sounds copied to iOS");
35+
} catch (err) {
36+
console.error("❌ Error copying sounds:", err);
37+
process.exit(1);
38+
}
39+
}
40+
41+
copySounds();

scripts/setupScreenRecording.js

Lines changed: 100 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,23 @@ const path = require("path");
22
const fs = require("fs");
33

44
const androidBasePath = path.join(__dirname, "../android/app/src/main");
5-
const javaOrKotlinBasePath = path.join(
5+
const kotlinBasePath = path.join(
66
androidBasePath,
77
"java/com/digitalnomad91/codebuilderadmin"
88
);
99

1010
const androidManifestPath = path.join(androidBasePath, "AndroidManifest.xml");
11-
const mainActivityPathKotlin = path.join(
12-
javaOrKotlinBasePath,
13-
"MainActivity.kt"
14-
);
15-
const serviceKotlinPath = path.join(
16-
javaOrKotlinBasePath,
17-
"ScreenRecordService.kt"
18-
);
19-
20-
// Clean up potential duplicate in old java directory
21-
const oldJavaServicePath = path.join(
22-
androidBasePath,
23-
"java/com/digitalnomad91/codebuilderadmin/ScreenRecordService.kt"
24-
);
25-
if (fs.existsSync(oldJavaServicePath)) {
26-
fs.unlinkSync(oldJavaServicePath);
27-
console.log("🧹 Removed duplicate service file from java directory");
28-
}
11+
const mainActivityPath = path.join(kotlinBasePath, "MainActivity.kt");
12+
const servicePath = path.join(kotlinBasePath, "ScreenRecordService.kt");
2913

3014
const ensurePermissions = () => {
3115
if (!fs.existsSync(androidManifestPath)) {
32-
console.error("AndroidManifest.xml not found.");
16+
console.error("AndroidManifest.xml not found");
3317
return;
3418
}
3519

3620
let manifestContent = fs.readFileSync(androidManifestPath, "utf8");
37-
const permissions = [
21+
const requiredPermissions = [
3822
"android.permission.RECORD_AUDIO",
3923
"android.permission.FOREGROUND_SERVICE",
4024
"android.permission.SYSTEM_ALERT_WINDOW",
@@ -44,148 +28,185 @@ const ensurePermissions = () => {
4428
];
4529

4630
let modified = false;
47-
permissions.forEach((permission) => {
31+
requiredPermissions.forEach((permission) => {
4832
if (!manifestContent.includes(permission)) {
4933
manifestContent = manifestContent.replace(
5034
"</manifest>",
51-
` <uses-permission android:name="${permission}"/>\n</manifest>`
35+
` <uses-permission android:name="${permission}" />\n</manifest>`
5236
);
5337
modified = true;
5438
}
5539
});
5640

5741
if (modified) {
5842
fs.writeFileSync(androidManifestPath, manifestContent, "utf8");
59-
console.log("✅ AndroidManifest.xml updated with permissions.");
43+
console.log("✅ AndroidManifest.xml permissions updated");
6044
} else {
61-
console.log("✅ AndroidManifest.xml has necessary permissions.");
45+
console.log("✅ AndroidManifest.xml has required permissions");
6246
}
6347
};
6448

6549
const ensureMainActivityModifications = () => {
66-
if (!fs.existsSync(mainActivityPathKotlin)) {
67-
console.error("❌ MainActivity.kt not found.");
50+
if (!fs.existsSync(mainActivityPath)) {
51+
console.error("❌ MainActivity.kt not found");
6852
return;
6953
}
7054

71-
let content = fs.readFileSync(mainActivityPathKotlin, "utf8");
55+
let content = fs.readFileSync(mainActivityPath, "utf8");
56+
57+
// Clean up duplicate imports
58+
const importsToManage = [
59+
"android.os.Bundle",
60+
"android.content.Context",
61+
"android.content.Intent",
62+
"android.media.projection.MediaProjectionManager",
63+
];
64+
65+
importsToManage.forEach((imp) => {
66+
const importRegex = new RegExp(`import ${imp}[\n\r]`, "g");
67+
if ((content.match(importRegex) || []).length > 1) {
68+
content = content.replace(importRegex, "");
69+
content = `import ${imp}\n${content}`;
70+
}
71+
});
72+
73+
// Ensure required imports exist
74+
const requiredImports = `
75+
import android.os.Bundle
76+
import android.content.Context
77+
import android.content.Intent
78+
import android.media.projection.MediaProjectionManager
79+
`.trim();
80+
81+
if (!content.includes("MediaProjectionManager")) {
82+
content = content.replace(
83+
/import com\.facebook\.react\.ReactActivity/,
84+
`import com.facebook.react.ReactActivity\n${requiredImports}`
85+
);
86+
}
87+
88+
// Injection code with null safety and proper overrides
7289
const injectionCode = `
7390
private val SCREEN_RECORD_REQUEST_CODE = 1001
74-
private var projectionManager: MediaProjectionManager? = null
91+
private lateinit var projectionManager: MediaProjectionManager
7592
7693
override fun onCreate(savedInstanceState: Bundle?) {
7794
super.onCreate(savedInstanceState)
7895
projectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
7996
}
8097
8198
fun startScreenRecording() {
82-
val intent = projectionManager?.createScreenCaptureIntent()
83-
startActivityForResult(intent, SCREEN_RECORD_REQUEST_CODE)
99+
val captureIntent = projectionManager.createScreenCaptureIntent()
100+
startActivityForResult(captureIntent, SCREEN_RECORD_REQUEST_CODE)
84101
}
85102
86103
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
87104
super.onActivityResult(requestCode, resultCode, data)
88-
if (requestCode == SCREEN_RECORD_REQUEST_CODE) {
89-
val serviceIntent = Intent(this, ScreenRecordService::class.java)
90-
serviceIntent.putExtra("RESULT_CODE", resultCode)
91-
serviceIntent.putExtra("DATA", data)
92-
startForegroundService(serviceIntent)
105+
if (requestCode == SCREEN_RECORD_REQUEST_CODE && data != null) {
106+
Intent(this, ScreenRecordService::class.java).apply {
107+
putExtra("RESULT_CODE", resultCode)
108+
putExtra("DATA", data)
109+
startForegroundService(this)
110+
}
93111
}
94112
}
95-
`;
96-
97-
// Add imports if missing
98-
if (
99-
!content.includes("import android.media.projection.MediaProjectionManager")
100-
) {
101-
content = content.replace(
102-
"import com.facebook.react.ReactActivity",
103-
`import com.facebook.react.ReactActivity
104-
import android.content.Context
105-
import android.content.Intent
106-
import android.media.projection.MediaProjectionManager
107-
import android.os.Bundle`
108-
);
109-
}
113+
`.trim();
110114

111115
if (!content.includes("SCREEN_RECORD_REQUEST_CODE")) {
116+
// Remove any existing duplicate code
117+
const duplicateCodePatterns = [
118+
/private val SCREEN_RECORD_REQUEST_CODE = \d+/,
119+
/override fun onCreate\(.*?\)\s*\{[\s\S]*?\}/,
120+
/fun startScreenRecording\(\)\s*\{[\s\S]*?\}/,
121+
/override fun onActivityResult\(.*?\)\s*\{[\s\S]*?\}/,
122+
];
123+
124+
duplicateCodePatterns.forEach((pattern) => {
125+
content = content.replace(pattern, "");
126+
});
127+
128+
// Insert new code
112129
content = content.replace(
113-
/class MainActivity : ReactActivity\(\) \{/,
114-
`class MainActivity : ReactActivity() {${injectionCode}`
130+
/class MainActivity : ReactActivity\(\)\s*\{/,
131+
`class MainActivity : ReactActivity() {\n${injectionCode}\n`
115132
);
116-
fs.writeFileSync(mainActivityPathKotlin, content, "utf8");
117-
console.log("✅ MainActivity.kt updated.");
133+
134+
fs.writeFileSync(mainActivityPath, content, "utf8");
135+
console.log("✅ MainActivity.kt updated with proper implementations");
118136
} else {
119-
console.log("✅ MainActivity already modified.");
137+
console.log("✅ MainActivity already contains correct code");
120138
}
121139
};
122140

123141
const ensureScreenRecordService = () => {
124-
const serviceDir = path.dirname(serviceKotlinPath);
125-
if (!fs.existsSync(serviceDir)) {
126-
fs.mkdirSync(serviceDir, { recursive: true });
127-
console.log("✅ Created service directory");
142+
if (!fs.existsSync(kotlinBasePath)) {
143+
fs.mkdirSync(kotlinBasePath, { recursive: true });
128144
}
129145

130-
if (!fs.existsSync(serviceKotlinPath)) {
146+
if (!fs.existsSync(servicePath)) {
131147
const serviceCode = `package com.digitalnomad91.codebuilderadmin
132148
133149
import android.app.Notification
134150
import android.app.NotificationChannel
135151
import android.app.NotificationManager
136152
import android.app.Service
137153
import android.content.Intent
138-
import android.media.projection.MediaProjection
139154
import android.os.Build
140155
import android.os.IBinder
141156
import androidx.core.app.NotificationCompat
142157
import com.digitalnomad91.codebuilderadmin.R
143158
144159
class ScreenRecordService : Service() {
145-
private val CHANNEL_ID = "ScreenRecordChannel"
146-
private var mediaProjection: MediaProjection? = null
160+
companion object {
161+
const val CHANNEL_ID = "ScreenRecorderChannel"
162+
}
147163
148164
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
149-
createNotification()
165+
createNotificationChannel()
166+
startForeground(1, createNotification())
150167
return START_STICKY
151168
}
152169
153-
private fun createNotification() {
170+
private fun createNotificationChannel() {
154171
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
155172
val channel = NotificationChannel(
156173
CHANNEL_ID,
157174
"Screen Recording",
158175
NotificationManager.IMPORTANCE_LOW
159-
)
160-
val manager = getSystemService(NotificationManager::class.java)
161-
manager.createNotificationChannel(channel)
176+
).apply {
177+
description = "Recording screen activity"
178+
}
179+
(getSystemService(NOTIFICATION_SERVICE) as NotificationManager)
180+
.createNotificationChannel(channel)
162181
}
182+
}
163183
164-
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
184+
private fun createNotification(): Notification {
185+
return NotificationCompat.Builder(this, CHANNEL_ID)
165186
.setContentTitle("Screen Recording")
166-
.setContentText("Your screen is being recorded")
187+
.setContentText("Recording in progress")
167188
.setSmallIcon(R.mipmap.ic_launcher_foreground)
168189
.build()
169-
170-
startForeground(1, notification)
171190
}
172191
173192
override fun onBind(intent: Intent?): IBinder? = null
174193
}
175194
`;
176-
fs.writeFileSync(serviceKotlinPath, serviceCode, "utf8");
177-
console.log("✅ ScreenRecordService.kt created.");
195+
fs.writeFileSync(servicePath, serviceCode, "utf8");
196+
console.log("✅ ScreenRecordService.kt created");
178197
} else {
179-
console.log("✅ ScreenRecordService.kt exists.");
198+
console.log("✅ ScreenRecordService.kt exists");
180199
}
181200
};
182201

183-
// Execute all steps
202+
// Execute all steps with error handling
184203
try {
204+
console.log("\n🚀 Starting screen recording setup...");
185205
ensurePermissions();
186206
ensureMainActivityModifications();
187207
ensureScreenRecordService();
188-
console.log("🎉 Screen recording setup completed!");
208+
console.log("🎉 Screen recording setup completed successfully!\n");
189209
} catch (error) {
190-
console.error("❌ Setup failed:", error);
210+
console.error("\n❌ Setup failed:", error.message);
211+
process.exit(1);
191212
}

0 commit comments

Comments
 (0)