Skip to content

Commit 48c64ea

Browse files
committed
feat(batch): Implement multi Disable/Enable apps
1 parent bf1ace4 commit 48c64ea

4 files changed

Lines changed: 229 additions & 5 deletions

File tree

backend/adb_service.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,65 @@ func (a *App) UninstallMultiplePackages(packageNames []string) (string, error) {
431431
return summary, nil
432432
}
433433

434+
func (a *App) DisableMultiplePackages(packageNames []string) (string, error) {
435+
if len(packageNames) == 0 {
436+
return "", fmt.Errorf("no packages selected")
437+
}
438+
439+
var successCount int
440+
var failCount int
441+
var errorMessages strings.Builder
442+
443+
for _, pkgName := range packageNames {
444+
_, err := a.DisablePackage(pkgName)
445+
if err != nil {
446+
failCount++
447+
errorMsg := err.Error()
448+
if strings.Contains(errorMsg, "is not allowed") {
449+
errorMessages.WriteString(fmt.Sprintf("Failed %s: (System app?)\n", pkgName))
450+
} else {
451+
errorMessages.WriteString(fmt.Sprintf("Failed %s: %v\n", pkgName, err))
452+
}
453+
} else {
454+
successCount++
455+
}
456+
}
457+
458+
summary := fmt.Sprintf("Successfully disabled %d packages.", successCount)
459+
if failCount > 0 {
460+
summary += fmt.Sprintf(" Failed to disable %d packages.\nDetails:\n%s", failCount, errorMessages.String())
461+
}
462+
463+
return summary, nil
464+
}
465+
466+
func (a *App) EnableMultiplePackages(packageNames []string) (string, error) {
467+
if len(packageNames) == 0 {
468+
return "", fmt.Errorf("no packages selected")
469+
}
470+
471+
var successCount int
472+
var failCount int
473+
var errorMessages strings.Builder
474+
475+
for _, pkgName := range packageNames {
476+
_, err := a.EnablePackage(pkgName)
477+
if err != nil {
478+
failCount++
479+
errorMessages.WriteString(fmt.Sprintf("Failed %s: %v\n", pkgName, err))
480+
} else {
481+
successCount++
482+
}
483+
}
484+
485+
summary := fmt.Sprintf("Successfully enabled %d packages.", successCount)
486+
if failCount > 0 {
487+
summary += fmt.Sprintf(" Failed to enable %d packages.\nDetails:\n%s", failCount, errorMessages.String())
488+
}
489+
490+
return summary, nil
491+
}
492+
434493
func (a *App) DeleteMultipleFiles(fullPaths []string) (string, error) {
435494
if len(fullPaths) == 0 {
436495
return "", fmt.Errorf("no files selected")

frontend/src/components/views/ViewAppManager.tsx

Lines changed: 158 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
EnablePackage,
1111
PullApk,
1212
UninstallMultiplePackages,
13+
DisableMultiplePackages,
14+
EnableMultiplePackages,
1315
} from '../../../wailsjs/go/backend/App';
1416
import { backend } from '../../../wailsjs/go/models';
1517

@@ -90,6 +92,11 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
9092
const [isBatchUninstalling, setIsBatchUninstalling] = useState(false);
9193
const [isBatchUninstallOpen, setIsBatchUninstallOpen] = useState(false);
9294

95+
const [isBatchDisabling, setIsBatchDisabling] = useState(false);
96+
const [isBatchDisablingOpen, setIsBatchDisablingOpen] = useState(false);
97+
const [isBatchEnabling, setIsBatchEnabling] = useState(false);
98+
const [isBatchEnablingOpen, setIsBatchEnablingOpen] = useState(false);
99+
93100
const loadPackages = async (currentFilter: FilterType) => {
94101
setIsLoadingList(true);
95102
try {
@@ -330,6 +337,60 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
330337
setIsBatchUninstallOpen(false);
331338
}
332339
};
340+
341+
const handleMultiDisable = async () => {
342+
if (selectedPackages.length === 0) return;
343+
setIsBatchDisabling(true);
344+
const toastId = toast.loading(
345+
`Disabling ${selectedPackages.length} packages...`
346+
);
347+
try {
348+
const output = await DisableMultiplePackages(selectedPackages);
349+
toast.success('Batch Disable Complete', {
350+
description: output,
351+
id: toastId,
352+
duration: 8000,
353+
});
354+
loadPackages(filter);
355+
setSelectedPackages([]);
356+
} catch (error) {
357+
toast.error('Batch Disable Failed', {
358+
description: String(error),
359+
id: toastId,
360+
});
361+
} finally {
362+
setIsBatchDisabling(false);
363+
setIsBatchDisablingOpen(false);
364+
}
365+
};
366+
367+
const handleMultiEnable = async () => {
368+
if (selectedPackages.length === 0) return;
369+
setIsBatchEnabling(true);
370+
const toastId = toast.loading(
371+
`Enabling ${selectedPackages.length} packages...`
372+
);
373+
try {
374+
const output = await EnableMultiplePackages(selectedPackages);
375+
toast.success('Batch Enable Complete', {
376+
description: output,
377+
id: toastId,
378+
duration: 8000,
379+
});
380+
loadPackages(filter);
381+
setSelectedPackages([]);
382+
} catch (error) {
383+
toast.error('Batch Enable Failed', {
384+
description: String(error),
385+
id: toastId,
386+
});
387+
} finally {
388+
setIsBatchEnabling(false);
389+
setIsBatchEnablingOpen(false);
390+
}
391+
};
392+
393+
const isBusy = isLoadingList || isBatchUninstalling || isBatchDisabling || isBatchEnabling;
333394

334395
return (
335396
<>
@@ -396,6 +457,78 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
396457
</AlertDialogContent>
397458
</AlertDialog>
398459

460+
<AlertDialog
461+
open={isBatchDisablingOpen}
462+
onOpenChange={setIsBatchDisablingOpen}
463+
>
464+
<AlertDialogContent>
465+
<AlertDialogHeader>
466+
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
467+
<AlertDialogDescription>
468+
You are about to attempt to disable{' '}
469+
<span className="font-semibold text-foreground">
470+
{selectedPackages.length} selected packages
471+
</span>
472+
.
473+
<br />
474+
<strong className="text-destructive">
475+
System apps will likely fail (this is normal).
476+
</strong>
477+
</AlertDialogDescription>
478+
</AlertDialogHeader>
479+
<AlertDialogFooter>
480+
<AlertDialogCancel disabled={isBatchDisabling}>
481+
Cancel
482+
</AlertDialogCancel>
483+
<AlertDialogAction
484+
onClick={handleMultiDisable}
485+
disabled={isBatchDisabling}
486+
>
487+
{isBatchDisabling ? (
488+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
489+
) : (
490+
<EyeOff className="mr-2 h-4 w-4" />
491+
)}
492+
Yes, Disable {selectedPackages.length}
493+
</AlertDialogAction>
494+
</AlertDialogFooter>
495+
</AlertDialogContent>
496+
</AlertDialog>
497+
498+
<AlertDialog
499+
open={isBatchEnablingOpen}
500+
onOpenChange={setIsBatchEnablingOpen}
501+
>
502+
<AlertDialogContent>
503+
<AlertDialogHeader>
504+
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
505+
<AlertDialogDescription>
506+
You are about to attempt to enable{' '}
507+
<span className="font-semibold text-foreground">
508+
{selectedPackages.length} selected packages
509+
</span>
510+
.
511+
</AlertDialogDescription>
512+
</AlertDialogHeader>
513+
<AlertDialogFooter>
514+
<AlertDialogCancel disabled={isBatchEnabling}>
515+
Cancel
516+
</AlertDialogCancel>
517+
<AlertDialogAction
518+
onClick={handleMultiEnable}
519+
disabled={isBatchEnabling}
520+
>
521+
{isBatchEnabling ? (
522+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
523+
) : (
524+
<Eye className="mr-2 h-4 w-4" />
525+
)}
526+
Yes, Enable {selectedPackages.length}
527+
</AlertDialogAction>
528+
</AlertDialogFooter>
529+
</AlertDialogContent>
530+
</AlertDialog>
531+
399532
<div className="flex flex-col gap-6">
400533

401534
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
@@ -519,7 +652,8 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
519652
List of applications installed on the device.
520653
</CardDescription>
521654
</div>
522-
<div className="flex items-center gap-2">
655+
<div className="flex items-center gap-2 flex-wrap justify-end">
656+
{/* Grup Filter */}
523657
<Button
524658
variant={filter === 'user' ? 'default' : 'outline'}
525659
size="sm"
@@ -545,22 +679,41 @@ export function ViewAppManager({ activeView }: { activeView: string }) {
545679
variant="ghost"
546680
size="icon"
547681
onClick={() => loadPackages(filter)}
548-
disabled={isLoadingList || isBatchUninstalling}
682+
disabled={isBusy}
549683
>
550-
{isLoadingList ? (
684+
{isBusy ? (
551685
<Loader2 className="h-4 w-4 animate-spin" />
552686
) : (
553687
<RefreshCw className="h-4 w-4" />
554688
)}
555689
</Button>
690+
691+
<Button
692+
variant="outline"
693+
size="sm"
694+
disabled={selectedPackages.length === 0 || isBusy}
695+
onClick={() => setIsBatchEnablingOpen(true)}
696+
>
697+
<Eye className="mr-2 h-4 w-4" />
698+
Enable ({selectedPackages.length})
699+
</Button>
700+
<Button
701+
variant="outline"
702+
size="sm"
703+
disabled={selectedPackages.length === 0 || isBusy}
704+
onClick={() => setIsBatchDisablingOpen(true)}
705+
>
706+
<EyeOff className="mr-2 h-4 w-4" />
707+
Disable ({selectedPackages.length})
708+
</Button>
556709
<Button
557710
variant="destructive"
558711
size="sm"
559-
disabled={selectedPackages.length === 0 || isBatchUninstalling}
712+
disabled={selectedPackages.length === 0 || isBusy}
560713
onClick={() => setIsBatchUninstallOpen(true)}
561714
>
562715
<Trash2 className="mr-2 h-4 w-4" />
563-
Uninstall Selected ({selectedPackages.length})
716+
Uninstall ({selectedPackages.length})
564717
</Button>
565718
</div>
566719
</CardHeader>

frontend/wailsjs/go/backend/App.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ export function DeleteFile(arg1:string):Promise<string>;
1212

1313
export function DeleteMultipleFiles(arg1:Array<string>):Promise<string>;
1414

15+
export function DisableMultiplePackages(arg1:Array<string>):Promise<string>;
16+
1517
export function DisablePackage(arg1:string):Promise<string>;
1618

1719
export function DisconnectWirelessAdb(arg1:string,arg2:string):Promise<string>;
1820

21+
export function EnableMultiplePackages(arg1:Array<string>):Promise<string>;
22+
1923
export function EnablePackage(arg1:string):Promise<string>;
2024

2125
export function EnableWirelessAdb(arg1:string):Promise<string>;

frontend/wailsjs/go/backend/App.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export function DeleteMultipleFiles(arg1) {
2222
return window['go']['backend']['App']['DeleteMultipleFiles'](arg1);
2323
}
2424

25+
export function DisableMultiplePackages(arg1) {
26+
return window['go']['backend']['App']['DisableMultiplePackages'](arg1);
27+
}
28+
2529
export function DisablePackage(arg1) {
2630
return window['go']['backend']['App']['DisablePackage'](arg1);
2731
}
@@ -30,6 +34,10 @@ export function DisconnectWirelessAdb(arg1, arg2) {
3034
return window['go']['backend']['App']['DisconnectWirelessAdb'](arg1, arg2);
3135
}
3236

37+
export function EnableMultiplePackages(arg1) {
38+
return window['go']['backend']['App']['EnableMultiplePackages'](arg1);
39+
}
40+
3341
export function EnablePackage(arg1) {
3442
return window['go']['backend']['App']['EnablePackage'](arg1);
3543
}

0 commit comments

Comments
 (0)