Skip to content

Commit cdbcd30

Browse files
committed
feat: supports configuring whether to start automatically on boot
1 parent ac46e88 commit cdbcd30

11 files changed

Lines changed: 263 additions & 2 deletions

File tree

frontend/src/biz/settings/service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Read, UpdateSettingsByPath, WriteConfig } from "~/configservice";
2+
import { UpdateAutoStart } from "~/systemservice";
23
import { RegisterShortcut, UnregisterShortcut } from "~/commonservice";
34

45
import { request } from "@/biz/requests";
@@ -60,3 +61,7 @@ export function registerShortcut(body: { shortcut: string; command: string }) {
6061
export function unregisterShortcut(body: { shortcut: string }) {
6162
return request.post(UnregisterShortcut, body);
6263
}
64+
65+
export function toggleAutoStart(body: { auto_start: boolean }) {
66+
return request.post(UpdateAutoStart, body);
67+
}

frontend/src/pages/settings/settings.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,19 @@ import { BrushCleaning, Check, Delete, File } from "lucide-solid";
66

77
import { ViewComponentProps } from "@/store/types";
88
import { useViewModel } from "@/hooks";
9-
import { Button, Input, ScrollView, Textarea } from "@/components/ui";
9+
import { Button, Checkbox, Input, ScrollView, Textarea } from "@/components/ui";
1010
import { FieldObjV2 } from "@/components/fieldv2/obj";
1111
import { FieldV2 } from "@/components/fieldv2/field";
1212

1313
import { base, Handler } from "@/domains/base";
1414
import { BizError } from "@/domains/error";
1515
import { RequestCore } from "@/domains/request";
16-
import { ButtonCore, InputCore, ScrollViewCore } from "@/domains/ui";
16+
import { ButtonCore, CheckboxCore, InputCore, ScrollViewCore } from "@/domains/ui";
1717
import { ObjectFieldCore, SingleFieldCore } from "@/domains/ui/formv2";
1818
import {
1919
fetchUserSettings,
2020
registerShortcut,
21+
toggleAutoStart,
2122
unregisterShortcut,
2223
updateUserSettings,
2324
updateUserSettingsWithPath,
@@ -33,6 +34,9 @@ function SettingsViewModel(props: ViewComponentProps) {
3334
register_shortcut: new RequestCore(registerShortcut, { client: props.client }),
3435
unregister_shortcut: new RequestCore(unregisterShortcut, { client: props.client }),
3536
},
37+
auto_start: {
38+
update: new RequestCore(toggleAutoStart, { client: props.client }),
39+
},
3640
};
3741
const methods = {
3842
refresh() {
@@ -77,6 +81,20 @@ function SettingsViewModel(props: ViewComponentProps) {
7781
}),
7882
$form_settings: new ObjectFieldCore({
7983
fields: {
84+
auto_start: new SingleFieldCore({
85+
label: "开机启动",
86+
input: new CheckboxCore({
87+
onChange() {
88+
const v = ui.$form_settings.getValueWithPath(["auto_start"]);
89+
methods.updateSettingsByPath("auto_start", {
90+
value: v,
91+
});
92+
request.auto_start.update.run({
93+
auto_start: v,
94+
});
95+
},
96+
}),
97+
}),
8098
douyin: new ObjectFieldCore({
8199
label: "抖音",
82100
fields: {
@@ -163,6 +181,11 @@ export function SettingsView(props: ViewComponentProps) {
163181
<div class="block">
164182
<div class="text-2xl text-w-fg-0">配置</div>
165183
<div class="mt-4 space-y-8">
184+
<div>
185+
<FieldV2 store={vm.ui.$form_settings.fields.auto_start}>
186+
<Checkbox store={vm.ui.$form_settings.fields.auto_start.input} />
187+
</FieldV2>
188+
</div>
166189
<div>
167190
<FieldObjV2 class="space-y-2" store={vm.ui.$form_settings.fields.douyin}>
168191
<FieldV2 store={vm.ui.$form_settings.fields.douyin.fields.cookie}>

internal/biz/settings.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type UserSettingsValue struct {
4141
RootDir string `json:"root_dir"`
4242
} `json:"webdav"`
4343
} `json:"synchronize"`
44+
AutoStart bool `json:"auto_start"` // 开机自启
4445
}
4546

4647
func NewBizConfig(dir string, filename string) *UserSettings {

internal/service/system.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"github.com/wailsapp/wails/v3/pkg/application"
66

77
"devboard/internal/biz"
8+
"devboard/pkg/autostart"
89
"devboard/pkg/system"
910
)
1011

@@ -81,3 +82,19 @@ func (s *SystemService) FetchComputeInfo() *Result {
8182
"app": app,
8283
})
8384
}
85+
86+
type UpdateAutoStartBody struct {
87+
AutoStart bool `json:"auto_start"`
88+
}
89+
90+
func (s *SystemService) UpdateAutoStart(body UpdateAutoStartBody) *Result {
91+
service := autostart.New(s.Biz.Name)
92+
if body.AutoStart {
93+
service.Enable()
94+
} else {
95+
service.Disable()
96+
}
97+
return Ok(map[string]interface{}{
98+
"auto_start": body.AutoStart,
99+
})
100+
}

main.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"devboard/internal/routes"
2525
"devboard/internal/service"
2626
"devboard/models"
27+
"devboard/pkg/autostart"
2728
"devboard/pkg/logger"
2829
"devboard/pkg/system"
2930
)
@@ -374,6 +375,19 @@ func main() {
374375
}
375376
}
376377
}()
378+
go func() {
379+
auto_start := biz.Perferences.Value.AutoStart
380+
as := autostart.New(biz.Name)
381+
if auto_start && !as.IsEnabled() {
382+
if err := as.Enable(); err != nil {
383+
fmt.Println("Failed to enable autostart:", err)
384+
}
385+
} else if !auto_start && as.IsEnabled() {
386+
if err := as.Disable(); err != nil {
387+
fmt.Println("Failed to disable autostart:", err)
388+
}
389+
}
390+
}()
377391
}()
378392
// Run the application. This blocks until the application has been exited.
379393
if err := app.Run(); err != nil {

pkg/autostart/autostart.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package autostart
2+
3+
// AutoStart provides cross-platform autostart functionality
4+
type AutoStart interface {
5+
Enable() error
6+
Disable() error
7+
IsEnabled() bool
8+
}
9+
10+
// New creates a new AutoStart instance for the current platform
11+
func New(appName string) AutoStart {
12+
return newPlatformAutoStart(appName)
13+
}

pkg/autostart/autostart_darwin.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//go:build darwin
2+
// +build darwin
3+
4+
package autostart
5+
6+
/*
7+
#cgo CFLAGS: -x objective-c
8+
#cgo LDFLAGS: -framework Foundation -framework ServiceManagement
9+
#include "autostart_darwin.h"
10+
*/
11+
import "C"
12+
import "fmt"
13+
14+
type darwinAutoStart struct {
15+
appName string
16+
}
17+
18+
func newPlatformAutoStart(appName string) AutoStart {
19+
return &darwinAutoStart{appName: appName}
20+
}
21+
22+
func (a *darwinAutoStart) Enable() error {
23+
result := C.enableLoginItem()
24+
if result == 0 {
25+
return fmt.Errorf("failed to enable login item")
26+
}
27+
return nil
28+
}
29+
30+
func (a *darwinAutoStart) Disable() error {
31+
result := C.disableLoginItem()
32+
if result == 0 {
33+
return fmt.Errorf("failed to disable login item")
34+
}
35+
return nil
36+
}
37+
38+
func (a *darwinAutoStart) IsEnabled() bool {
39+
result := C.isLoginItemEnabled()
40+
return result == 1
41+
}

pkg/autostart/autostart_darwin.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef AUTOSTART_DARWIN_H
2+
#define AUTOSTART_DARWIN_H
3+
4+
int enableLoginItem();
5+
int disableLoginItem();
6+
int isLoginItemEnabled();
7+
8+
#endif

pkg/autostart/autostart_darwin.m

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#import <Foundation/Foundation.h>
2+
#import <ServiceManagement/ServiceManagement.h>
3+
#import "autostart_darwin.h"
4+
5+
int enableLoginItem() {
6+
if (@available(macOS 13.0, *)) {
7+
SMAppService *service = [SMAppService mainAppService];
8+
NSError *error = nil;
9+
BOOL success = [service registerAndReturnError:&error];
10+
if (!success) {
11+
NSLog(@"Failed to register login item: %@", error);
12+
return 0;
13+
}
14+
return 1;
15+
} else {
16+
// For macOS 12 and earlier, we'd need to use SMLoginItemSetEnabled
17+
// For simplicity, we'll return failure on older macOS
18+
NSLog(@"Login items require macOS 13 or later");
19+
return 0;
20+
}
21+
}
22+
23+
int disableLoginItem() {
24+
if (@available(macOS 13.0, *)) {
25+
SMAppService *service = [SMAppService mainAppService];
26+
NSError *error = nil;
27+
BOOL success = [service unregisterAndReturnError:&error];
28+
if (!success) {
29+
NSLog(@"Failed to unregister login item: %@", error);
30+
return 0;
31+
}
32+
return 1;
33+
} else {
34+
return 0;
35+
}
36+
}
37+
38+
int isLoginItemEnabled() {
39+
if (@available(macOS 13.0, *)) {
40+
SMAppService *service = [SMAppService mainAppService];
41+
SMAppServiceStatus status = service.status;
42+
return (status == SMAppServiceStatusEnabled) ? 1 : 0;
43+
} else {
44+
return 0;
45+
}
46+
}

pkg/autostart/autostart_other.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//go:build !darwin && !windows
2+
// +build !darwin,!windows
3+
4+
package autostart
5+
6+
import "fmt"
7+
8+
type stubAutoStart struct {
9+
appName string
10+
}
11+
12+
func newPlatformAutoStart(appName string) AutoStart {
13+
return &stubAutoStart{appName: appName}
14+
}
15+
16+
func (a *stubAutoStart) Enable() error {
17+
return fmt.Errorf("autostart not supported on this platform")
18+
}
19+
20+
func (a *stubAutoStart) Disable() error {
21+
return fmt.Errorf("autostart not supported on this platform")
22+
}
23+
24+
func (a *stubAutoStart) IsEnabled() bool {
25+
return false
26+
}

0 commit comments

Comments
 (0)