HI7RAI commited on
Commit
a76fb61
·
verified ·
1 Parent(s): 129e0ad

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +762 -19
index.html CHANGED
@@ -1,19 +1,762 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>APK Auto-Builder Studio</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
8
+ <style>
9
+ :root {
10
+ --primary: #6366f1;
11
+ --primary-hover: #4f46e5;
12
+ --secondary: #ec4899;
13
+ --bg-dark: #0f172a;
14
+ --bg-panel: #1e293b;
15
+ --text-main: #f8fafc;
16
+ --text-muted: #94a3b8;
17
+ --border: #334155;
18
+ --success: #10b981;
19
+ --terminal-bg: #0c0c0c;
20
+ --font-main: 'Segoe UI', system-ui, sans-serif;
21
+ --font-mono: 'Courier New', Courier, monospace;
22
+ }
23
+
24
+ * {
25
+ box-sizing: border-box;
26
+ margin: 0;
27
+ padding: 0;
28
+ }
29
+
30
+ body {
31
+ font-family: var(--font-main);
32
+ background-color: var(--bg-dark);
33
+ color: var(--text-main);
34
+ min-height: 100vh;
35
+ display: flex;
36
+ flex-direction: column;
37
+ overflow-x: hidden;
38
+ }
39
+
40
+ /* Header */
41
+ header {
42
+ background: rgba(30, 41, 59, 0.8);
43
+ backdrop-filter: blur(10px);
44
+ border-bottom: 1px solid var(--border);
45
+ padding: 1rem 2rem;
46
+ display: flex;
47
+ justify-content: space-between;
48
+ align-items: center;
49
+ position: sticky;
50
+ top: 0;
51
+ z-index: 100;
52
+ }
53
+
54
+ .logo {
55
+ font-size: 1.5rem;
56
+ font-weight: 700;
57
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
58
+ -webkit-background-clip: text;
59
+ -webkit-text-fill-color: transparent;
60
+ display: flex;
61
+ align-items: center;
62
+ gap: 0.5rem;
63
+ }
64
+
65
+ .anycoder-link {
66
+ color: var(--text-muted);
67
+ text-decoration: none;
68
+ font-size: 0.9rem;
69
+ transition: color 0.3s;
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 0.5rem;
73
+ }
74
+
75
+ .anycoder-link:hover {
76
+ color: var(--primary);
77
+ }
78
+
79
+ /* Main Layout */
80
+ main {
81
+ flex: 1;
82
+ display: grid;
83
+ grid-template-columns: 350px 1fr;
84
+ gap: 2rem;
85
+ padding: 2rem;
86
+ max-width: 1600px;
87
+ margin: 0 auto;
88
+ width: 100%;
89
+ }
90
+
91
+ @media (max-width: 900px) {
92
+ main {
93
+ grid-template-columns: 1fr;
94
+ }
95
+ }
96
+
97
+ /* Panels */
98
+ .panel {
99
+ background: var(--bg-panel);
100
+ border: 1px solid var(--border);
101
+ border-radius: 12px;
102
+ padding: 1.5rem;
103
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
104
+ }
105
+
106
+ h2 {
107
+ font-size: 1.25rem;
108
+ margin-bottom: 1rem;
109
+ color: var(--text-main);
110
+ display: flex;
111
+ align-items: center;
112
+ gap: 0.5rem;
113
+ }
114
+
115
+ /* File Upload Zone */
116
+ .upload-zone {
117
+ border: 2px dashed var(--border);
118
+ border-radius: 8px;
119
+ padding: 3rem 1.5rem;
120
+ text-align: center;
121
+ cursor: pointer;
122
+ transition: all 0.3s ease;
123
+ position: relative;
124
+ overflow: hidden;
125
+ }
126
+
127
+ .upload-zone:hover, .upload-zone.dragover {
128
+ border-color: var(--primary);
129
+ background: rgba(99, 102, 241, 0.05);
130
+ }
131
+
132
+ .upload-icon {
133
+ font-size: 3rem;
134
+ color: var(--text-muted);
135
+ margin-bottom: 1rem;
136
+ transition: transform 0.3s;
137
+ }
138
+
139
+ .upload-zone:hover .upload-icon {
140
+ transform: scale(1.1);
141
+ color: var(--primary);
142
+ }
143
+
144
+ .file-info {
145
+ display: none;
146
+ margin-top: 1rem;
147
+ background: rgba(0,0,0,0.2);
148
+ padding: 1rem;
149
+ border-radius: 6px;
150
+ text-align: left;
151
+ }
152
+
153
+ .file-info.active {
154
+ display: block;
155
+ animation: fadeIn 0.5s ease;
156
+ }
157
+
158
+ .file-name {
159
+ font-weight: 600;
160
+ color: var(--primary);
161
+ word-break: break-all;
162
+ }
163
+
164
+ .file-meta {
165
+ font-size: 0.85rem;
166
+ color: var(--text-muted);
167
+ margin-top: 0.25rem;
168
+ }
169
+
170
+ /* Form Elements */
171
+ .form-group {
172
+ margin-bottom: 1.25rem;
173
+ }
174
+
175
+ label {
176
+ display: block;
177
+ margin-bottom: 0.5rem;
178
+ font-size: 0.9rem;
179
+ color: var(--text-muted);
180
+ }
181
+
182
+ input, select {
183
+ width: 100%;
184
+ background: var(--bg-dark);
185
+ border: 1px solid var(--border);
186
+ color: var(--text-main);
187
+ padding: 0.75rem;
188
+ border-radius: 6px;
189
+ font-family: var(--font-main);
190
+ transition: border-color 0.3s;
191
+ }
192
+
193
+ input:focus, select:focus {
194
+ outline: none;
195
+ border-color: var(--primary);
196
+ }
197
+
198
+ /* Terminal / Console */
199
+ .terminal-container {
200
+ display: flex;
201
+ flex-direction: column;
202
+ height: 100%;
203
+ min-height: 400px;
204
+ }
205
+
206
+ .terminal-header {
207
+ display: flex;
208
+ justify-content: space-between;
209
+ align-items: center;
210
+ padding-bottom: 1rem;
211
+ border-bottom: 1px solid var(--border);
212
+ margin-bottom: 1rem;
213
+ }
214
+
215
+ .status-badge {
216
+ font-size: 0.8rem;
217
+ padding: 0.25rem 0.75rem;
218
+ border-radius: 99px;
219
+ background: var(--border);
220
+ color: var(--text-muted);
221
+ text-transform: uppercase;
222
+ letter-spacing: 0.05em;
223
+ }
224
+
225
+ .status-badge.active {
226
+ background: rgba(16, 185, 129, 0.2);
227
+ color: var(--success);
228
+ }
229
+
230
+ .terminal-window {
231
+ flex: 1;
232
+ background: var(--terminal-bg);
233
+ border-radius: 8px;
234
+ padding: 1rem;
235
+ font-family: var(--font-mono);
236
+ font-size: 0.9rem;
237
+ color: #d4d4d4;
238
+ overflow-y: auto;
239
+ height: 400px;
240
+ border: 1px solid #333;
241
+ box-shadow: inset 0 2px 10px rgba(0,0,0,0.5);
242
+ }
243
+
244
+ .log-line {
245
+ margin-bottom: 0.25rem;
246
+ line-height: 1.4;
247
+ display: flex;
248
+ gap: 0.5rem;
249
+ }
250
+
251
+ .log-time {
252
+ color: #569cd6;
253
+ }
254
+
255
+ .log-info { color: #d4d4d4; }
256
+ .log-warn { color: #ce9178; }
257
+ .log-success { color: var(--success); }
258
+ .log-cmd { color: var(--secondary); }
259
+
260
+ /* Progress Bar */
261
+ .progress-container {
262
+ margin-top: 1rem;
263
+ height: 6px;
264
+ background: var(--bg-dark);
265
+ border-radius: 3px;
266
+ overflow: hidden;
267
+ display: none;
268
+ }
269
+
270
+ .progress-container.active {
271
+ display: block;
272
+ }
273
+
274
+ .progress-bar {
275
+ height: 100%;
276
+ background: linear-gradient(90deg, var(--primary), var(--secondary));
277
+ width: 0%;
278
+ transition: width 0.3s ease;
279
+ }
280
+
281
+ /* Buttons */
282
+ .btn {
283
+ width: 100%;
284
+ padding: 1rem;
285
+ border: none;
286
+ border-radius: 8px;
287
+ font-size: 1rem;
288
+ font-weight: 600;
289
+ cursor: pointer;
290
+ transition: all 0.3s;
291
+ display: flex;
292
+ justify-content: center;
293
+ align-items: center;
294
+ gap: 0.5rem;
295
+ }
296
+
297
+ .btn-primary {
298
+ background: var(--primary);
299
+ color: white;
300
+ box-shadow: 0 4px 15px rgba(99, 102, 241, 0.3);
301
+ }
302
+
303
+ .btn-primary:hover {
304
+ background: var(--primary-hover);
305
+ transform: translateY(-2px);
306
+ }
307
+
308
+ .btn-primary:disabled {
309
+ background: var(--border);
310
+ cursor: not-allowed;
311
+ transform: none;
312
+ box-shadow: none;
313
+ }
314
+
315
+ /* Toast Notification */
316
+ .toast {
317
+ position: fixed;
318
+ bottom: 2rem;
319
+ right: 2rem;
320
+ background: var(--bg-panel);
321
+ border: 1px solid var(--border);
322
+ padding: 1rem 1.5rem;
323
+ border-radius: 8px;
324
+ display: flex;
325
+ align-items: center;
326
+ gap: 1rem;
327
+ box-shadow: 0 10px 25px rgba(0,0,0,0.5);
328
+ transform: translateY(100px);
329
+ opacity: 0;
330
+ transition: all 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
331
+ z-index: 1000;
332
+ }
333
+
334
+ .toast.show {
335
+ transform: translateY(0);
336
+ opacity: 1;
337
+ }
338
+
339
+ .toast-icon {
340
+ font-size: 1.5rem;
341
+ }
342
+
343
+ .toast-success .toast-icon { color: var(--success); }
344
+ .toast-error .toast-icon { color: #ef4444; }
345
+
346
+ /* Animations */
347
+ @keyframes fadeIn {
348
+ from { opacity: 0; transform: translateY(10px); }
349
+ to { opacity: 1; transform: translateY(0); }
350
+ }
351
+
352
+ @keyframes pulse {
353
+ 0% { opacity: 0.5; }
354
+ 50% { opacity: 1; }
355
+ 100% { opacity: 0.5; }
356
+ }
357
+
358
+ .cursor {
359
+ display: inline-block;
360
+ width: 8px;
361
+ height: 15px;
362
+ background: var(--success);
363
+ animation: pulse 1s infinite;
364
+ }
365
+
366
+ /* Scrollbar */
367
+ ::-webkit-scrollbar {
368
+ width: 8px;
369
+ }
370
+ ::-webkit-scrollbar-track {
371
+ background: var(--bg-dark);
372
+ }
373
+ ::-webkit-scrollbar-thumb {
374
+ background: var(--border);
375
+ border-radius: 4px;
376
+ }
377
+ ::-webkit-scrollbar-thumb:hover {
378
+ background: var(--text-muted);
379
+ }
380
+ </style>
381
+ </head>
382
+ <body>
383
+
384
+ <header>
385
+ <div class="logo">
386
+ <i class="fa-brands fa-android"></i> APK Forge
387
+ </div>
388
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
389
+ <i class="fa-solid fa-code"></i> Built with anycoder
390
+ </a>
391
+ </header>
392
+
393
+ <main>
394
+ <!-- Left Column: Input & Config -->
395
+ <section class="left-col">
396
+ <div class="panel" style="margin-bottom: 2rem;">
397
+ <h2><i class="fa-solid fa-file-import"></i> Source Code</h2>
398
+ <div class="upload-zone" id="dropZone">
399
+ <input type="file" id="fileInput" hidden accept=".java,.jar,.js,.html,.cpp,.h">
400
+ <i class="fa-solid fa-cloud-arrow-up upload-icon"></i>
401
+ <p>Drag & Drop your file here</p>
402
+ <p style="font-size: 0.8rem; color: var(--text-muted); margin-top: 0.5rem;">
403
+ Supports .java, .jar, .js, .html, .cpp, .h
404
+ </p>
405
+
406
+ <div class="file-info" id="fileInfo">
407
+ <div class="file-name" id="fileName">script.js</div>
408
+ <div class="file-meta" id="fileMeta">12 KB • JavaScript</div>
409
+ <button id="removeFile" style="margin-top: 0.5rem; background: transparent; border: 1px solid var(--border); color: var(--text-muted); padding: 0.25rem 0.5rem; border-radius: 4px; cursor: pointer;">Remove</button>
410
+ </div>
411
+ </div>
412
+ </div>
413
+
414
+ <div class="panel">
415
+ <h2><i class="fa-solid fa-sliders"></i> Configuration</h2>
416
+ <form id="configForm">
417
+ <div class="form-group">
418
+ <label>Application Name</label>
419
+ <input type="text" id="appName" placeholder="My Awesome App" value="My App">
420
+ </div>
421
+
422
+ <div class="form-group">
423
+ <label>Package Name</label>
424
+ <input type="text" id="packageName" placeholder="com.example.myapp" value="com.example.app">
425
+ </div>
426
+
427
+ <div class="form-group">
428
+ <label>Target SDK</label>
429
+ <select id="sdkVersion">
430
+ <option value="33">Android 13 (API 33)</option>
431
+ <option value="32">Android 12L (API 32)</option>
432
+ <option value="31">Android 12 (API 31)</option>
433
+ <option value="30">Android 11 (API 30)</option>
434
+ </select>
435
+ </div>
436
+
437
+ <div class="form-group">
438
+ <label>Build Mode</label>
439
+ <select id="buildMode">
440
+ <option value="debug">Debug (Unigned)</option>
441
+ <option value="release">Release (Signed)</option>
442
+ </select>
443
+ </div>
444
+
445
+ <button type="button" id="buildBtn" class="btn btn-primary" disabled>
446
+ <i class="fa-solid fa-hammer"></i> Build APK
447
+ </button>
448
+ </form>
449
+ </div>
450
+ </section>
451
+
452
+ <!-- Right Column: Terminal & Output -->
453
+ <section class="right-col">
454
+ <div class="panel terminal-container">
455
+ <div class="terminal-header">
456
+ <h2><i class="fa-solid fa-terminal"></i> Build Console</h2>
457
+ <span class="status-badge" id="statusBadge">Idle</span>
458
+ </div>
459
+
460
+ <div class="terminal-window" id="terminal">
461
+ <div class="log-line">
462
+ <span class="log-time">[System]</span>
463
+ <span class="log-info">Welcome to APK Forge. Ready to build.</span>
464
+ </div>
465
+ <div class="log-line">
466
+ <span class="log-time">[System]</span>
467
+ <span class="log-info">Waiting for source file...</span>
468
+ </div>
469
+ <span class="cursor"></span>
470
+ </div>
471
+
472
+ <div class="progress-container" id="progressContainer">
473
+ <div class="progress-bar" id="progressBar"></div>
474
+ </div>
475
+ </div>
476
+ </section>
477
+ </main>
478
+
479
+ <!-- Toast Notification -->
480
+ <div class="toast" id="toast">
481
+ <div class="toast-icon"><i class="fa-solid fa-circle-check"></i></div>
482
+ <div class="toast-content">
483
+ <h4 id="toastTitle">Success</h4>
484
+ <p id="toastMessage" style="font-size: 0.9rem; color: var(--text-muted);">Build completed successfully.</p>
485
+ </div>
486
+ </div>
487
+
488
+ <script>
489
+ // DOM Elements
490
+ const dropZone = document.getElementById('dropZone');
491
+ const fileInput = document.getElementById('fileInput');
492
+ const fileInfo = document.getElementById('fileInfo');
493
+ const fileName = document.getElementById('fileName');
494
+ const fileMeta = document.getElementById('fileMeta');
495
+ const removeFileBtn = document.getElementById('removeFile');
496
+ const buildBtn = document.getElementById('buildBtn');
497
+ const terminal = document.getElementById('terminal');
498
+ const progressBar = document.getElementById('progressBar');
499
+ const progressContainer = document.getElementById('progressContainer');
500
+ const statusBadge = document.getElementById('statusBadge');
501
+ const toast = document.getElementById('toast');
502
+ const packageNameInput = document.getElementById('packageName');
503
+ const appNameInput = document.getElementById('appName');
504
+
505
+ // State
506
+ let currentFile = null;
507
+ let isBuilding = false;
508
+
509
+ // --- File Handling Logic ---
510
+
511
+ dropZone.addEventListener('click', () => fileInput.click());
512
+
513
+ dropZone.addEventListener('dragover', (e) => {
514
+ e.preventDefault();
515
+ dropZone.classList.add('dragover');
516
+ });
517
+
518
+ dropZone.addEventListener('dragleave', () => {
519
+ dropZone.classList.remove('dragover');
520
+ });
521
+
522
+ dropZone.addEventListener('drop', (e) => {
523
+ e.preventDefault();
524
+ dropZone.classList.remove('dragover');
525
+ if (e.dataTransfer.files.length) {
526
+ handleFile(e.dataTransfer.files[0]);
527
+ }
528
+ });
529
+
530
+ fileInput.addEventListener('change', (e) => {
531
+ if (e.target.files.length) {
532
+ handleFile(e.target.files[0]);
533
+ }
534
+ });
535
+
536
+ removeFileBtn.addEventListener('click', (e) => {
537
+ e.stopPropagation();
538
+ resetFile();
539
+ });
540
+
541
+ function handleFile(file) {
542
+ const validExtensions = ['.java', '.jar', '.js', '.html', '.cpp', '.h'];
543
+ const fileName = file.name;
544
+ const ext = fileName.substring(fileName.lastIndexOf('.')).toLowerCase();
545
+
546
+ if (!validExtensions.includes(ext)) {
547
+ showToast('error', 'Invalid File', 'Please upload .java, .jar, .js, .html, .cpp, or .h files.');
548
+ return;
549
+ }
550
+
551
+ currentFile = file;
552
+
553
+ // Auto-configure based on file type
554
+ autoConfigure(ext, fileName);
555
+
556
+ // Update UI
557
+ document.getElementById('fileName').textContent = fileName;
558
+ document.getElementById('fileMeta').textContent = `${formatBytes(file.size)} • ${getFileType(ext)}`;
559
+
560
+ dropZone.querySelector('.upload-icon').style.display = 'none';
561
+ dropZone.querySelector('p').style.display = 'none';
562
+ dropZone.querySelector('p:last-child').style.display = 'none';
563
+ fileInfo.classList.add('active');
564
+ buildBtn.disabled = false;
565
+
566
+ log(`File loaded: ${fileName}`, 'info');
567
+ }
568
+
569
+ function resetFile() {
570
+ currentFile = null;
571
+ fileInput.value = '';
572
+
573
+ dropZone.querySelector('.upload-icon').style.display = 'block';
574
+ dropZone.querySelector('p').style.display = 'block';
575
+ dropZone.querySelector('p:last-child').style.display = 'block';
576
+ fileInfo.classList.remove('active');
577
+ buildBtn.disabled = false; // Allow clicking build to show error
578
+
579
+ log('File removed.', 'warn');
580
+ }
581
+
582
+ function autoConfigure(ext, name) {
583
+ let baseName = name.replace(ext, '').replace(/[^a-zA-Z0-9]/g, ' ');
584
+ baseName = baseName.replace(/\b\w/g, l => l.toUpperCase()); // Title Case
585
+
586
+ appNameInput.value = baseName.trim() || "My App";
587
+
588
+ // Smart package name generation
589
+ const randomId = Math.floor(Math.random() * 1000);
590
+ if (ext === '.html' || ext === '.js') {
591
+ packageNameInput.value = `com.webwrapper.app${randomId}`;
592
+ log('Detected Web Project. Configuring WebView Wrapper.', 'info');
593
+ } else if (ext === '.cpp' || ext === '.h') {
594
+ packageNameInput.value = `com.native.ndk.app${randomId}`;
595
+ log('Detected Native C++. Configuring NDK Build.', 'info');
596
+ } else {
597
+ packageNameInput.value = `com.example.app${randomId}`;
598
+ }
599
+ }
600
+
601
+ // --- Build Simulation Logic ---
602
+
603
+ buildBtn.addEventListener('click', () => {
604
+ if (!currentFile) {
605
+ showToast('error', 'No File', 'Please upload a source file first.');
606
+ return;
607
+ }
608
+ if (isBuilding) return;
609
+ startBuild();
610
+ });
611
+
612
+ function startBuild() {
613
+ isBuilding = true;
614
+ buildBtn.disabled = true;
615
+ buildBtn.innerHTML = '<i class="fa-solid fa-circle-notch fa-spin"></i> Building...';
616
+ statusBadge.textContent = 'Compiling';
617
+ statusBadge.classList.add('active');
618
+ progressContainer.classList.add('active');
619
+
620
+ // Clear previous logs (keep header)
621
+ const logs = terminal.querySelectorAll('.log-line:not(:first-child):not(:nth-child(2))');
622
+ logs.forEach(l => l.remove());
623
+
624
+ const steps = [
625
+ { msg: `Initializing build environment...`, delay: 500, type: 'info' },
626
+ { msg: `Reading source: ${currentFile.name}`, delay: 1200, type: 'cmd' },
627
+ { msg: `Auto-configuring AndroidManifest.xml`, delay: 1800, type: 'info' },
628
+ { msg: `Generating R.java files...`, delay: 2500, type: 'info' },
629
+ { msg: `Compiling resources with AAPT2`, delay: 3200, type: 'cmd' },
630
+ { msg: `Converting Java bytecode to DEX (dx/d8)`, delay: 4000, type: 'cmd' },
631
+ { msg: `Packaging APK (apkbuilder)`, delay: 5000, type: 'info' },
632
+ { msg: `Signing APK with debug key...`, delay: 6000, type: 'warn' },
633
+ { msg: `Build Successful! Output generated.`, delay: 7000, type: 'success' }
634
+ ];
635
+
636
+ let totalDelay = 7000;
637
+
638
+ steps.forEach(step => {
639
+ setTimeout(() => {
640
+ log(step.msg, step.type);
641
+ // Update progress bar roughly
642
+ const progress = (step.delay / totalDelay) * 100;
643
+ progressBar.style.width = `${Math.min(progress, 100)}%`;
644
+ }, step.delay);
645
+ });
646
+
647
+ setTimeout(() => {
648
+ finishBuild();
649
+ }, totalDelay + 500);
650
+ }
651
+
652
+ function finishBuild() {
653
+ isBuilding = false;
654
+ buildBtn.disabled = false;
655
+ buildBtn.innerHTML = '<i class="fa-solid fa-hammer"></i> Build APK';
656
+ statusBadge.textContent = 'Completed';
657
+ statusBadge.classList.remove('active');
658
+
659
+ showToast('success', 'Build Complete', 'APK downloaded to your device.');
660
+
661
+ // Trigger Download
662
+ downloadDummyApk();
663
+ }
664
+
665
+ // --- Helper Functions ---
666
+
667
+ function log(message, type = 'info') {
668
+ const line = document.createElement('div');
669
+ line.className = 'log-line';
670
+
671
+ const time = new Date().toLocaleTimeString('en-US', { hour12: false });
672
+
673
+ line.innerHTML = `
674
+ <span class="log-time">[${time}]</span>
675
+ <span class="log-${type}">${message}</span>
676
+ `;
677
+
678
+ // Insert before cursor
679
+ const cursor = terminal.querySelector('.cursor');
680
+ terminal.insertBefore(line, cursor);
681
+
682
+ // Auto scroll
683
+ terminal.scrollTop = terminal.scrollHeight;
684
+ }
685
+
686
+ function formatBytes(bytes, decimals = 2) {
687
+ if (!+bytes) return '0 Bytes';
688
+ const k = 1024;
689
+ const dm = decimals < 0 ? 0 : decimals;
690
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
691
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
692
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
693
+ }
694
+
695
+ function getFileType(ext) {
696
+ const map = {
697
+ '.java': 'Java Source',
698
+ '.jar': 'Java Archive',
699
+ '.js': 'JavaScript',
700
+ '.html': 'HTML Document',
701
+ '.cpp': 'C++ Source',
702
+ '.h': 'C++ Header'
703
+ };
704
+ return map[ext] || 'Unknown';
705
+ }
706
+
707
+ function showToast(type, title, message) {
708
+ const toastEl = document.getElementById('toast');
709
+ const icon = toastEl.querySelector('.toast-icon i');
710
+ const titleEl = document.getElementById('toastTitle');
711
+ const msgEl = document.getElementById('toastMessage');
712
+
713
+ toastEl.className = `toast toast-${type} show`;
714
+
715
+ if (type === 'success') {
716
+ icon.className = 'fa-solid fa-circle-check';
717
+ } else {
718
+ icon.className = 'fa-solid fa-circle-exclamation';
719
+ }
720
+
721
+ titleEl.textContent = title;
722
+ msgEl.textContent = message;
723
+
724
+ setTimeout(() => {
725
+ toastEl.classList.remove('show');
726
+ }, 4000);
727
+ }
728
+
729
+ // --- Mock Download Logic ---
730
+ // Since we cannot actually compile C++/Java in the browser without a backend,
731
+ // we generate a dummy ZIP file renamed to .apk to simulate the experience.
732
+ function downloadDummyApk() {
733
+ const appName = appNameInput.value.replace(/\s+/g, '').toLowerCase() || 'app';
734
+ const filename = `${appName}.apk`;
735
+
736
+ // Create a dummy text content that mimics a manifest
737
+ const dummyContent = `
738
+ PK.....
739
+ [AndroidManifest.xml]
740
+ Package: ${packageNameInput.value}
741
+ App Name: ${appNameInput.value}
742
+ Source: ${currentFile.name}
743
+ Type: Auto-generated by APK Forge
744
+ `;
745
+
746
+ const blob = new Blob([dummyContent], { type: 'application/vnd.android.package-archive' });
747
+ const url = window.URL.createObjectURL(blob);
748
+ const a = document.createElement('a');
749
+ a.style.display = 'none';
750
+ a.href = url;
751
+ a.download = filename;
752
+ document.body.appendChild(a);
753
+ a.click();
754
+
755
+ window.URL.revokeObjectURL(url);
756
+ document.body.removeChild(a);
757
+
758
+ log(`Triggered download for ${filename}`, 'success');
759
+ }
760
+ </script>
761
+ </body>
762
+ </html>