diff --git a/go.mod b/go.mod index c9f9408..652a79d 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.24.3 require ( fyne.io/fyne/v2 v2.7.1 + github.com/google/uuid v1.6.0 github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f github.com/mattn/go-mastodon v0.0.10 github.com/webview/webview_go v0.0.0-20240831120633-6173450d4dd6 diff --git a/go.sum b/go.sum index 346d7c4..f744de0 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,8 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hack-pad/go-indexeddb v0.3.2 h1:DTqeJJYc1usa45Q5r52t01KhvlSN02+Oq+tQbSBI91A= diff --git a/main.go b/main.go index afea225..19a524a 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "github.com/kirsle/configdir" "github.com/mattn/go-mastodon" + "github.com/google/uuid" webview "github.com/webview/webview_go" "encoding/json" @@ -25,6 +26,16 @@ import ( var App fyne.App var MainWindow fyne.Window +// Federale config settings apply to all profiles. +// The config stores the name of the profile to launch, +// as well as if the profile selection screen should +// show when the program is next launched. + +type FederaleConfig struct { + ProfileName string + DoNotDropToProfileSelection bool +} + type FederaleProfile struct { // Blueprint for a Federale profile Name string // Name displayed to user InternalName string // Filename @@ -42,6 +53,7 @@ type FederaleProfile struct { // Blueprint for a Federale profile } var LoadedProfile *FederaleProfile // Profile currently loaded into memory for this Federale instance +var LoadedConfig *FederaleConfig // Config currently loaded into memory var Profiles []*FederaleProfile // Profiles loaded from FS go here. var ProfileSetupDone bool = false @@ -50,8 +62,33 @@ var ProfileSetupProfile *FederaleProfile var ProfileSelectionDone bool = false var ProfileSelectionProfile *FederaleProfile +// This function saves the config in memory to disk. +func SaveConfigToDisk() error { + ConfigPath := configdir.LocalConfig("federale") // Federale foler in the user's config directory + + err := configdir.MakePath(ConfigPath) // Ensure it exists. + if err != nil { + return err + } + + ConfigFilePath := filepath.Join(ConfigPath, "federale.json") + b, err := json.MarshalIndent(LoadedConfig, "", "\t") + if err != nil { + return err + } + + log.Println("Saving configuration to disk") + + err = os.WriteFile(filepath.Join(ConfigFilePath), b, 0644) + if err != nil { + return err + } + + return nil +} + // This function asks for the profile to launch Federale with. -func ProfileLaunch() (error, *FederaleProfile) { +func ProfileLaunch() { ConfigPath := configdir.LocalConfig("federale") // Federale foler in the user's config directory err := configdir.MakePath(ConfigPath) // Ensure it exists. @@ -66,6 +103,9 @@ func ProfileLaunch() (error, *FederaleProfile) { for _, v := range Files { if !v.IsDir() { + if v.Name() == "federale.json" { + continue + } Profile := new(FederaleProfile) dat, err := os.ReadFile(filepath.Join(ConfigPath, v.Name())) if err != nil { @@ -82,10 +122,9 @@ func ProfileLaunch() (error, *FederaleProfile) { Profiles = append(Profiles, Profile) } } - - + App = app.New() - + MainWindow = App.NewWindow("Select a profile") Box := container.NewVBox() Box.Add(widget.NewRichTextFromMarkdown("# Please pick a profile")) Box.Add(widget.NewLabel(fmt.Sprintf("There are %d profile(s) available.", len(Profiles)))) @@ -131,8 +170,8 @@ func ProfileLaunch() (error, *FederaleProfile) { dialog.ShowConfirm("Confirm", "Do you have an authorisation code?", func (b bool) { if b { NewProfile := new(FederaleProfile) - NewProfile.Name = "boob" - NewProfile.InternalName = "boob123456" // TODO: Use UUID + NewProfile.Name = fmt.Sprintf("Profile %d", len(Profiles) + 1) + NewProfile.InternalName = uuid.New().String() NewProfile.Server = Domain NewProfile.ClientID = app.ClientID NewProfile.ClientSecret = app.ClientSecret @@ -182,6 +221,7 @@ func ProfileLaunch() (error, *FederaleProfile) { ) for _, v := range Profiles { + ProfileSelection.Add( container.NewHBox( widget.NewLabel(v.Name), @@ -199,19 +239,30 @@ func ProfileLaunch() (error, *FederaleProfile) { Box.Add(ProfileSelection) RootBox := container.New(layout.NewCenterLayout(), Box) - MainWindow = App.NewWindow("Please pick a profile") MainWindow.SetContent(RootBox) MainWindow.SetFixedSize(true) MainWindow.ShowAndRun() if ProfileSetupDone { // A new profile was created. Return this new profile. - return nil, ProfileSetupProfile + LoadedConfig.ProfileName = ProfileSetupProfile.InternalName + LoadedConfig.DoNotDropToProfileSelection = true + err = SaveConfigToDisk() + if err != nil { + panic(err) + } + App.SendNotification(fyne.NewNotification("Done", "Relaunch the application")) } else { // A profile was either picked from the list OR no profile was picked by the user. if ProfileSelectionDone { - return nil, ProfileSelectionProfile + LoadedConfig.ProfileName = ProfileSelectionProfile.InternalName + LoadedConfig.DoNotDropToProfileSelection = true + err = SaveConfigToDisk() + if err != nil { + panic(err) + } + App.SendNotification(fyne.NewNotification("Done", "Relaunch the application")) } else { - return errors.New("no profile specified"), new(FederaleProfile) + panic(errors.New("no profile specified")) } } } @@ -219,12 +270,78 @@ func ProfileLaunch() (error, *FederaleProfile) { func main() { - err, profile := ProfileLaunch() + + log.Println("Checking for federale config") + + ConfigPath := configdir.LocalConfig("federale") // Federale foler in the user's config directory + + err := configdir.MakePath(ConfigPath) // Ensure it exists. + log.Println("Creating federale folder if it does not exist") + if err != nil { + panic(err) + } + + log.Println("Checking if configuration file exists") + // Check if the Federale configuration file exists + _, err = os.Stat(filepath.Join(ConfigPath, "federale.json")) + if errors.Is(err, os.ErrNotExist) { + log.Println("Creating new configuration") + // Create a new configuration + EmptyConfig := new(FederaleConfig) + EmptyConfig.DoNotDropToProfileSelection = false + log.Println("Converting configuration to JSON") + b, err := json.MarshalIndent(EmptyConfig, "", "\t") + if err != nil { + panic(err) + } + + log.Println("Saving configuration to disk") + + err = os.WriteFile(filepath.Join(ConfigPath, "federale.json"), b, 0644) + if err != nil { + panic(err) + } + } else if err != nil { + panic(err) + } + + // Read the config from disk + log.Println("Grabbing config from disk") + b, err := os.ReadFile(filepath.Join(ConfigPath, "federale.json")) + // You get the gist by now if err != nil { panic(err) } - LoadedProfile = profile + log.Println("Unmarshalling JSON") + + tempconf := new(FederaleConfig) + err = json.Unmarshal(b, tempconf) + fmt.Println(tempconf) + if err != nil { + panic(err) + } + + LoadedConfig = tempconf + + if !LoadedConfig.DoNotDropToProfileSelection { + log.Println("Launching profile selection") + ProfileLaunch() + return + } + + ProfilePath := filepath.Join(ConfigPath, LoadedConfig.ProfileName + ".json") + log.Println("Reading profile from disk") + b, err = os.ReadFile(ProfilePath) + if err != nil { + panic(err) + } + log.Println("Unmarshalling config to RAM") + err = json.Unmarshal(b, LoadedConfig) + if err != nil { + return + } + ////////////////////////////////////////////////////