2026-01-29 21:35:36 +00:00
package main
// This file contains the function that generates message widgets depending on message stanza
import (
2026-01-30 13:29:53 +00:00
"context"
2026-01-30 15:56:58 +00:00
"encoding/base64"
2026-01-29 21:35:36 +00:00
"fmt"
2026-02-01 18:16:55 +00:00
"github.com/diamondburned/gotk4/pkg/gdk/v4"
2026-08-07 12:50:35 +01:00
"github.com/diamondburned/gotk4/pkg/glib/v2"
2026-02-08 09:44:45 +00:00
"github.com/diamondburned/gotk4/pkg/gtk/v4"
2026-01-30 15:56:58 +00:00
"github.com/google/uuid"
"github.com/jasonlovesdoggo/gopen"
2026-01-29 21:35:36 +00:00
"gosrc.io/xmpp/stanza"
2026-05-19 14:07:21 +01:00
xmpp_color "mellium.im/xmpp/color"
2026-01-29 21:35:36 +00:00
"mellium.im/xmpp/jid"
2026-01-30 15:56:58 +00:00
"os"
"path/filepath"
2026-01-31 10:25:09 +00:00
"runtime"
2026-04-06 11:04:53 +01:00
"strings"
2026-01-29 21:35:36 +00:00
)
2026-01-31 10:02:04 +00:00
func generatePresenceWidget ( p stanza . Packet ) gtk . Widgetter {
2026-02-16 09:52:25 +00:00
b := gtk . NewBox ( gtk . OrientationHorizontal , 0 )
2026-01-31 10:02:04 +00:00
presence , ok := p .( stanza . Presence )
if ! ok {
2026-04-28 12:58:00 +01:00
return gtk . NewLabel ( loadedLocale [ "unsupportedMessage" ])
2026-01-31 10:02:04 +00:00
}
2026-06-03 06:38:31 +01:00
nick := JidMustParse ( presence . From ). Resource
2026-01-31 10:02:04 +00:00
if presence . Type == stanza . PresenceTypeUnavailable {
2026-01-31 15:08:54 +00:00
var mu MucUser
ok := presence . Get ( & mu )
if ok {
if mu . MucUserItem . Affiliation == "outcast" {
2026-06-03 06:38:31 +01:00
if loadedConfig . CompactMode {
l := gtk . NewLabel ( "" )
if mu . MucUserItem . Actor . Nick != "" {
l . SetMarkup ( fmt . Sprintf ( "<span background='black' foreground='white'>%s%s%s!</span>" , nick , loadedLocale [ "bannedWidget" ], mu . MucUserItem . Actor . Nick ))
} else {
l . SetMarkup ( fmt . Sprintf ( "<span background='black' foreground='white'>%s%s%s!</span>" , nick , loadedLocale [ "bannedWidgetNoActor" ]))
}
b . Append ( l )
return b
}
2026-05-23 06:45:18 +01:00
b . Append ( gtk . NewImageFromPaintable ( clientAssetsLoad ( "outcast" )))
2026-06-03 06:38:31 +01:00
b . Append ( gtk . NewLabel ( nick + loadedLocale [ "bannedWidget" ] + mu . MucUserItem . Actor . Nick + "!" ))
2026-02-16 09:52:25 +00:00
return b
2026-01-31 15:08:54 +00:00
}
}
2026-06-03 06:38:31 +01:00
if loadedConfig . CompactMode {
l := gtk . NewLabel ( "" )
l . SetMarkup ( fmt . Sprintf ( "<span foreground='%s'>- %s</span>" , "red" , nick ))
b . Append ( l )
} else {
b . Append ( gtk . NewImageFromPaintable ( clientAssetsLoad ( "door_out" )))
b . Append ( gtk . NewLabel ( nick ))
}
2026-01-31 10:02:04 +00:00
} else {
2026-06-03 06:38:31 +01:00
if loadedConfig . CompactMode {
l := gtk . NewLabel ( "" )
l . SetMarkup ( fmt . Sprintf ( "<span foreground='%s'>+ %s</span>" , "green" , nick ))
b . Append ( l )
} else {
b . Append ( gtk . NewImageFromPaintable ( clientAssetsLoad ( "door_in" )))
b . Append ( gtk . NewLabel ( JidMustParse ( presence . From ). Resource ))
}
2026-01-31 10:02:04 +00:00
}
2026-02-16 09:52:25 +00:00
b . SetTooltipText ( presence . Status )
return b
2026-01-31 10:02:04 +00:00
}
2026-08-16 20:07:53 +01:00
func generateMessageWidget ( p stanza . Packet , blocked bool , target string ) ( gtk . Widgetter , bool ) {
2026-01-29 21:35:36 +00:00
m , ok := p .( stanza . Message )
if ! ok {
2026-07-17 18:38:35 +01:00
return gtk . NewLabel ( "Unsupported message." ), true
2026-01-29 21:35:36 +00:00
}
2026-02-01 13:49:30 +00:00
readmarker := Marker {}
ok = m . Get ( & readmarker )
if ok {
2026-02-03 10:07:33 +00:00
b := gtk . NewBox ( gtk . OrientationHorizontal , 0 )
2026-04-28 12:58:00 +01:00
b . Append ( gtk . NewLabel ( fmt . Sprintf ( "%s%s" , JidMustParse ( m . From ). Resource , loadedLocale [ "readWidget" ])))
2026-07-17 18:38:35 +01:00
return b , true
2026-02-03 10:07:33 +00:00
}
2026-02-08 09:44:45 +00:00
composing := stanza . StateComposing {}
ok = m . Get ( & composing )
if ok {
2026-02-03 10:07:33 +00:00
b := gtk . NewBox ( gtk . OrientationHorizontal , 0 )
2026-04-28 12:58:00 +01:00
b . Append ( gtk . NewLabel ( fmt . Sprintf ( "%s%s" , JidMustParse ( m . From ). Resource , loadedLocale [ "isTyping" ])))
2026-07-17 18:38:35 +01:00
return b , true
2026-02-03 10:07:33 +00:00
}
if m . Error . Type != "" {
error_box := gtk . NewBox ( gtk . OrientationHorizontal , 0 )
2026-05-23 06:45:18 +01:00
cancel_img := gtk . NewImageFromPaintable ( clientAssetsLoad ( "cancel" ))
2026-02-16 09:52:25 +00:00
error_label := gtk . NewLabel ( m . Error . Text + ": " )
2026-02-03 10:07:33 +00:00
error_box . Append ( cancel_img )
error_box . Append ( error_label )
2026-02-15 13:08:52 +00:00
error_box . Append ( gtk . NewLabel ( m . Error . Reason ))
2026-07-17 18:38:35 +01:00
return error_box , true
2026-02-01 13:49:30 +00:00
}
2026-08-16 20:07:53 +01:00
store_label := false
tab , ok := tabs . Load ( target )
if ok {
store_label = true
}
typed_tab := tab .( * chatTab )
2026-01-29 21:35:36 +00:00
sid := StanzaID {}
m . Get ( & sid )
2026-07-17 17:15:41 +01:00
ocu := OccupantID {}
m . Get ( & ocu )
id := JidMustParse ( m . From ). Resource
name := id
2026-08-03 19:39:57 +01:00
2026-07-17 17:15:41 +01:00
custom_nick , ok := loadedConfig . CustomNicks [ ocu . ID ]
if ok {
name = custom_nick
}
// Avatar hash custom nicks. This code needs to be optimised.
mo , ok := mucmembers . Load ( JidMustParse ( m . From ). Bare ())
if ok {
mm , ok := mo .( mucUnit )
if ok {
mmm , ok := mm . Members . Load ( id )
if ok {
u := mmm .( stanza . Presence )
var vcu VCardUpdate
ok = u . Get ( & vcu )
if ok {
av_nick , ok := loadedConfig . CustomNicksAV [ vcu . Photo ]
if ok {
name = av_nick
}
}
}
}
}
2026-05-09 09:00:44 +01:00
padding := 10
orientation := gtk . OrientationVertical
if loadedConfig . CompactMode {
padding = 5
orientation = gtk . OrientationHorizontal
}
mainBox := gtk . NewBox ( orientation , padding )
2026-01-29 21:35:36 +00:00
gesture := gtk . NewGestureClick ()
gesture . SetButton ( 3 ) // Right click
2026-02-01 18:16:55 +00:00
popover := gtk . NewPopover ()
popover . SetParent ( mainBox )
popover . SetHasArrow ( false )
2026-05-07 09:16:38 +01:00
gesture . Connect ( "pressed" , func ( n_press , x , y int ) {
2026-05-09 07:33:47 +01:00
rc_box := gtk . NewBox ( gtk . OrientationVertical , 0 )
2026-02-01 18:16:55 +00:00
2026-05-09 07:33:47 +01:00
reactions := gtk . NewBox ( gtk . OrientationHorizontal , 0 )
reaction := [] string { "👍" , "👎" , "♥️" , "🤣" , "💀" }
for _ , v := range reaction {
2026-05-18 06:27:55 +01:00
like := gtk . NewButtonWithLabel ( v )
2026-05-09 07:33:47 +01:00
like . SetHExpand ( true )
like . ConnectClicked ( func () {
client . SendRaw ( fmt . Sprintf ( `
2026-01-29 21:35:36 +00:00
<message from='%s' to='%s' id='%s' type='%s'>
<reactions id='%s' xmlns='urn:xmpp:reactions:0'>
<reaction>%s</reaction>
</reactions>
</message>
` , m . To , jid . MustParse ( m . From ). Bare (). String (), uuid . New (). String (), m . Type , sid . ID , v ))
2026-05-09 07:33:47 +01:00
})
reactions . Append ( like )
2026-04-06 11:04:53 +01:00
}
2026-05-09 07:33:47 +01:00
rc_box . Append ( reactions )
2026-05-18 06:27:55 +01:00
custom := gtk . NewEntry ()
custom . SetPlaceholderText ( "..." )
enter_custom := gtk . NewButtonWithLabel ( "React" )
enter_custom . SetLabel ( "React" )
enter_custom . SetHExpand ( true )
enter_custom . ConnectClicked ( func () {
2026-05-19 14:07:21 +01:00
client . SendRaw ( fmt . Sprintf ( `
2026-05-18 06:27:55 +01:00
<message from='%s' to='%s' id='%s' type='%s'>
<reactions id='%s' xmlns='urn:xmpp:reactions:0'>
<reaction>%s</reaction>
</reactions>
</message>
` , m . To , jid . MustParse ( m . From ). Bare (). String (), uuid . New (). String (), m . Type , sid . ID , custom . Text ()))
})
rc_box . Append ( custom )
rc_box . Append ( enter_custom )
2026-04-06 11:04:53 +01:00
2026-05-09 07:33:47 +01:00
quote := gtk . NewButtonWithLabel ( "Quote" )
quote . ConnectClicked ( func () {
lines := strings . Split ( m . Body , "\n" )
for i , line := range lines {
quoteline := "> " + line
lines [ i ] = quoteline
}
2026-02-01 18:16:55 +00:00
2026-05-09 07:33:47 +01:00
newstr := strings . Join ( lines , "\n" ) + "\n\n"
message_en . SetText ( newstr )
})
rc_box . Append ( quote )
2026-07-17 17:15:41 +01:00
vp := gtk . NewButtonWithLabel ( "View profile" )
vp . ConnectClicked ( func () {
mo , ok := mucmembers . Load ( JidMustParse ( m . From ). Bare ())
if ok {
mm , ok := mo .( mucUnit )
if ok {
mmm , ok := mm . Members . Load ( id )
if ok {
u := mmm .( stanza . Presence )
showUserWindow ( u , name )
}
}
}
})
rc_box . Append ( vp )
2026-05-09 07:33:47 +01:00
popover . SetChild ( rc_box )
2026-02-01 18:16:55 +00:00
rect := gdk . NewRectangle ( x , y , 1 , 1 )
popover . SetPointingTo ( & rect )
popover . Popup ()
2026-01-29 21:35:36 +00:00
})
mainBox . AddController ( gesture )
2026-05-18 06:27:55 +01:00
if name == "" {
name = JidMustParse ( m . From ). Bare ()
2026-05-10 14:46:19 +01:00
}
2026-01-30 13:29:53 +00:00
2026-05-09 09:00:44 +01:00
if loadedConfig . CompactMode {
2026-07-30 01:39:31 +01:00
if m . Body == "" {
/*
mlabel.SetText(loadedLocale["noBodySet"])
mlabel.AddCSSClass("visitor")
*/
return nil , false
}
2026-07-17 17:15:41 +01:00
al := gtk . NewLabel ( name )
2026-05-09 09:00:44 +01:00
ycbcr := xmpp_color . String ( id , 255 , loadedConfig . CVD )
r , g , b , _ := ycbcr . RGBA ()
hexcolor := fmt . Sprintf ( "#%02x%02x%02x" , r , g , b )
2026-02-14 22:38:32 +00:00
2026-07-17 17:15:41 +01:00
al . SetMarkup ( fmt . Sprintf ( "<span foreground='%s'>%s</span>" , hexcolor , name ))
2026-05-09 09:00:44 +01:00
al . SetSelectable ( true )
al . SetVAlign ( gtk . AlignStart )
mainBox . Append ( al )
2026-01-29 21:35:36 +00:00
2026-08-03 19:39:57 +01:00
body := m . Body
2026-08-16 20:07:53 +01:00
body = XEPToPango ( body , false )
2026-08-03 19:39:57 +01:00
mlabel := gtk . NewLabel ( "" )
mlabel . SetMarkup ( body )
2026-01-30 19:08:18 +00:00
2026-05-09 09:00:44 +01:00
mlabel . SetWrap ( true )
mlabel . SetSelectable ( true )
// mlabel.SetHAlign(gtk.AlignFill)
mainBox . Append ( mlabel )
2026-08-16 20:07:53 +01:00
if store_label {
typed_tab . msg_refsID [ m . Id ]. label_ref = mlabel
tabs . Store ( target , tab )
}
2026-05-09 09:00:44 +01:00
} else {
authorBox := gtk . NewBox ( gtk . OrientationHorizontal , 10 )
contentBox := gtk . NewBox ( gtk . OrientationHorizontal , 0 )
2026-05-10 14:46:19 +01:00
2026-05-18 06:27:55 +01:00
al := gtk . NewLabel ( name )
2026-05-09 09:00:44 +01:00
al . AddCSSClass ( "author" )
al . SetSelectable ( true )
2026-02-01 18:16:55 +00:00
2026-05-09 09:00:44 +01:00
if m . Type == stanza . MessageTypeGroupchat {
2026-05-18 06:27:55 +01:00
can_generate := true
mo , ok := mucmembers . Load ( JidMustParse ( m . From ). Bare ())
if ! ok {
can_generate = false
}
mm , ok := mo .( mucUnit )
if ! ok {
can_generate = false
}
2026-05-09 09:00:44 +01:00
mmm := mm . Members
mmmm , ok := mmm . Load ( id )
2026-05-18 06:27:55 +01:00
if ! ok {
can_generate = false
}
2026-08-07 12:50:35 +01:00
2026-08-06 13:33:55 +01:00
im := gtk . NewImage ()
2026-08-07 12:50:35 +01:00
im . SetFromPaintable ( clientAssetsLoad ( "DefaultAvatar" ))
im . SetPixelSize ( 40 )
im . AddCSSClass ( "author_img" )
// createIdenticon(m.From, false, im)
authorBox . Append ( im )
2026-05-18 06:27:55 +01:00
if can_generate {
2026-05-09 09:00:44 +01:00
pres := mmmm .( stanza . Presence )
var vu VCardUpdate
pres . Get ( & vu )
if vu . Photo != "" {
2026-08-06 13:33:55 +01:00
go getAvatar ( m . From , vu . Photo , im )
2026-05-09 09:00:44 +01:00
}
} else {
2026-08-06 13:33:55 +01:00
createIdenticon ( m . From , false , im )
2026-08-07 12:50:35 +01:00
/*
2026-08-08 13:54:20 +01:00
im.SetPixelSize(40)
im.AddCSSClass("author_img")
authorBox.Append(im)
2026-08-07 12:50:35 +01:00
*/
2026-01-30 21:31:33 +00:00
}
2026-05-09 09:00:44 +01:00
} else if m . Type == stanza . MessageTypeChat {
al . SetText ( al . Text () + loadedLocale [ "whispers" ])
}
2026-04-30 14:55:17 +01:00
2026-05-09 09:00:44 +01:00
authorBox . Append ( al )
if m . Thread != "" {
2026-08-06 13:33:55 +01:00
im := gtk . NewImage ()
createIdenticon ( m . Thread , true , im )
2026-05-09 09:00:44 +01:00
im . SetPixelSize ( 10 )
2026-01-30 21:31:33 +00:00
authorBox . Append ( im )
2026-01-30 19:08:18 +00:00
}
2026-05-09 09:00:44 +01:00
wxdc := XDCEl {}
ok = m . Get ( & wxdc )
2026-05-01 21:05:14 +01:00
if ok {
2026-05-09 09:00:44 +01:00
authorBox . Append ( gtk . NewLabel ( "🎮" ))
2026-05-01 21:05:14 +01:00
}
2026-02-16 09:52:25 +00:00
2026-08-07 12:50:35 +01:00
body := m . Body
2026-08-16 20:07:53 +01:00
body = XEPToPango ( body , false )
2026-08-07 12:50:35 +01:00
mlabel := gtk . NewLabel ( "" )
2026-05-09 09:00:44 +01:00
if m . Body == "" {
2026-07-17 18:38:35 +01:00
/*
2026-07-30 01:39:31 +01:00
mlabel.SetText(loadedLocale["noBodySet"])
mlabel.AddCSSClass("visitor")
2026-07-17 18:38:35 +01:00
*/
return nil , false
2026-05-09 09:00:44 +01:00
}
2026-08-07 12:50:35 +01:00
mlabel . SetMarkup ( body )
2026-05-09 09:00:44 +01:00
mlabel . SetWrap ( true )
mlabel . SetSelectable ( true )
mlabel . SetHAlign ( gtk . AlignFill )
2026-01-29 21:35:36 +00:00
2026-08-16 20:07:53 +01:00
if store_label {
msg , ok := typed_tab . msg_refsID [ m . Id ]
if ! ok {
msg = new ( abMessage )
typed_tab . msg_refsID [ m . Id ] = msg
2026-05-09 09:00:44 +01:00
}
2026-01-29 21:35:36 +00:00
2026-08-16 20:07:53 +01:00
msg . label_ref = mlabel
msg . ocu_id = ocu . ID
tabs . Store ( target , typed_tab )
}
2026-05-09 09:00:44 +01:00
contentBox . Append ( mlabel )
2026-01-29 21:35:36 +00:00
2026-05-09 09:00:44 +01:00
mainBox . Append ( authorBox )
mainBox . Append ( contentBox )
2026-02-15 13:08:52 +00:00
2026-05-09 09:00:44 +01:00
oob := stanza . OOB {}
ok = m . Get ( & oob )
if ok {
// media := newPictureFromWeb(oob.URL)
// media.SetCanShrink(false)
// mainBox.Append(media)
// media.AddCSSClass("chat_image")
mbtn := gtk . NewButtonWithLabel ( "🖼️" )
// mbtn.SetChild(newImageFromWeb(oob.URL))
mbtn . ConnectClicked ( func () {
gopen . Open ( oob . URL )
})
authorBox . Append ( mbtn )
}
2026-04-26 10:40:13 +01:00
2026-05-09 09:00:44 +01:00
if m . Subject != "" {
subjectlabel := gtk . NewLabel ( m . Subject )
subjectlabel . SetWrap ( true )
subjectlabel . SetSelectable ( true )
subjectlabel . SetHAlign ( gtk . AlignFill )
subjectlabel . AddCSSClass ( "subject" )
mainBox . Append ( subjectlabel )
}
2026-04-26 10:40:13 +01:00
2026-05-09 09:00:44 +01:00
link_preview := LinkPreview {}
ok = m . Get ( & link_preview )
if ok {
lp_box := gtk . NewBox ( gtk . OrientationVertical , 10 )
lp_box . AddCSSClass ( "link_preview" )
lp_title := gtk . NewLabel ( link_preview . Title )
lp_title . SetSelectable ( true )
lp_title . SetWrap ( true )
lp_title . SetHAlign ( gtk . AlignFill )
lp_desc := gtk . NewLabel ( link_preview . URL + "\n" + link_preview . Description )
lp_desc . SetSelectable ( true )
lp_desc . SetWrap ( true )
lp_desc . SetHAlign ( gtk . AlignFill )
2026-04-26 10:40:13 +01:00
2026-05-09 09:00:44 +01:00
lp_box . Append ( lp_title )
lp_box . Append ( lp_desc )
warning := gtk . NewLabel ( "⚠️" )
warning . SetTooltipText ( loadedLocale [ "linkPreviewWarning" ])
lp_box . Append ( warning )
mainBox . Append ( lp_box )
}
2026-08-07 12:50:35 +01:00
2026-04-26 10:40:13 +01:00
}
2026-07-30 01:39:31 +01:00
if loadedConfig . BlockingMode == Highlight && blocked {
mainBox . AddCSSClass ( "blocked" )
}
if loadedConfig . BlockingMode == Hide && blocked {
mainBox . SetVisible ( false )
blocked_box := gtk . NewBox ( gtk . OrientationVertical , 0 )
blocked_part := gtk . NewBox ( gtk . OrientationHorizontal , 0 )
blocked_part . Append ( gtk . NewLabel ( "This message is from a user you have blocked. " ))
show_hide := gtk . NewButtonWithLabel ( "Toggle" )
show_hide . ConnectClicked ( func () {
mainBox . SetVisible (! mainBox . IsVisible ())
})
blocked_part . Append ( show_hide )
blocked_box . Append ( blocked_part )
blocked_box . Append ( mainBox )
return blocked_box , true
}
2026-07-17 18:38:35 +01:00
return mainBox , true
2026-01-29 21:35:36 +00:00
}
func getVAdjustment ( scrolledWindow * gtk . ScrolledWindow ) * gtk . Adjustment {
val := scrolledWindow . ObjectProperty ( "vadjustment" ).( * gtk . Adjustment )
return val
}
2026-01-30 13:29:53 +00:00
2026-08-06 13:33:55 +01:00
func getAvatar ( j , hash string , i * gtk . Image ) { // TODO: This function probably shouldn't be here, and should probably be in xmpp-helpers or somewhere similar.
2026-03-12 16:09:22 +00:00
oghash := hash
2026-01-30 15:56:58 +00:00
p , err := ensureCache ()
if err != nil {
2026-08-06 13:33:55 +01:00
createIdenticon ( j , false , i )
return
2026-01-30 15:56:58 +00:00
}
2026-01-30 13:29:53 +00:00
2026-01-30 19:08:18 +00:00
if hash == "" {
2026-08-06 13:33:55 +01:00
createIdenticon ( j , false , i )
return
2026-01-30 19:08:18 +00:00
}
2026-05-08 06:56:51 +01:00
_ , ok := invalidImages . Load ( hash )
2026-03-12 16:09:22 +00:00
if ok {
2026-08-06 13:33:55 +01:00
createIdenticon ( j , false , i )
return
2026-03-12 16:09:22 +00:00
}
2026-05-02 06:56:08 +01:00
hash = filepath . Join ( p , hash )
2026-01-30 15:56:58 +00:00
_ , err = os . ReadFile ( hash )
2026-01-30 13:29:53 +00:00
if err == nil {
2026-08-06 13:33:55 +01:00
/*
2026-08-08 13:54:20 +01:00
i, err = newImageFromPath(hash)
if err != nil {
invalidImages.Store(oghash, true)
createIdenticon(j, false, i)
}
2026-08-06 13:33:55 +01:00
*/
2026-08-08 13:54:20 +01:00
glib . IdleAdd ( func () {
setImageFromPath ( hash , i )
})
2026-08-06 13:33:55 +01:00
return
2026-08-08 13:54:20 +01:00
}
2026-01-30 13:29:53 +00:00
iqResp , err := stanza . NewIQ ( stanza . Attrs {
Type : "get" ,
From : clientroot . Session . BindJid ,
2026-01-30 15:56:58 +00:00
To : j ,
2026-05-02 06:56:08 +01:00
Id : uuid . New (). String (),
2026-01-30 15:56:58 +00:00
Lang : "en" ,
2026-01-30 13:29:53 +00:00
})
if err != nil {
panic ( err )
}
iqResp . Payload = & VCard {}
ctx := context . TODO ()
mychan , err := client . SendIQ ( ctx , iqResp )
if err != nil {
panic ( err )
}
2026-01-30 15:56:58 +00:00
result := <- mychan
2026-01-30 13:29:53 +00:00
card , ok := result . Payload .( * VCard )
if ! ok {
2026-08-06 13:33:55 +01:00
createIdenticon ( j , false , i )
return
2026-01-30 13:29:53 +00:00
}
base64_data := card . Photo . Binval
2026-02-20 09:01:40 +00:00
if card . Photo . Binval == "" || (( card . Photo . Type == "image/svg+xml" || card . Photo . Type == "image/webp" ) && ( runtime . GOOS == "windows" || runtime . GOOS == "netbsd" )) {
2026-05-08 06:56:51 +01:00
invalidImages . Store ( oghash , true )
2026-08-06 13:33:55 +01:00
createIdenticon ( j , false , i )
return
2026-01-30 13:29:53 +00:00
}
data , err := base64 . StdEncoding . DecodeString ( base64_data )
if err != nil {
panic ( err )
}
err = os . WriteFile ( hash , data , 0644 )
if err != nil {
panic ( err )
}
2026-08-07 12:50:35 +01:00
glib . IdleAdd ( func () {
2026-08-08 13:54:20 +01:00
err = setImageFromPath ( hash , i )
if err != nil {
invalidImages . Store ( oghash , true )
createIdenticon ( j , false , i )
}
2026-08-06 13:33:55 +01:00
2026-08-08 13:54:20 +01:00
i . AddCSSClass ( loadedConfig . CVD . String () + "_CVD" )
2026-08-07 12:50:35 +01:00
})
2026-01-30 15:56:58 +00:00
}