Athagi commited on
Commit
bad8f36
·
verified ·
1 Parent(s): 9216c2a

Create templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +662 -0
templates/index.html ADDED
@@ -0,0 +1,662 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 Editor</title>
7
+ <style>
8
+ :root {
9
+ --primary-color: #4285f4;
10
+ --secondary-color: #34a853;
11
+ --danger-color: #ea4335;
12
+ --warning-color: #fbbc05;
13
+ --light-color: #f8f9fa;
14
+ --dark-color: #343a40;
15
+ }
16
+
17
+ * {
18
+ box-sizing: border-box;
19
+ margin: 0;
20
+ padding: 0;
21
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
22
+ }
23
+
24
+ body {
25
+ background-color: #f5f5f5;
26
+ color: #333;
27
+ line-height: 1.6;
28
+ }
29
+
30
+ .container {
31
+ max-width: 1200px;
32
+ margin: 0 auto;
33
+ padding: 20px;
34
+ }
35
+
36
+ header {
37
+ background-color: var(--primary-color);
38
+ color: white;
39
+ padding: 20px 0;
40
+ text-align: center;
41
+ margin-bottom: 30px;
42
+ border-radius: 5px;
43
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
44
+ }
45
+
46
+ h1 {
47
+ margin-bottom: 10px;
48
+ }
49
+
50
+ .card {
51
+ background-color: white;
52
+ border-radius: 5px;
53
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
54
+ padding: 20px;
55
+ margin-bottom: 20px;
56
+ }
57
+
58
+ .card h2 {
59
+ margin-bottom: 15px;
60
+ color: var(--primary-color);
61
+ border-bottom: 1px solid #eee;
62
+ padding-bottom: 10px;
63
+ }
64
+
65
+ .form-group {
66
+ margin-bottom: 15px;
67
+ }
68
+
69
+ label {
70
+ display: block;
71
+ margin-bottom: 5px;
72
+ font-weight: bold;
73
+ }
74
+
75
+ input[type="file"] {
76
+ display: none;
77
+ }
78
+
79
+ .file-upload {
80
+ border: 2px dashed #ccc;
81
+ padding: 20px;
82
+ text-align: center;
83
+ cursor: pointer;
84
+ margin-bottom: 10px;
85
+ border-radius: 5px;
86
+ transition: all 0.3s;
87
+ }
88
+
89
+ .file-upload:hover {
90
+ border-color: var(--primary-color);
91
+ background-color: #f8f9fa;
92
+ }
93
+
94
+ .btn {
95
+ display: inline-block;
96
+ background-color: var(--primary-color);
97
+ color: white;
98
+ padding: 10px 20px;
99
+ border: none;
100
+ border-radius: 5px;
101
+ cursor: pointer;
102
+ text-decoration: none;
103
+ font-size: 16px;
104
+ transition: background-color 0.3s;
105
+ }
106
+
107
+ .btn:hover {
108
+ background-color: #3367d6;
109
+ }
110
+
111
+ .btn-secondary {
112
+ background-color: var(--secondary-color);
113
+ }
114
+
115
+ .btn-secondary:hover {
116
+ background-color: #2d9249;
117
+ }
118
+
119
+ .btn-danger {
120
+ background-color: var(--danger-color);
121
+ }
122
+
123
+ .btn-danger:hover {
124
+ background-color: #d33426;
125
+ }
126
+
127
+ .progress-container {
128
+ width: 100%;
129
+ background-color: #f1f1f1;
130
+ border-radius: 5px;
131
+ margin: 10px 0;
132
+ display: none;
133
+ }
134
+
135
+ .progress-bar {
136
+ height: 20px;
137
+ background-color: var(--primary-color);
138
+ border-radius: 5px;
139
+ width: 0%;
140
+ transition: width 0.3s;
141
+ text-align: center;
142
+ color: white;
143
+ line-height: 20px;
144
+ font-size: 12px;
145
+ }
146
+
147
+ .status {
148
+ padding: 10px;
149
+ border-radius: 5px;
150
+ margin-bottom: 10px;
151
+ display: none;
152
+ }
153
+
154
+ .status.success {
155
+ background-color: #d4edda;
156
+ color: #155724;
157
+ display: block;
158
+ }
159
+
160
+ .status.error {
161
+ background-color: #f8d7da;
162
+ color: #721c24;
163
+ display: block;
164
+ }
165
+
166
+ .status.info {
167
+ background-color: #d1ecf1;
168
+ color: #0c5460;
169
+ display: block;
170
+ }
171
+
172
+ .icon-preview {
173
+ max-width: 100px;
174
+ max-height: 100px;
175
+ margin: 10px 0;
176
+ display: none;
177
+ }
178
+
179
+ .step {
180
+ margin-bottom: 30px;
181
+ }
182
+
183
+ .step-number {
184
+ display: inline-block;
185
+ background-color: var(--primary-color);
186
+ color: white;
187
+ width: 30px;
188
+ height: 30px;
189
+ text-align: center;
190
+ line-height: 30px;
191
+ border-radius: 50%;
192
+ margin-right: 10px;
193
+ }
194
+
195
+ .hidden {
196
+ display: none;
197
+ }
198
+
199
+ #downloadBtn {
200
+ display: none;
201
+ }
202
+
203
+ @media (max-width: 768px) {
204
+ .container {
205
+ padding: 10px;
206
+ }
207
+
208
+ .card {
209
+ padding: 15px;
210
+ }
211
+ }
212
+ </style>
213
+ </head>
214
+ <body>
215
+ <div class="container">
216
+ <header>
217
+ <h1>APK Editor</h1>
218
+ <p>Modify and customize your Android APK files</p>
219
+ </header>
220
+
221
+ <div class="card">
222
+ <div class="step">
223
+ <h2><span class="step-number">1</span>Upload APK</h2>
224
+ <div class="form-group">
225
+ <label for="apkFile">Select APK File:</label>
226
+ <input type="file" id="apkFile" accept=".apk">
227
+ <div class="file-upload" id="fileUpload">
228
+ <p>Click to select APK file or drag and drop here</p>
229
+ <p id="fileName">No file selected</p>
230
+ </div>
231
+ <button class="btn" id="uploadBtn">Upload</button>
232
+ </div>
233
+ <div class="progress-container" id="uploadProgressContainer">
234
+ <div class="progress-bar" id="uploadProgressBar">0%</div>
235
+ </div>
236
+ <div class="status" id="uploadStatus"></div>
237
+ </div>
238
+
239
+ <div class="step hidden" id="decompileStep">
240
+ <h2><span class="step-number">2</span>Decompile APK</h2>
241
+ <p>Decompile the APK to access its resources and manifest</p>
242
+ <button class="btn" id="decompileBtn">Decompile</button>
243
+ <div class="progress-container" id="decompileProgressContainer">
244
+ <div class="progress-bar" id="decompileProgressBar">0%</div>
245
+ </div>
246
+ <div class="status" id="decompileStatus"></div>
247
+ <img id="appIcon" class="icon-preview" alt="App Icon">
248
+ </div>
249
+
250
+ <div class="step hidden" id="modifyStep">
251
+ <h2><span class="step-number">3</span>Modify APK</h2>
252
+ <div class="form-group">
253
+ <label for="appName">New App Name:</label>
254
+ <input type="text" id="appName" class="form-control" placeholder="Enter new app name">
255
+ </div>
256
+ <div class="form-group">
257
+ <label for="packageName">New Package Name:</label>
258
+ <input type="text" id="packageName" class="form-control" placeholder="com.example.newapp">
259
+ </div>
260
+ <div class="form-group">
261
+ <label for="versionCode">Version Code:</label>
262
+ <input type="number" id="versionCode" class="form-control" placeholder="1">
263
+ </div>
264
+ <div class="form-group">
265
+ <label for="versionName">Version Name:</label>
266
+ <input type="text" id="versionName" class="form-control" placeholder="1.0">
267
+ </div>
268
+ <button class="btn" id="saveChangesBtn">Save Changes</button>
269
+ <div class="status" id="modifyStatus"></div>
270
+ </div>
271
+
272
+ <div class="step hidden" id="recompileStep">
273
+ <h2><span class="step-number">4</span>Recompile APK</h2>
274
+ <p>Recompile the modified APK</p>
275
+ <button class="btn" id="recompileBtn">Recompile</button>
276
+ <div class="progress-container" id="recompileProgressContainer">
277
+ <div class="progress-bar" id="recompileProgressBar">0%</div>
278
+ </div>
279
+ <div class="status" id="recompileStatus"></div>
280
+ </div>
281
+
282
+ <div class="step hidden" id="signStep">
283
+ <h2><span class="step-number">5</span>Sign APK</h2>
284
+ <p>Sign the APK with a debug key</p>
285
+ <button class="btn" id="signBtn">Sign APK</button>
286
+ <div class="progress-container" id="signProgressContainer">
287
+ <div class="progress-bar" id="signProgressBar">0%</div>
288
+ </div>
289
+ <div class="status" id="signStatus"></div>
290
+ </div>
291
+
292
+ <div class="step hidden" id="downloadStep">
293
+ <h2><span class="step-number">6</span>Download APK</h2>
294
+ <p>Your modified APK is ready!</p>
295
+ <a href="#" class="btn btn-secondary" id="downloadBtn">Download APK</a>
296
+ <div class="status" id="downloadStatus"></div>
297
+ </div>
298
+ </div>
299
+ </div>
300
+
301
+ <script>
302
+ // Global variables to store APK file info
303
+ let currentApk = {
304
+ path: null,
305
+ decompiledPath: null,
306
+ modifiedPath: null,
307
+ signedPath: null
308
+ };
309
+
310
+ // DOM elements
311
+ const apkFileInput = document.getElementById('apkFile');
312
+ const fileUpload = document.getElementById('fileUpload');
313
+ const fileName = document.getElementById('fileName');
314
+ const uploadBtn = document.getElementById('uploadBtn');
315
+ const uploadProgressContainer = document.getElementById('uploadProgressContainer');
316
+ const uploadProgressBar = document.getElementById('uploadProgressBar');
317
+ const uploadStatus = document.getElementById('uploadStatus');
318
+
319
+ const decompileStep = document.getElementById('decompileStep');
320
+ const decompileBtn = document.getElementById('decompileBtn');
321
+ const decompileProgressContainer = document.getElementById('decompileProgressContainer');
322
+ const decompileProgressBar = document.getElementById('decompileProgressBar');
323
+ const decompileStatus = document.getElementById('decompileStatus');
324
+ const appIcon = document.getElementById('appIcon');
325
+
326
+ const modifyStep = document.getElementById('modifyStep');
327
+ const saveChangesBtn = document.getElementById('saveChangesBtn');
328
+ const modifyStatus = document.getElementById('modifyStatus');
329
+
330
+ const recompileStep = document.getElementById('recompileStep');
331
+ const recompileBtn = document.getElementById('recompileBtn');
332
+ const recompileProgressContainer = document.getElementById('recompileProgressContainer');
333
+ const recompileProgressBar = document.getElementById('recompileProgressBar');
334
+ const recompileStatus = document.getElementById('recompileStatus');
335
+
336
+ const signStep = document.getElementById('signStep');
337
+ const signBtn = document.getElementById('signBtn');
338
+ const signProgressContainer = document.getElementById('signProgressContainer');
339
+ const signProgressBar = document.getElementById('signProgressBar');
340
+ const signStatus = document.getElementById('signStatus');
341
+
342
+ const downloadStep = document.getElementById('downloadStep');
343
+ const downloadBtn = document.getElementById('downloadBtn');
344
+ const downloadStatus = document.getElementById('downloadStatus');
345
+
346
+ // Event listeners
347
+ fileUpload.addEventListener('click', () => apkFileInput.click());
348
+
349
+ apkFileInput.addEventListener('change', (e) => {
350
+ if (e.target.files.length > 0) {
351
+ fileName.textContent = e.target.files[0].name;
352
+ } else {
353
+ fileName.textContent = 'No file selected';
354
+ }
355
+ });
356
+
357
+ // Drag and drop functionality
358
+ fileUpload.addEventListener('dragover', (e) => {
359
+ e.preventDefault();
360
+ fileUpload.style.borderColor = '#4285f4';
361
+ fileUpload.style.backgroundColor = '#f8f9fa';
362
+ });
363
+
364
+ fileUpload.addEventListener('dragleave', () => {
365
+ fileUpload.style.borderColor = '#ccc';
366
+ fileUpload.style.backgroundColor = 'transparent';
367
+ });
368
+
369
+ fileUpload.addEventListener('drop', (e) => {
370
+ e.preventDefault();
371
+ fileUpload.style.borderColor = '#ccc';
372
+ fileUpload.style.backgroundColor = 'transparent';
373
+
374
+ if (e.dataTransfer.files.length > 0) {
375
+ const file = e.dataTransfer.files[0];
376
+ if (file.name.endsWith('.apk')) {
377
+ apkFileInput.files = e.dataTransfer.files;
378
+ fileName.textContent = file.name;
379
+ } else {
380
+ showStatus(uploadStatus, 'Only APK files are allowed', 'error');
381
+ }
382
+ }
383
+ });
384
+
385
+ uploadBtn.addEventListener('click', uploadApk);
386
+ decompileBtn.addEventListener('click', decompileApk);
387
+ saveChangesBtn.addEventListener('click', saveChanges);
388
+ recompileBtn.addEventListener('click', recompileApk);
389
+ signBtn.addEventListener('click', signApk);
390
+
391
+ // Functions
392
+ function showStatus(element, message, type) {
393
+ element.textContent = message;
394
+ element.className = 'status ' + type;
395
+ }
396
+
397
+ function resetStatus(element) {
398
+ element.textContent = '';
399
+ element.className = 'status';
400
+ element.style.display = 'none';
401
+ }
402
+
403
+ function updateProgressBar(bar, container, percentage) {
404
+ bar.style.width = percentage + '%';
405
+ bar.textContent = percentage + '%';
406
+ container.style.display = 'block';
407
+ }
408
+
409
+ function hideProgressBar(container) {
410
+ container.style.display = 'none';
411
+ }
412
+
413
+ async function uploadApk() {
414
+ if (!apkFileInput.files || apkFileInput.files.length === 0) {
415
+ showStatus(uploadStatus, 'Please select an APK file first', 'error');
416
+ return;
417
+ }
418
+
419
+ const file = apkFileInput.files[0];
420
+ const formData = new FormData();
421
+ formData.append('file', file);
422
+
423
+ resetStatus(uploadStatus);
424
+ updateProgressBar(uploadProgressBar, uploadProgressContainer, 0);
425
+
426
+ try {
427
+ const response = await fetch('/api/upload', {
428
+ method: 'POST',
429
+ body: formData,
430
+ });
431
+
432
+ const data = await response.json();
433
+
434
+ if (response.ok) {
435
+ currentApk.path = data.filepath;
436
+ showStatus(uploadStatus, 'APK uploaded successfully!', 'success');
437
+ updateProgressBar(uploadProgressBar, uploadProgressContainer, 100);
438
+
439
+ // Show next step
440
+ decompileStep.classList.remove('hidden');
441
+
442
+ // Extract and show app icon
443
+ extractAppIcon();
444
+ } else {
445
+ showStatus(uploadStatus, data.error || 'Upload failed', 'error');
446
+ hideProgressBar(uploadProgressContainer);
447
+ }
448
+ } catch (error) {
449
+ showStatus(uploadStatus, 'Error uploading file: ' + error.message, 'error');
450
+ hideProgressBar(uploadProgressContainer);
451
+ }
452
+ }
453
+
454
+ async function extractAppIcon() {
455
+ try {
456
+ const response = await fetch('/api/extract_icon', {
457
+ method: 'POST',
458
+ headers: {
459
+ 'Content-Type': 'application/json',
460
+ },
461
+ body: JSON.stringify({
462
+ apk_path: currentApk.path
463
+ }),
464
+ });
465
+
466
+ if (response.ok) {
467
+ const blob = await response.blob();
468
+ const objectURL = URL.createObjectURL(blob);
469
+ appIcon.src = objectURL;
470
+ appIcon.style.display = 'block';
471
+ }
472
+ } catch (error) {
473
+ console.error('Error extracting app icon:', error);
474
+ }
475
+ }
476
+
477
+ async function decompileApk() {
478
+ if (!currentApk.path) {
479
+ showStatus(decompileStatus, 'No APK file available', 'error');
480
+ return;
481
+ }
482
+
483
+ resetStatus(decompileStatus);
484
+ updateProgressBar(decompileProgressBar, decompileProgressContainer, 0);
485
+
486
+ try {
487
+ const response = await fetch('/api/decompile', {
488
+ method: 'POST',
489
+ headers: {
490
+ 'Content-Type': 'application/json',
491
+ },
492
+ body: JSON.stringify({
493
+ apk_path: currentApk.path
494
+ }),
495
+ });
496
+
497
+ const data = await response.json();
498
+
499
+ if (response.ok) {
500
+ currentApk.decompiledPath = data.output_dir;
501
+ showStatus(decompileStatus, 'APK decompiled successfully!', 'success');
502
+ updateProgressBar(decompileProgressBar, decompileProgressContainer, 100);
503
+
504
+ // Show next step
505
+ modifyStep.classList.remove('hidden');
506
+ } else {
507
+ showStatus(decompileStatus, data.error || 'Decompilation failed', 'error');
508
+ hideProgressBar(decompileProgressContainer);
509
+ }
510
+ } catch (error) {
511
+ showStatus(decompileStatus, 'Error decompiling APK: ' + error.message, 'error');
512
+ hideProgressBar(decompileProgressContainer);
513
+ }
514
+ }
515
+
516
+ async function saveChanges() {
517
+ const appName = document.getElementById('appName').value;
518
+ const packageName = document.getElementById('packageName').value;
519
+ const versionCode = document.getElementById('versionCode').value;
520
+ const versionName = document.getElementById('versionName').value;
521
+
522
+ if (!appName && !packageName && !versionCode && !versionName) {
523
+ showStatus(modifyStatus, 'No changes specified', 'error');
524
+ return;
525
+ }
526
+
527
+ resetStatus(modifyStatus);
528
+
529
+ try {
530
+ const response = await fetch('/api/modify_manifest', {
531
+ method: 'POST',
532
+ headers: {
533
+ 'Content-Type': 'application/json',
534
+ },
535
+ body: JSON.stringify({
536
+ decompiled_dir: currentApk.decompiledPath,
537
+ modifications: [
538
+ {
539
+ action: 'set_attribute',
540
+ path: '.',
541
+ attribute: 'package',
542
+ value: packageName || 'com.example.app'
543
+ },
544
+ {
545
+ action: 'set_attribute',
546
+ path: '.',
547
+ attribute: 'android:versionCode',
548
+ value: versionCode || '1'
549
+ },
550
+ {
551
+ action: 'set_attribute',
552
+ path: '.',
553
+ attribute: 'android:versionName',
554
+ value: versionName || '1.0'
555
+ },
556
+ {
557
+ action: 'set_attribute',
558
+ path: 'application',
559
+ attribute: 'android:label',
560
+ value: appName || 'My App'
561
+ }
562
+ ]
563
+ }),
564
+ });
565
+
566
+ const data = await response.json();
567
+
568
+ if (response.ok) {
569
+ showStatus(modifyStatus, 'Changes saved successfully!', 'success');
570
+
571
+ // Show next step
572
+ recompileStep.classList.remove('hidden');
573
+ } else {
574
+ showStatus(modifyStatus, data.error || 'Failed to save changes', 'error');
575
+ }
576
+ } catch (error) {
577
+ showStatus(modifyStatus, 'Error saving changes: ' + error.message, 'error');
578
+ }
579
+ }
580
+
581
+ async function recompileApk() {
582
+ if (!currentApk.decompiledPath) {
583
+ showStatus(recompileStatus, 'No decompiled APK available', 'error');
584
+ return;
585
+ }
586
+
587
+ resetStatus(recompileStatus);
588
+ updateProgressBar(recompileProgressBar, recompileProgressContainer, 0);
589
+
590
+ try {
591
+ const response = await fetch('/api/recompile', {
592
+ method: 'POST',
593
+ headers: {
594
+ 'Content-Type': 'application/json',
595
+ },
596
+ body: JSON.stringify({
597
+ decompiled_dir: currentApk.decompiledPath
598
+ }),
599
+ });
600
+
601
+ const data = await response.json();
602
+
603
+ if (response.ok) {
604
+ currentApk.modifiedPath = data.output_apk;
605
+ showStatus(recompileStatus, 'APK recompiled successfully!', 'success');
606
+ updateProgressBar(recompileProgressBar, recompileProgressContainer, 100);
607
+
608
+ // Show next step
609
+ signStep.classList.remove('hidden');
610
+ } else {
611
+ showStatus(recompileStatus, data.error || 'Recompilation failed', 'error');
612
+ hideProgressBar(recompileProgressContainer);
613
+ }
614
+ } catch (error) {
615
+ showStatus(recompileStatus, 'Error recompiling APK: ' + error.message, 'error');
616
+ hideProgressBar(recompileProgressContainer);
617
+ }
618
+ }
619
+
620
+ async function signApk() {
621
+ if (!currentApk.modifiedPath) {
622
+ showStatus(signStatus, 'No modified APK available', 'error');
623
+ return;
624
+ }
625
+
626
+ resetStatus(signStatus);
627
+ updateProgressBar(signProgressBar, signProgressContainer, 0);
628
+
629
+ try {
630
+ const response = await fetch('/api/sign', {
631
+ method: 'POST',
632
+ headers: {
633
+ 'Content-Type': 'application/json',
634
+ },
635
+ body: JSON.stringify({
636
+ apk_path: currentApk.modifiedPath
637
+ }),
638
+ });
639
+
640
+ const data = await response.json();
641
+
642
+ if (response.ok) {
643
+ currentApk.signedPath = data.signed_apk;
644
+ showStatus(signStatus, 'APK signed successfully!', 'success');
645
+ updateProgressBar(signProgressBar, signProgressContainer, 100);
646
+
647
+ // Show next step
648
+ downloadStep.classList.remove('hidden');
649
+ downloadBtn.href = `/api/download?apk_path=${encodeURIComponent(currentApk.signedPath)}`;
650
+ downloadBtn.style.display = 'inline-block';
651
+ } else {
652
+ showStatus(signStatus, data.error || 'Signing failed', 'error');
653
+ hideProgressBar(signProgressContainer);
654
+ }
655
+ } catch (error) {
656
+ showStatus(signStatus, 'Error signing APK: ' + error.message, 'error');
657
+ hideProgressBar(signProgressContainer);
658
+ }
659
+ }
660
+ </script>
661
+ </body>
662
+ </html>