Files
lmvpn_client/internal/ui/profile.go
T
2026-07-06 16:21:06 +08:00

135 lines
3.7 KiB
Go

package ui
import (
"strconv"
"lmvpn/internal/model"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/widget"
)
// showProfileDialog displays an add/edit dialog for a server profile.
// If editing is nil, a new profile is created.
func (a *App) showProfileDialog(editing *model.ServerProfile) {
isNew := editing == nil
nameEntry := widget.NewEntry()
serverEntry := widget.NewEntry()
userEntry := widget.NewEntry()
passEntry := widget.NewPasswordEntry()
authSelect := widget.NewSelect([]string{"both", "jwt", "password"}, nil)
routeSelect := widget.NewSelect([]string{"full", "split", "custom"}, nil)
cidrEntry := widget.NewMultiLineEntry()
cidrEntry.SetPlaceHolder("10.0.0.0/8, 172.16.0.0/12")
mtuEntry := widget.NewEntry()
mtuEntry.SetPlaceHolder("0 = use server MTU")
if !isNew {
nameEntry.SetText(editing.Name)
serverEntry.SetText(editing.ServerURL)
userEntry.SetText(editing.Username)
authSelect.SetSelected(string(editing.AuthMode))
routeSelect.SetSelected(string(editing.RoutingMode))
cidrEntry.SetText(editing.CustomCIDRs)
mtuEntry.SetText(fmtInt(editing.MTUOverride))
passEntry.SetPlaceHolder("(unchanged)")
} else {
authSelect.SetSelected(string(model.AuthModeBoth))
routeSelect.SetSelected(string(model.RoutingFull))
mtuEntry.SetText("0")
}
form := container.NewVBox(
widget.NewLabel("Name"), nameEntry,
widget.NewLabel("Server URL"), serverEntry,
widget.NewLabel("Username"), userEntry,
widget.NewLabel("Password"), passEntry,
widget.NewLabel("Auth Mode"), authSelect,
widget.NewLabel("Routing Mode"), routeSelect,
widget.NewLabel("Custom CIDRs (comma-separated)"), cidrEntry,
widget.NewLabel("MTU Override"), mtuEntry,
)
d := dialog.NewCustomConfirm("Profile", "Save", "Cancel", form, func(save bool) {
if !save {
return
}
a.saveProfile(editing, nameEntry.Text, serverEntry.Text,
userEntry.Text, passEntry.Text,
authSelect.Selected, routeSelect.Selected,
cidrEntry.Text, mtuEntry.Text, isNew)
}, a.window)
d.Resize(fyne.NewSize(400, 500))
d.Show()
}
// saveProfile creates or updates a profile and stores credentials.
func (a *App) saveProfile(editing *model.ServerProfile,
name, server, user, password, authMode, routeMode, cidrs, mtuStr string, isNew bool) {
if name == "" || server == "" || user == "" {
showError("Validation", "Name, Server URL, and Username are required.", a.window)
return
}
mtu := parseIntDefault(mtuStr, 0)
if isNew {
p := &model.ServerProfile{
Name: name,
ServerURL: server,
Username: user,
AuthMode: model.AuthMode(authMode),
RoutingMode: model.RoutingMode(routeMode),
CustomCIDRs: cidrs,
MTUOverride: mtu,
}
id, err := a.db.CreateProfile(p)
if err != nil {
showError("Save Error", err.Error(), a.window)
return
}
_ = id
if password != "" {
if err := a.kc.SetPassword(name, password); err != nil {
showError("Keychain Error", err.Error(), a.window)
}
}
} else {
oldName := editing.Name
editing.Name = name
editing.ServerURL = server
editing.Username = user
editing.AuthMode = model.AuthMode(authMode)
editing.RoutingMode = model.RoutingMode(routeMode)
editing.CustomCIDRs = cidrs
editing.MTUOverride = mtu
if err := a.db.UpdateProfile(editing); err != nil {
showError("Save Error", err.Error(), a.window)
return
}
if password != "" {
_ = a.kc.DeleteAll(oldName)
if err := a.kc.SetPassword(name, password); err != nil {
showError("Keychain Error", err.Error(), a.window)
}
}
}
a.loadProfiles()
}
func fmtInt(n int) string {
return strconv.Itoa(n)
}
func parseIntDefault(s string, def int) int {
n, err := strconv.Atoi(s)
if err != nil {
return def
}
return n
}