Rename program from federale to hashbang

This commit is contained in:
2025-11-23 15:53:00 +00:00
parent 16ede1f39c
commit 54760cb9f4
3 changed files with 51 additions and 38 deletions

View File

@@ -1,3 +1,3 @@
# Federalé # Hashbang
fediverse client for feds by feds. uses the mastodon client API fediverse client for feds by feds. uses the mastodon client API

2
go.mod
View File

@@ -1,4 +1,4 @@
module federale module hashbang
go 1.24.3 go 1.24.3

85
main.go
View File

@@ -1,3 +1,4 @@
// TODO: RENAME ALL OCCURENCES OF FEDERALE WITH HASHBANG
package main package main
import ( import (
@@ -18,6 +19,7 @@ import (
"encoding/json" "encoding/json"
"path/filepath" "path/filepath"
_ "net/http"
"context" "context"
"errors" "errors"
@@ -36,17 +38,17 @@ var Version string = "25w47a"
// Client used for posting, getting posts, etc. // Client used for posting, getting posts, etc.
var Client *mastodon.Client var Client *mastodon.Client
// Federale config settings apply to all profiles. // Hashbang config settings apply to all profiles.
// The config stores the name of the profile to launch, // The config stores the name of the profile to launch,
// as well as if the profile selection screen should // as well as if the profile selection screen should
// show when the program is next launched. // show when the program is next launched.
type FederaleConfig struct { type HashbangConfig struct {
ProfileName string ProfileName string
DoNotDropToProfileSelection bool DoNotDropToProfileSelection bool
} }
type FederaleProfile struct { // Blueprint for a Federale profile type HashbangProfile struct { // Blueprint for a Hashbang profile
Name string // Name displayed to user Name string // Name displayed to user
InternalName string // Filename InternalName string // Filename
@@ -61,29 +63,29 @@ type FederaleProfile struct { // Blueprint for a Federale profile
Running bool // Whether the profile is currently running Running bool // Whether the profile is currently running
} }
var LoadedProfile *FederaleProfile // Profile currently loaded into memory for this Federale instance var LoadedProfile *HashbangProfile // Profile currently loaded into memory for this Hashbang instance
var LoadedConfig *FederaleConfig // Config currently loaded into memory var LoadedConfig *HashbangConfig // Config currently loaded into memory
var Profiles []*FederaleProfile // Profiles loaded from FS go here. var Profiles []*HashbangProfile // Profiles loaded from FS go here.
var ProfileSetupDone bool = false var ProfileSetupDone bool = false
var ProfileSetupProfile *FederaleProfile var ProfileSetupProfile *HashbangProfile
var ProfileSelectionDone bool = false var ProfileSelectionDone bool = false
var ProfileSelectionProfile *FederaleProfile var ProfileSelectionProfile *HashbangProfile
// The visibility that the post is going to be posted with // The visibility that the post is going to be posted with
var PostVisibility string var PostVisibility string
// This function saves the config in memory to disk. // This function saves the config in memory to disk.
func SaveConfigToDisk() error { func SaveConfigToDisk() error {
ConfigPath := configdir.LocalConfig("federale") // Federale foler in the user's config directory ConfigPath := configdir.LocalConfig("hashbang") // Hashbang foler in the user's config directory
err := configdir.MakePath(ConfigPath) // Ensure it exists. err := configdir.MakePath(ConfigPath) // Ensure it exists.
if err != nil { if err != nil {
return err return err
} }
ConfigFilePath := filepath.Join(ConfigPath, "federale.json") ConfigFilePath := filepath.Join(ConfigPath, "hashbang.json")
b, err := json.MarshalIndent(LoadedConfig, "", "\t") b, err := json.MarshalIndent(LoadedConfig, "", "\t")
if err != nil { if err != nil {
return err return err
@@ -99,9 +101,9 @@ func SaveConfigToDisk() error {
return nil return nil
} }
// This function asks for the profile to launch Federale with. // This function asks for the profile to launch Hashbang with.
func ProfileLaunch() { func ProfileLaunch() {
ConfigPath := configdir.LocalConfig("federale") // Federale foler in the user's config directory ConfigPath := configdir.LocalConfig("hashbang") // Hashbang foler in the user's config directory
err := configdir.MakePath(ConfigPath) // Ensure it exists. err := configdir.MakePath(ConfigPath) // Ensure it exists.
if err != nil { if err != nil {
@@ -115,10 +117,10 @@ func ProfileLaunch() {
for _, v := range Files { for _, v := range Files {
if !v.IsDir() { if !v.IsDir() {
if v.Name() == "federale.json" { if v.Name() == "hashbang.json" {
continue continue
} }
Profile := new(FederaleProfile) Profile := new(HashbangProfile)
dat, err := os.ReadFile(filepath.Join(ConfigPath, v.Name())) dat, err := os.ReadFile(filepath.Join(ConfigPath, v.Name()))
if err != nil { if err != nil {
log.Println("ERR - " + err.Error()) log.Println("ERR - " + err.Error())
@@ -158,9 +160,9 @@ func ProfileLaunch() {
// Step one: register the application // Step one: register the application
AppConfig := &mastodon.AppConfig{ AppConfig := &mastodon.AppConfig{
Server: Domain, Server: Domain,
ClientName: "Federalé", ClientName: "Hashbang",
Scopes: "read write push", Scopes: "read write push",
Website: "https://forge.sunglocto.net", Website: "https://forge.sunglocto.net/sunglocto/Hashbang",
RedirectURIs: "urn:ietf:wg:oauth:2.0:oob", RedirectURIs: "urn:ietf:wg:oauth:2.0:oob",
} }
@@ -184,7 +186,7 @@ func ProfileLaunch() {
// Step three: get the authorization code from the user // Step three: get the authorization code from the user
dialog.ShowConfirm("Confirm", "Do you have an authorisation code?", func(b bool) { dialog.ShowConfirm("Confirm", "Do you have an authorisation code?", func(b bool) {
if b { if b {
NewProfile := new(FederaleProfile) NewProfile := new(HashbangProfile)
NewProfile.Name = fmt.Sprintf("Profile %d", len(Profiles)+1) NewProfile.Name = fmt.Sprintf("Profile %d", len(Profiles)+1)
NewProfile.InternalName = uuid.New().String() NewProfile.InternalName = uuid.New().String()
NewProfile.Server = Domain NewProfile.Server = Domain
@@ -238,7 +240,7 @@ func ProfileLaunch() {
}) })
GoButton.Importance = widget.HighImportance GoButton.Importance = widget.HighImportance
AddProfileBox.Add(widget.NewLabel("Federalé will log in via OAuth2\nInstance:")) AddProfileBox.Add(widget.NewLabel("Hashbang will log in via OAuth2\nInstance:"))
AddProfileBox.Add(InstanceEntry) AddProfileBox.Add(InstanceEntry)
AddProfileBox.Add(GoButton) AddProfileBox.Add(GoButton)
@@ -294,23 +296,23 @@ func ProfileLaunch() {
func main() { func main() {
log.Println("Checking for federale config") log.Println("Checking for hashbang config")
ConfigPath := configdir.LocalConfig("federale") // Federale foler in the user's config directory ConfigPath := configdir.LocalConfig("hashbang") // Hashbang foler in the user's config directory
err := configdir.MakePath(ConfigPath) // Ensure it exists. err := configdir.MakePath(ConfigPath) // Ensure it exists.
log.Println("Creating federale folder if it does not exist") log.Println("Creating hashbang folder if it does not exist")
if err != nil { if err != nil {
panic(err) panic(err)
} }
log.Println("Checking if configuration file exists") log.Println("Checking if configuration file exists")
// Check if the Federale configuration file exists // Check if the Hashbang configuration file exists
_, err = os.Stat(filepath.Join(ConfigPath, "federale.json")) _, err = os.Stat(filepath.Join(ConfigPath, "hashbang.json"))
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
log.Println("Creating new configuration") log.Println("Creating new configuration")
// Create a new configuration // Create a new configuration
EmptyConfig := new(FederaleConfig) EmptyConfig := new(HashbangConfig)
EmptyConfig.DoNotDropToProfileSelection = false EmptyConfig.DoNotDropToProfileSelection = false
log.Println("Converting configuration to JSON") log.Println("Converting configuration to JSON")
b, err := json.MarshalIndent(EmptyConfig, "", "\t") b, err := json.MarshalIndent(EmptyConfig, "", "\t")
@@ -320,7 +322,7 @@ func main() {
log.Println("Saving configuration to disk") log.Println("Saving configuration to disk")
err = os.WriteFile(filepath.Join(ConfigPath, "federale.json"), b, 0644) err = os.WriteFile(filepath.Join(ConfigPath, "hashbang.json"), b, 0644)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -330,7 +332,7 @@ func main() {
// Read the config from disk // Read the config from disk
log.Println("Grabbing config from disk") log.Println("Grabbing config from disk")
b, err := os.ReadFile(filepath.Join(ConfigPath, "federale.json")) b, err := os.ReadFile(filepath.Join(ConfigPath, "hashbang.json"))
// You get the gist by now // You get the gist by now
if err != nil { if err != nil {
panic(err) panic(err)
@@ -338,7 +340,7 @@ func main() {
log.Println("Unmarshalling JSON") log.Println("Unmarshalling JSON")
tempconf := new(FederaleConfig) tempconf := new(HashbangConfig)
err = json.Unmarshal(b, tempconf) err = json.Unmarshal(b, tempconf)
fmt.Println(tempconf) fmt.Println(tempconf)
if err != nil { if err != nil {
@@ -359,7 +361,7 @@ func main() {
panic(err) panic(err)
} }
tempprof := new(FederaleProfile) tempprof := new(HashbangProfile)
log.Println("Unmarshalling config to RAM") log.Println("Unmarshalling config to RAM")
err = json.Unmarshal(b, tempprof) err = json.Unmarshal(b, tempprof)
if err != nil { if err != nil {
@@ -381,11 +383,11 @@ func main() {
log.Println(Client) log.Println(Client)
App = app.New() App = app.New()
MainWindow = App.NewWindow("Federalé") MainWindow = App.NewWindow("Hashbang")
TootEntry := widget.NewMultiLineEntry() TootEntry := widget.NewMultiLineEntry()
ReplyIDEntry := widget.NewEntry() ReplyIDEntry := widget.NewEntry()
ReplyIDLabel := widget.NewLabel("In reply to") ReplyIDLabel := widget.NewLabel("In reply to")
ReplyBox := container.NewHBox(ReplyIDLabel, ReplyIDEntry) ReplyBox := container.NewGridWithColumns(2, ReplyIDLabel, ReplyIDEntry)
Timeline := container.NewGridWithColumns(4) Timeline := container.NewGridWithColumns(4)
@@ -393,7 +395,8 @@ func main() {
PostVisibility = value PostVisibility = value
}) })
go func() { ShowNotifications := func() {
Timeline.RemoveAll()
pg := new(mastodon.Pagination) pg := new(mastodon.Pagination)
//NewTimeline := container.NewVBox(widget.NewLabel("Notifications")) //NewTimeline := container.NewVBox(widget.NewLabel("Notifications"))
notis, err := Client.GetNotifications(context.Background(), pg) notis, err := Client.GetNotifications(context.Background(), pg)
@@ -408,9 +411,14 @@ func main() {
continue continue
} }
timestring := string(timeb) timestring := string(timeb)
label := widget.NewLabel(html2text.HTML2Text(v.Status.Content)) var label *widget.Label
if v.Status != nil {
label = widget.NewLabel(html2text.HTML2Text(v.Status.Content))
} else {
label = widget.NewLabel("No content set")
}
label.Truncation = fyne.TextTruncateEllipsis label.Truncation = fyne.TextTruncateEllipsis
avatar_uri := v.Account.AvatarStatic avatar_uri := v.Account.Avatar
u, err := storage.ParseURI(avatar_uri) u, err := storage.ParseURI(avatar_uri)
if err != nil { if err != nil {
continue continue
@@ -419,13 +427,18 @@ func main() {
im := canvas.NewImageFromURI(u) im := canvas.NewImageFromURI(u)
im.FillMode = canvas.ImageFillContain im.FillMode = canvas.ImageFillContain
Timeline.Add(im) fyne.Do(func(){Timeline.Add(im)
Timeline.Add(widget.NewRichTextFromMarkdown(fmt.Sprintf("%s %s your post", v.Account.Username, v.Type))) Timeline.Add(widget.NewRichTextFromMarkdown(fmt.Sprintf("%s %s your post", v.Account.Username, v.Type)))
Timeline.Add(label) Timeline.Add(label)
Timeline.Add(widget.NewLabel(timestring)) Timeline.Add(widget.NewLabel(timestring))
})
} }
//Timeline = NewTimeline //Timeline = NewTimeline
}() }
go ShowNotifications()
RefreshNotis := widget.NewButton("Refresh", ShowNotifications)
MainWindow.SetContent(container.NewHSplit(container.NewVBox(TootEntry, ReplyBox, VisibilitySelector, widget.NewButton("Post", func() { MainWindow.SetContent(container.NewHSplit(container.NewVBox(TootEntry, ReplyBox, VisibilitySelector, widget.NewButton("Post", func() {
toot := mastodon.Toot{ toot := mastodon.Toot{
@@ -438,6 +451,6 @@ func main() {
if err != nil { if err != nil {
dialog.ShowError(err, MainWindow) dialog.ShowError(err, MainWindow)
} }
})), container.NewVScroll(Timeline))) }), RefreshNotis), container.NewVScroll(Timeline)))
MainWindow.ShowAndRun() MainWindow.ShowAndRun()
} }