Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
6c3195b029 | |||
5b5d4656aa | |||
![]() |
3afa1e7e38 | ||
ece04e1c36 | |||
52e38e7e66 | |||
59d83cb185 | |||
4015107de0 | |||
150f42bc58 | |||
3d6f835d4f | |||
922bc1d7cf | |||
a61d3090e1 | |||
215839d833 | |||
d7264e91f7 | |||
![]() |
93d3bb20d2 | ||
181b91edb4 | |||
ca6bda7950 |
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@@ -30,5 +30,5 @@ jobs:
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pi-binary
|
||||
path: pi
|
||||
path: pi-im
|
||||
|
||||
|
10
README.md
10
README.md
@@ -1,10 +1,10 @@
|
||||
<center>
|
||||
<img src="https://github.com/sunglocto/pi/blob/255bc3749c089e3945871ddf19dd17d14a83f9ff/pi.png">
|
||||
<img width="100" height="100" src="https://github.com/sunglocto/pi/blob/255bc3749c089e3945871ddf19dd17d14a83f9ff/pi.png">
|
||||
</center>
|
||||
|
||||
# π
|
||||
[](https://github.com/sunglocto/pi/actions/workflows/go.yml)
|
||||
<img width="1050" height="632" alt="image" src="https://github.com/user-attachments/assets/a5a3a7ab-8a85-49f0-81e9-ae5b977e7455" />
|
||||
<img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/9e2d9209-6ad5-4f22-94d0-4cc18c835372" />
|
||||
|
||||
|
||||
## the XMPP client from hell
|
||||
> it's 10% code. 20% ai
|
||||
@@ -90,6 +90,10 @@ From fellow insane and schizophrenic XMPP users:
|
||||
|
||||
> pi devstream when
|
||||
|
||||
<img width="361" height="66" alt="image" src="https://github.com/user-attachments/assets/5a926f6b-1005-4795-a6ef-4e0538bb4d5a" />
|
||||
<img width="316" height="73" alt="image" src="https://github.com/user-attachments/assets/52309c60-8110-43eb-9c45-56c9cfd82cc4" />
|
||||
|
||||
|
||||
## επιπλέον
|
||||
(extra)
|
||||
|
||||
|
3
go.mod
3
go.mod
@@ -1,10 +1,11 @@
|
||||
module pi
|
||||
module pi-im
|
||||
|
||||
go 1.24.5
|
||||
|
||||
require (
|
||||
fyne.io/fyne/v2 v2.6.2
|
||||
fyne.io/x/fyne v0.0.0-20250418202416-58a230ad1acb
|
||||
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d
|
||||
mellium.im/xmpp v0.22.0
|
||||
pain.agency/oasis-sdk v0.0.0-20250805052243-df6be3f9f629
|
||||
)
|
||||
|
2
go.sum
2
go.sum
@@ -58,6 +58,8 @@ github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d h1:l3+2LWCbVxn5itfvXAfH9n4YL9jh8l1g5zcncbIc1cs=
|
||||
github.com/rrivera/identicon v0.0.0-20240116195454-d5ba35832c0d/go.mod h1:TbpErkob6SY7cyozRVSGoB3OlO2qOAgVN8O3KAJ4fMI=
|
||||
github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU=
|
||||
github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
|
||||
|
369
main.go
369
main.go
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -20,6 +21,7 @@ import (
|
||||
"fyne.io/fyne/v2/storage"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/rrivera/identicon"
|
||||
|
||||
// xmpp - required
|
||||
"mellium.im/xmpp/disco"
|
||||
@@ -33,7 +35,7 @@ import (
|
||||
// TODO: integrated theme switcher
|
||||
)
|
||||
|
||||
var version string = "3.1a"
|
||||
var version string = "3.14a"
|
||||
var statBar widget.Label
|
||||
var chatInfo fyne.Container
|
||||
var chatSidebar fyne.Container
|
||||
@@ -42,21 +44,28 @@ var chatSidebar fyne.Container
|
||||
// license AGPL
|
||||
|
||||
type Message struct {
|
||||
Author string
|
||||
Content string
|
||||
ID string
|
||||
ReplyID string
|
||||
ImageURL string
|
||||
Raw oasisSdk.XMPPChatMessage
|
||||
Author string
|
||||
Content string
|
||||
ID string
|
||||
ReplyID string
|
||||
ImageURL string
|
||||
Raw oasisSdk.XMPPChatMessage
|
||||
Important bool
|
||||
}
|
||||
|
||||
type MucTab struct {
|
||||
Jid jid.JID
|
||||
Nick string
|
||||
Messages []Message
|
||||
Scroller *widget.List
|
||||
isMuc bool
|
||||
Muc *muc.Channel
|
||||
type ChatTab struct {
|
||||
Jid jid.JID
|
||||
Nick string
|
||||
Messages []Message
|
||||
isMuc bool
|
||||
Muc *muc.Channel
|
||||
UpdateSidebar bool
|
||||
}
|
||||
|
||||
type ChatTabUI struct {
|
||||
Internal *ChatTab
|
||||
Scroller *widget.List `xml:"-"`
|
||||
Sidebar *fyne.Container `xml:"-"`
|
||||
}
|
||||
|
||||
type piConfig struct {
|
||||
@@ -69,8 +78,10 @@ var config piConfig
|
||||
var login oasisSdk.LoginInfo
|
||||
var DMs []string
|
||||
|
||||
var chatTabs = make(map[string]*MucTab)
|
||||
var tabs *container.AppTabs
|
||||
var chatTabs = make(map[string]*ChatTab)
|
||||
var UITabs = make(map[string]*ChatTabUI)
|
||||
|
||||
var AppTabs *container.AppTabs
|
||||
var selectedId widget.ListItemID
|
||||
var replying bool = false
|
||||
var notifications bool
|
||||
@@ -101,54 +112,62 @@ var scrollDownOnNewMessage bool = true
|
||||
var w fyne.Window
|
||||
var a fyne.App
|
||||
|
||||
func addChatTab(isMuc bool, chatJid jid.JID, nick string) {
|
||||
mucJidStr := chatJid.String()
|
||||
if _, ok := chatTabs[mucJidStr]; ok {
|
||||
// Tab already exists
|
||||
return
|
||||
}
|
||||
|
||||
tabData := &MucTab{
|
||||
Jid: chatJid,
|
||||
Nick: nick,
|
||||
Messages: []Message{},
|
||||
isMuc: isMuc,
|
||||
}
|
||||
|
||||
func CreateUITab(chatJidStr string) ChatTabUI {
|
||||
var scroller *widget.List
|
||||
scroller = widget.NewList(
|
||||
func() int {
|
||||
return len(tabData.Messages)
|
||||
return len(chatTabs[chatJidStr].Messages)
|
||||
},
|
||||
func() fyne.CanvasObject {
|
||||
gen, _ := identicon.New("github", 5, 3)
|
||||
ii, _ := gen.Draw("default")
|
||||
im := ii.Image(25)
|
||||
ico := canvas.NewImageFromImage(im)
|
||||
ico.FillMode = canvas.ImageFillOriginal
|
||||
author := widget.NewLabel("author")
|
||||
author.TextStyle.Bold = true
|
||||
content := widget.NewRichTextWithText("content")
|
||||
content := widget.NewLabel("content")
|
||||
content.Wrapping = fyne.TextWrapWord
|
||||
content.Selectable = true
|
||||
icon := theme.FileVideoIcon()
|
||||
btn := widget.NewButtonWithIcon("View media", icon, func() {
|
||||
|
||||
})
|
||||
return container.NewVBox(author, content, btn)
|
||||
return container.NewVBox(container.NewHBox(ico, author), content, btn)
|
||||
},
|
||||
func(i widget.ListItemID, co fyne.CanvasObject) {
|
||||
vbox := co.(*fyne.Container)
|
||||
author := vbox.Objects[0].(*widget.Label)
|
||||
content := vbox.Objects[1].(*widget.RichText)
|
||||
authorBox := vbox.Objects[0].(*fyne.Container)
|
||||
// generate a Icon
|
||||
|
||||
gen, _ := identicon.New("github", 5, 3)
|
||||
ii, _ := gen.Draw(chatTabs[chatJidStr].Messages[i].Author)
|
||||
im := ii.Image(25)
|
||||
authorBox.Objects[0] = canvas.NewImageFromImage(im)
|
||||
authorBox.Objects[0].(*canvas.Image).FillMode = canvas.ImageFillOriginal
|
||||
authorBox.Objects[0].Refresh()
|
||||
|
||||
// Icon generate end
|
||||
|
||||
author := authorBox.Objects[1].(*widget.Label)
|
||||
content := vbox.Objects[1].(*widget.Label)
|
||||
btn := vbox.Objects[2].(*widget.Button)
|
||||
if chatTabs[chatJidStr].Messages[i].Important {
|
||||
//content.Importance = widget.DangerImportance TODO: Fix highlighting messages with mentions, it's currently broken
|
||||
}
|
||||
btn.Hidden = true // Hide by default
|
||||
msgContent := tabData.Messages[i].Content
|
||||
if tabData.Messages[i].ImageURL != "" {
|
||||
msgContent := chatTabs[chatJidStr].Messages[i].Content
|
||||
if chatTabs[chatJidStr].Messages[i].ImageURL != "" {
|
||||
btn.Hidden = false
|
||||
btn.OnTapped = func() {
|
||||
fyne.Do(func() {
|
||||
u, err := storage.ParseURI(tabData.Messages[i].ImageURL)
|
||||
u, err := storage.ParseURI(chatTabs[chatJidStr].Messages[i].ImageURL)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
if strings.HasSuffix(tabData.Messages[i].ImageURL, "mp4") {
|
||||
url, err := url.Parse(tabData.Messages[i].ImageURL)
|
||||
if strings.HasSuffix(chatTabs[chatJidStr].Messages[i].ImageURL, "mp4") || strings.HasSuffix(chatTabs[chatJidStr].Messages[i].ImageURL, "mp3") {
|
||||
url, err := url.Parse(chatTabs[chatJidStr].Messages[i].ImageURL)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
@@ -171,27 +190,67 @@ func addChatTab(isMuc bool, chatJid jid.JID, nick string) {
|
||||
}
|
||||
msgContent = strings.Join(lines, "\n")
|
||||
|
||||
content.ParseMarkdown(msgContent)
|
||||
if tabData.Messages[i].ReplyID != "PICLIENT:UNAVAILABLE" {
|
||||
author.SetText(fmt.Sprintf("%s > %s", tabData.Messages[i].Author, jid.MustParse(tabData.Messages[i].Raw.Reply.To).Resourcepart()))
|
||||
//content.ParseMarkdown(msgContent)
|
||||
content.SetText(msgContent)
|
||||
if chatTabs[chatJidStr].Messages[i].ReplyID != "PICLIENT:UNAVAILABLE" {
|
||||
author.SetText(fmt.Sprintf("%s > %s", chatTabs[chatJidStr].Messages[i].Author, jid.MustParse(chatTabs[chatJidStr].Messages[i].Raw.Reply.To).Resourcepart()))
|
||||
} else {
|
||||
author.SetText(tabData.Messages[i].Author)
|
||||
author.SetText(chatTabs[chatJidStr].Messages[i].Author)
|
||||
}
|
||||
|
||||
|
||||
if strings.Split(msgContent," ")[0] == "/me" {
|
||||
sl := strings.Split(msgContent, " ")
|
||||
sl[0] = ""
|
||||
author.SetText(author.Text + strings.Join(sl, " "))
|
||||
content.SetText(" ")
|
||||
}
|
||||
|
||||
scroller.SetItemHeight(i, vbox.MinSize().Height)
|
||||
},
|
||||
)
|
||||
|
||||
scroller.OnSelected = func(id widget.ListItemID) {
|
||||
selectedId = id
|
||||
}
|
||||
|
||||
myUITab := ChatTabUI{}
|
||||
|
||||
scroller.CreateItem()
|
||||
myUITab.Scroller = scroller
|
||||
gen, _ := identicon.New("github", 50, 20)
|
||||
ii, _ := gen.Draw(chatJidStr)
|
||||
im := ii.Image(250)
|
||||
imw := canvas.NewImageFromImage(im)
|
||||
imw.FillMode = canvas.ImageFillOriginal
|
||||
myUITab.Sidebar = container.NewVBox(imw)
|
||||
|
||||
tabData.Scroller = scroller
|
||||
return myUITab
|
||||
}
|
||||
func addChatTab(isMuc bool, chatJid jid.JID, nick string) {
|
||||
|
||||
chatTabs[mucJidStr] = tabData
|
||||
chatJidStr := chatJid.String()
|
||||
if _, ok := chatTabs[chatJidStr]; ok {
|
||||
// Tab already exists
|
||||
return
|
||||
}
|
||||
|
||||
tabItem := container.NewTabItem(chatJid.Localpart(), scroller)
|
||||
tabs.Append(tabItem)
|
||||
myChatTab := ChatTab{
|
||||
Jid: chatJid,
|
||||
Nick: nick,
|
||||
Messages: []Message{},
|
||||
isMuc: isMuc,
|
||||
}
|
||||
|
||||
myUITab := CreateUITab(chatJid.String())
|
||||
myUITab.Internal = &myChatTab
|
||||
|
||||
chatTabs[chatJidStr] = &myChatTab
|
||||
UITabs[chatJidStr] = &myUITab
|
||||
|
||||
fyne.Do(func() {
|
||||
AppTabs.Append(container.NewTabItem(chatJid.String(), myUITab.Scroller))
|
||||
})
|
||||
}
|
||||
|
||||
func dropToSignInPage(reason string) {
|
||||
@@ -227,8 +286,7 @@ func dropToSignInPage(reason string) {
|
||||
config.Login.User = userEntry.Text
|
||||
config.Login.Password = passwordEntry.Text
|
||||
config.Login.DisplayName = nicknameEntry.Text
|
||||
config.Notifications = true
|
||||
config.Login.MucsToJoin = append(config.Login.MucsToJoin, "ringen@muc.isekai.rocks") // DEBUG
|
||||
config.Notifications = false
|
||||
|
||||
bytes, err := xml.MarshalIndent(config, "", "\t")
|
||||
if err != nil {
|
||||
@@ -263,8 +321,9 @@ func dropToSignInPage(reason string) {
|
||||
|
||||
func main() {
|
||||
muc.Since(time.Now())
|
||||
|
||||
config = piConfig{}
|
||||
a = app.NewWithID("pi-ism")
|
||||
a = app.NewWithID("pi-im")
|
||||
reader, err := a.Storage().Open("pi.xml")
|
||||
if err != nil {
|
||||
dropToSignInPage(err.Error())
|
||||
@@ -305,10 +364,9 @@ func main() {
|
||||
lines := strings.Split(str, "\n")
|
||||
for i, line := range lines {
|
||||
s := strings.Split(line, " ")
|
||||
for j, v := range s {
|
||||
for _, v := range s {
|
||||
_, err := url.Parse(v)
|
||||
if err == nil && strings.HasPrefix(v, "https://") {
|
||||
s[j] = fmt.Sprintf("[%s](%s)", v, v)
|
||||
if strings.HasSuffix(v, ".png") || strings.HasSuffix(v, ".jpg") || strings.HasSuffix(v, ".jpeg") || strings.HasSuffix(v, ".webp") || strings.HasSuffix(v, ".mp4") {
|
||||
img = v
|
||||
}
|
||||
@@ -335,9 +393,9 @@ func main() {
|
||||
|
||||
tab.Messages = append(tab.Messages, myMessage)
|
||||
fyne.Do(func() {
|
||||
tab.Scroller.Refresh()
|
||||
UITabs[userJidStr].Scroller.Refresh()
|
||||
if scrollDownOnNewMessage {
|
||||
tab.Scroller.ScrollToBottom()
|
||||
UITabs[userJidStr].Scroller.ScrollToBottom()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -346,6 +404,7 @@ func main() {
|
||||
// HACK: IGNORING ALL MESSAGES FROM CLASSIC MUC HISTORY IN PREPARATION OF MAM SUPPORT
|
||||
ignore := false
|
||||
correction := false
|
||||
important := false
|
||||
for _, v := range msg.Unknown {
|
||||
if v.XMLName.Local == "delay" { // CLasic history message
|
||||
//ignore = true
|
||||
@@ -364,8 +423,12 @@ func main() {
|
||||
if tab, ok := chatTabs[mucJidStr]; ok {
|
||||
chatTabs[mucJidStr].Muc = muc
|
||||
str := *msg.CleanedBody
|
||||
if strings.Contains(str, login.DisplayName) {
|
||||
fmt.Println(str)
|
||||
important = true
|
||||
}
|
||||
if !ignore && notifications {
|
||||
if !correction && strings.Contains(str, login.DisplayName) || (msg.Reply != nil && strings.Contains(msg.Reply.To, login.DisplayName)) {
|
||||
if !correction && msg.From.String() != client.JID.String() && strings.Contains(str, login.DisplayName) || (msg.Reply != nil && strings.Contains(msg.Reply.To, login.DisplayName)) {
|
||||
a.SendNotification(fyne.NewNotification(fmt.Sprintf("Mentioned in %s", mucJidStr), str))
|
||||
}
|
||||
}
|
||||
@@ -373,11 +436,10 @@ func main() {
|
||||
lines := strings.Split(str, "\n")
|
||||
for i, line := range lines {
|
||||
s := strings.Split(line, " ")
|
||||
for j, v := range s {
|
||||
for _, v := range s {
|
||||
_, err := url.Parse(v)
|
||||
if err == nil && strings.HasPrefix(v, "https://") {
|
||||
s[j] = fmt.Sprintf("[%s](%s)", v, v)
|
||||
if strings.HasSuffix(v, ".png") || strings.HasSuffix(v, ".jpg") || strings.HasSuffix(v, ".jpeg") || strings.HasSuffix(v, ".webp") || strings.HasSuffix(v, ".mp4") {
|
||||
if strings.HasSuffix(v, ".png") || strings.HasSuffix(v, ".jpg") || strings.HasSuffix(v, ".jpeg") || strings.HasSuffix(v, ".webp") || strings.HasSuffix(v, ".mp4") || strings.HasSuffix(v, ".mp3") {
|
||||
ImageID = v
|
||||
}
|
||||
}
|
||||
@@ -396,11 +458,11 @@ func main() {
|
||||
}
|
||||
|
||||
if correction {
|
||||
for i := len(tab.Messages)-1; i > 0; i-- {
|
||||
for i := len(tab.Messages) - 1; i > 0; i-- {
|
||||
if tab.Messages[i].Raw.From.String() == msg.From.String() {
|
||||
tab.Messages[i].Content = *msg.CleanedBody + " (edited)"
|
||||
fyne.Do(func() {
|
||||
tab.Scroller.Refresh()
|
||||
UITabs[mucJidStr].Scroller.Refresh()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -408,20 +470,21 @@ func main() {
|
||||
}
|
||||
|
||||
myMessage := Message{
|
||||
Author: msg.From.Resourcepart(),
|
||||
Content: str,
|
||||
ID: msg.ID,
|
||||
ReplyID: replyID,
|
||||
Raw: *msg,
|
||||
ImageURL: ImageID,
|
||||
Author: msg.From.Resourcepart(),
|
||||
Content: str,
|
||||
ID: msg.ID,
|
||||
ReplyID: replyID,
|
||||
Raw: *msg,
|
||||
ImageURL: ImageID,
|
||||
Important: important,
|
||||
}
|
||||
if !ignore {
|
||||
tab.Messages = append(tab.Messages, myMessage)
|
||||
}
|
||||
fyne.Do(func() {
|
||||
tab.Scroller.Refresh()
|
||||
UITabs[mucJidStr].Scroller.Refresh()
|
||||
if scrollDownOnNewMessage {
|
||||
tab.Scroller.ScrollToBottom()
|
||||
UITabs[mucJidStr].Scroller.ScrollToBottom()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -447,7 +510,7 @@ func main() {
|
||||
})
|
||||
default:
|
||||
fyne.Do(func() {
|
||||
statBar.SetText(fmt.Sprint("Unknown state: ", state))
|
||||
statBar.SetText("")
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -462,29 +525,6 @@ func main() {
|
||||
log.Fatalln("Could not create client - " + err.Error())
|
||||
}
|
||||
|
||||
/*
|
||||
client.Session.Serve(xmpp.HandlerFunc(func(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
|
||||
d := xml.NewTokenDecoder(t)
|
||||
|
||||
// Ignore anything that's not a message.
|
||||
if start.Name.Local != "message" {
|
||||
return nil
|
||||
}
|
||||
|
||||
msg := struct {
|
||||
stanza.Message
|
||||
Body string `xml:"body"`
|
||||
}{}
|
||||
err := d.DecodeElement(&msg, start)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if msg.Body != "" {
|
||||
log.Println("Got message: %q", msg.Body)
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
*/
|
||||
go func() {
|
||||
for connection {
|
||||
err = client.Connect()
|
||||
@@ -514,21 +554,21 @@ func main() {
|
||||
|
||||
SendCallback := func() {
|
||||
text := entry.Text
|
||||
if tabs.Selected() == nil || tabs.Selected().Content == nil {
|
||||
if AppTabs.Selected() == nil || AppTabs.Selected().Content == nil || text == "" {
|
||||
return
|
||||
}
|
||||
|
||||
selectedScroller, ok := tabs.Selected().Content.(*widget.List)
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var activeMucJid string
|
||||
var isMuc bool
|
||||
for jid, tabData := range chatTabs {
|
||||
for jid, tabData := range UITabs {
|
||||
if tabData.Scroller == selectedScroller {
|
||||
activeMucJid = jid
|
||||
isMuc = tabData.isMuc
|
||||
isMuc = chatTabs[activeMucJid].isMuc
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -540,11 +580,23 @@ func main() {
|
||||
go func() {
|
||||
if replying {
|
||||
m := chatTabs[activeMucJid].Messages[selectedId].Raw
|
||||
client.ReplyToEvent(&m, text)
|
||||
err = client.ReplyToEvent(&m, text)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
url, uerr := url.Parse(strings.Split(text, " ")[0])
|
||||
if uerr == nil && strings.HasPrefix(strings.Split(text, " ")[0], "https://") {
|
||||
err = client.SendImage(jid.MustParse(activeMucJid).Bare(), text, url.String(), &text)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
return
|
||||
}
|
||||
err = client.SendText(jid.MustParse(activeMucJid).Bare(), text)
|
||||
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
@@ -558,7 +610,7 @@ func main() {
|
||||
})
|
||||
fyne.Do(func() {
|
||||
if scrollDownOnNewMessage {
|
||||
chatTabs[activeMucJid].Scroller.ScrollToBottom()
|
||||
UITabs[activeMucJid].Scroller.ScrollToBottom()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -614,7 +666,7 @@ func main() {
|
||||
})
|
||||
|
||||
jtb := fyne.NewMenuItem("jump to bottom", func() {
|
||||
selectedScroller, ok := tabs.Selected().Content.(*widget.List)
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -622,7 +674,7 @@ func main() {
|
||||
})
|
||||
|
||||
jtt := fyne.NewMenuItem("jump to top", func() {
|
||||
selectedScroller, ok := tabs.Selected().Content.(*widget.List)
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -663,9 +715,9 @@ func main() {
|
||||
|
||||
})
|
||||
|
||||
deb := fyne.NewMenuItem("DEBUG: Attempt to get MAM history from a user", func() {
|
||||
//res, err := history.Fetch(client.Ctx, history.Query{}, jid.MustParse("ringen@muc.isekai.rocks"), client.Session)
|
||||
})
|
||||
//deb := fyne.NewMenuItem("DEBUG: Attempt to get MAM history from a user", func() {
|
||||
//res, err := history.Fetch(client.Ctx, history.Query{}, jid.MustParse("ringen@muc.isekai.rocks"), client.Session)
|
||||
//})
|
||||
mic := fyne.NewMenuItem("upload a file", func() {
|
||||
var link string
|
||||
var toperr error
|
||||
@@ -691,7 +743,9 @@ func main() {
|
||||
progress := make(chan oasisSdk.UploadProgress)
|
||||
myprogressbar := widget.NewProgressBar()
|
||||
diag := dialog.NewCustom("Uploading file", "Hide", myprogressbar, w)
|
||||
diag.Show()
|
||||
fyne.Do(func() {
|
||||
diag.Show()
|
||||
})
|
||||
go func() {
|
||||
client.UploadFile(client.Ctx, reader.URI().Path(), progress)
|
||||
}()
|
||||
@@ -721,32 +775,72 @@ func main() {
|
||||
}, w)
|
||||
})
|
||||
|
||||
servDisc := fyne.NewMenuItem("Service discovery", func() {
|
||||
servDisc := fyne.NewMenuItem("Disco features", func() {
|
||||
var search jid.JID
|
||||
dialog.ShowEntryDialog("Disco features", "JID: ", func(s string) { // TODO: replace with undeprecated widget
|
||||
search, err = jid.Parse(s)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
myBox := container.NewVBox()
|
||||
info, err := disco.GetInfo(client.Ctx, "", jid.MustParse("ringen@muc.isekai.rocks"), client.Session)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
m := info.Features
|
||||
for _, v := range m {
|
||||
myBox.Objects = append(myBox.Objects, widget.NewLabel(v.Var))
|
||||
myBox.Refresh()
|
||||
}
|
||||
myBox := container.NewGridWithColumns(1, widget.NewLabel("Items\na\na\na\na\na"))
|
||||
info, err := disco.GetInfo(client.Ctx, "", search, client.Session)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
m := info.Features
|
||||
for _, v := range m {
|
||||
myBox.Add(widget.NewLabel(v.Var))
|
||||
myBox.Refresh()
|
||||
}
|
||||
|
||||
dialog.ShowCustom("things", "cancel", myBox, w)
|
||||
dialog.ShowCustom("Features", "cancel", myBox, w)
|
||||
|
||||
}, w)
|
||||
})
|
||||
|
||||
menu_help := fyne.NewMenu("π", mit, reconnect, deb)
|
||||
menu_changeroom := fyne.NewMenu("β", mic, servDisc)
|
||||
menu_configureview := fyne.NewMenu("γ", mia, mis, jtt, jtb)
|
||||
savedata := fyne.NewMenuItem("DEBUG: Save tab data to disk", func() {
|
||||
d := []ChatTab{}
|
||||
for _, v := range chatTabs {
|
||||
d = append(d, *v)
|
||||
}
|
||||
b, err := xml.Marshal(d)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
return
|
||||
}
|
||||
os.Create("test.xml")
|
||||
os.WriteFile("text.xml", b, os.ModeAppend)
|
||||
})
|
||||
menu_help := fyne.NewMenu("π", mit, reconnect, savedata)
|
||||
menu_changeroom := fyne.NewMenu("Α", mic, servDisc)
|
||||
menu_configureview := fyne.NewMenu("Β", mia, mis, jtt, jtb)
|
||||
hafjag := fyne.NewMenuItem("Hafjag", func() {
|
||||
entry.Text = "Hafjag"
|
||||
SendCallback()
|
||||
entry.Text = "Hafjag"
|
||||
})
|
||||
|
||||
hotfuck := fyne.NewMenuItem("Hot Fuck", func() {
|
||||
entry.Text = "Hot Fuck"
|
||||
SendCallback()
|
||||
entry.Text = "Oh Yeah."
|
||||
})
|
||||
|
||||
mycurrenttime := fyne.NewMenuItem("Current time", func() {
|
||||
entry.Text = fmt.Sprintf("It is currently %s", time.Now().Format(time.RFC850))
|
||||
SendCallback()
|
||||
})
|
||||
menu_jokes := fyne.NewMenu("δ", mycurrenttime, hafjag, hotfuck)
|
||||
bit := fyne.NewMenuItem("mark selected message as read", func() {
|
||||
selectedScroller, ok := tabs.Selected().Content.(*widget.List)
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var activeMucJid string
|
||||
for jid, tabData := range chatTabs {
|
||||
for jid, tabData := range UITabs {
|
||||
if tabData.Scroller == selectedScroller {
|
||||
activeMucJid = jid
|
||||
break
|
||||
@@ -764,13 +858,13 @@ func main() {
|
||||
bic := fyne.NewMenuItem("show message XML", func() {
|
||||
pre := widget.NewLabel("")
|
||||
|
||||
selectedScroller, ok := tabs.Selected().Content.(*widget.List)
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var activeChatJid string
|
||||
for jid, tabData := range chatTabs {
|
||||
for jid, tabData := range UITabs {
|
||||
if tabData.Scroller == selectedScroller {
|
||||
activeChatJid = jid
|
||||
break
|
||||
@@ -788,11 +882,11 @@ func main() {
|
||||
pre.Refresh()
|
||||
dialog.ShowCustom("Message", "Close", pre, w)
|
||||
})
|
||||
menu_messageoptions := fyne.NewMenu("Σ", bit, bia, bic)
|
||||
ma := fyne.NewMainMenu(menu_help, menu_changeroom, menu_configureview, menu_messageoptions)
|
||||
menu_messageoptions := fyne.NewMenu("Γ", bit, bia, bic)
|
||||
ma := fyne.NewMainMenu(menu_help, menu_changeroom, menu_configureview, menu_messageoptions, menu_jokes)
|
||||
w.SetMainMenu(ma)
|
||||
|
||||
tabs = container.NewAppTabs(
|
||||
AppTabs = container.NewAppTabs(
|
||||
container.NewTabItem("τίποτα", widget.NewLabel(`
|
||||
pi
|
||||
`)),
|
||||
@@ -813,14 +907,14 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
tabs.OnSelected = func(ti *container.TabItem) {
|
||||
selectedScroller, ok := tabs.Selected().Content.(*widget.List)
|
||||
AppTabs.OnSelected = func(ti *container.TabItem) {
|
||||
selectedScroller, ok := AppTabs.Selected().Content.(*widget.List)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var activeChatJid string
|
||||
for jid, tabData := range chatTabs {
|
||||
for jid, tabData := range UITabs {
|
||||
if tabData.Scroller == selectedScroller {
|
||||
activeChatJid = jid
|
||||
break
|
||||
@@ -828,19 +922,22 @@ func main() {
|
||||
}
|
||||
|
||||
tab := chatTabs[activeChatJid]
|
||||
UITab := UITabs[activeChatJid]
|
||||
if tab.isMuc {
|
||||
chatInfo = *container.NewHBox(widget.NewLabel(tab.Muc.Addr().String()))
|
||||
} else {
|
||||
chatInfo = *container.NewHBox(widget.NewLabel(tab.Jid.String()))
|
||||
}
|
||||
|
||||
if tab.isMuc {
|
||||
chatSidebar = *container.NewStack(container.NewVScroll(container.NewVBox(widget.NewRichTextFromMarkdown(fmt.Sprintf("# %s", tab.Jid.String())), widget.NewRichTextFromMarkdown(tab.Muc.Addr().String()))))
|
||||
//chatSidebar.Refresh()
|
||||
}
|
||||
chatSidebar = *UITab.Sidebar
|
||||
old := chatSidebar.Position()
|
||||
chatSidebar.Refresh()
|
||||
chatSidebar.Move(old)
|
||||
}
|
||||
|
||||
statBar.SetText("nothing seems to be happening right now...")
|
||||
w.SetContent(container.NewVSplit(container.NewVSplit(container.NewHSplit(tabs, &chatSidebar), container.NewHSplit(entry, sendbtn)), container.NewHSplit(&statBar, &chatInfo)))
|
||||
// HACK - disable chatsidebar because it's currently very buggy
|
||||
chatSidebar.Hidden = true
|
||||
statBar.SetText("")
|
||||
w.SetContent(container.NewVSplit(container.NewVSplit(AppTabs, container.NewHSplit(entry, sendbtn)), container.NewHSplit(&statBar, &chatInfo)))
|
||||
w.ShowAndRun()
|
||||
}
|
||||
|
Reference in New Issue
Block a user