diff --git a/hamy-vpn-client-test.exe b/hamy-vpn-client-test.exe new file mode 100644 index 0000000..a659460 Binary files /dev/null and b/hamy-vpn-client-test.exe differ diff --git a/main.go b/main.go index a93e822..bf74297 100644 --- a/main.go +++ b/main.go @@ -38,6 +38,7 @@ var ( currentProcess *exec.Cmd configs []Config // Store all configurations activeConfig int // Index of the active config (-1 if none) + configFilePath string = "configs.json" // Path to save/load configs ) // checkSingBox checks if sing-box.exe exists in the bin folder @@ -49,6 +50,40 @@ func checkSingBox() bool { return true } +// loadConfigs loads configurations from file at startup +func loadConfigs() error { + data, err := os.ReadFile(configFilePath) + if err != nil { + // If file doesn't exist, it's not an error - just start with empty configs + if os.IsNotExist(err) { + return nil + } + return err + } + + err = json.Unmarshal(data, &configs) + if err != nil { + return err + } + + return nil +} + +// saveConfigs saves configurations to file +func saveConfigs() error { + data, err := json.MarshalIndent(configs, "", " ") + if err != nil { + return err + } + + err = os.WriteFile(configFilePath, data, 0644) + if err != nil { + return err + } + + return nil +} + // isValidVLESS checks if the given URL is a valid VLESS URL func isValidVLESS(vlessURL string) bool { // Basic validation for VLESS URL format @@ -74,6 +109,9 @@ func isValidVLESS(vlessURL string) bool { // addConfig adds a new configuration to the list func addConfig(title, url string) { configs = append(configs, Config{Title: title, URL: url}) + + // Save configurations to file + saveConfigs() } // updateConfig updates an existing configuration @@ -81,6 +119,9 @@ func updateConfig(index int, title, url string) { if index >= 0 && index < len(configs) { configs[index].Title = title configs[index].URL = url + + // Save configurations to file + saveConfigs() } } @@ -94,6 +135,9 @@ func removeConfig(index int) { if activeConfig >= len(configs) { activeConfig = -1 } + + // Save configurations to file + saveConfigs() } } @@ -491,6 +535,9 @@ func main() { // Set the window size to 200x300 as requested myWindow.Resize(fyne.NewSize(200, 300)) + // Load configurations from file at startup + loadConfigs() + // Initialize active config to -1 (no config selected) activeConfig = -1 @@ -599,10 +646,12 @@ func main() { statusLabel.Refresh() }) connectButton.Importance = widget.HighImportance + + // Initially disable the button if no configs are available if len(configs) == 0 { - connectButton.Disable() // Disable initially until a config is selected + connectButton.Disable() } else { - connectButton.Enable() // Enable if we have configs + connectButton.Enable() } // Configurations button - opens a separate window @@ -632,6 +681,11 @@ func main() { // Refresh the list refreshList() importEntry.SetText("") + + // Enable connect button if we have configs + if len(configs) > 0 { + connectButton.Enable() + } } else if url != "" { dialog.ShowError(errors.New("Невалидная ссылка"), configWindow) } @@ -688,6 +742,11 @@ func main() { // Refresh the list refreshList() + + // Disable connect button if no configs remain or current config was deleted + if len(configs) == 0 || activeConfig == -1 { + connectButton.Disable() + } } }, configWindow) @@ -698,6 +757,10 @@ func main() { newListContainer.OnSelected = func(id widget.ListItemID) { activeConfig = id dialog.ShowInformation("Config Selected", fmt.Sprintf("Active config: %s", configs[id].Title), configWindow) + + // Enable the connect button since a config is selected + connectButton.Enable() + configWindow.Close() }