You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

443 lines
14 KiB

package ui
import (
. "gotoot/toot"
"log"
"strconv"
"strings"
"html"
"github.com/gotk3/gotk3/gtk"
"github.com/gotk3/gotk3/glib"
)
type AccountView struct {
Acc *TootAccount // reference to the account shown for later use in callbacks
Box *gtk.Box
Header *gtk.Image // profile header image, shown on the top
Avatar *gtk.Image // avatar image
Name *gtk.Label // Displayname of the profile (or Username if no Displayname is set)
Handle *gtk.Label // Handle of the profile (@username@instance.com)
Note *gtk.Label // Personal note of the profile
FieldsGrid *gtk.Grid
Viewport *gtk.Viewport
EditBtn *gtk.Button
FollowBtn *gtk.Button
FollowsYouLabel *gtk.Label
Action struct {
DirectBtn *gtk.Button
MuteBtn *gtk.Button
BlockBtn *gtk.Button
ReportBtn *gtk.Button
}
Notebook *gtk.Notebook // The Account notebook containing toots, media, followers, following
Toots *gtk.Box // Toots-view by this account
Followers *gtk.Box // List of the followers of this account
Following *gtk.Box // Listing of the people this account follows
Media *gtk.Box // All toots containing media
FollowRequests *gtk.Box
TootsLabel *gtk.Label // Label in the Notebook-tab for Toots-View
MediaLabel *gtk.Label // Label in the Notebook-tab for Media-View
FollowingLabel *gtk.Label // Label in the Notebook-tab for Following-View
FollowersLabel *gtk.Label // Label in the Notebook-tab for Followers-View
FollowRequestsLabel *gtk.Label
}
const ( // Buttons for AccountListing
ACCOUNT_LISTING_FOLLOW = 1
ACCOUNT_LISTING_MUTE = 2
ACCOUNT_LISTING_BLOCK = 4
ACCOUNT_LISTING_FOLLOWSYOU = 8
ACCOUNT_LISTING_FOLLOWREQUESTS = 16
)
func accIn ( accs []TootAccount, acc TootAccount ) bool {
for _, v := range accs {
if v.Id == acc.Id {
return true
}
}
return false
}
// Create a Listing of accounts in a gtk.ListBox and remove the placeholder
func AccountListing ( page *gtk.Box, accs []TootAccount, acc *TootAccount, placeholder *gtk.Box, buttons int ) {
if len(accs) == 0 {
if acc == nil {
NoEntries ( page, "No accounts found" )
return
}
if strings.Index( acc.Acct, "@" ) == -1 { // local account
NoEntries ( page, "No accounts found" )
} else {
NoEntries ( page, "No accounts found.\nDue to the nature of the Fediverse, the list might be incomplete.\nTry querying the home server of the user." )
}
return
}
var ids []string
for _, fx := range accs {
ids = append ( ids, fx.Id )
}
rel, err := Relationships ( ids... )
if err != nil {
// TODO Notify the user
}
for _, fx := range accs {
var rs *TootRelationship
for _, rx := range rel {
if fx.Id == rx.Id {
rs = &rx
break
}
}
if rs == nil {
// TODO Notify the user, that something horrible must have happened
rs = &TootRelationship{}
}
r, err := gtk.BoxNew ( gtk.ORIENTATION_VERTICAL, 0 );
if err != nil {
continue
}
var btnWidgets []*gtk.Widget
var w *gtk.Button
if fx.Id != MainWin.Account.Acc.Id {
if buttons & ACCOUNT_LISTING_FOLLOWSYOU != 0 {
if rs.FollowedBy == true {
fol, _ := gtk.LabelNew ( "" )
fol.SetMarkup ( "<i>Follows You</i>" )
btnWidgets = append ( btnWidgets, fol.ToWidget() )
}
}
if buttons & ACCOUNT_LISTING_FOLLOWREQUESTS != 0 {
w, _ = gtk.ButtonNewWithLabel ( "Accept Request" )
w.Connect("clicked", _acceptRequest, fx.Id )
btnWidgets = append ( btnWidgets, w.ToWidget() )
w, _ = gtk.ButtonNewWithLabel ( "Reject Request" )
w.Connect("clicked", _rejectRequest, fx.Id )
btnWidgets = append ( btnWidgets, w.ToWidget() )
}
if buttons & ACCOUNT_LISTING_FOLLOW != 0 {
if rs.Following == true {
w, _ = gtk.ButtonNewWithLabel ("Unfollow")
} else {
w, _ = gtk.ButtonNewWithLabel ("Follow")
}
w.Connect("clicked", _follow, fx.Id )
btnWidgets = append ( btnWidgets, w.ToWidget() )
}
if buttons & ACCOUNT_LISTING_MUTE != 0 {
if rs.Muting == true {
w, _ = gtk.ButtonNewWithLabel ("Unmute")
} else {
w, _ = gtk.ButtonNewWithLabel ("Mute")
}
w.Connect("clicked", _mute, fx.Id )
btnWidgets = append ( btnWidgets, w.ToWidget() )
}
if buttons & ACCOUNT_LISTING_BLOCK != 0 {
if rs.Blocking == true {
w, _ = gtk.ButtonNewWithLabel ("Unblock")
} else {
w, _ = gtk.ButtonNewWithLabel ("Block")
}
w.Connect("clicked", _block, fx.Id )
btnWidgets = append ( btnWidgets, w.ToWidget() )
}
}
accbox, err := AccountName ( fx, 42, btnWidgets... )
if err != nil {
continue
}
r.Add ( accbox )
page.Add ( r )
}
if placeholder != nil {
placeholder.Hide()
placeholder.Destroy()
}
page.ShowAll()
}
func uiAccountNotebook ( acc TootAccount, view *AccountView, num int ) {
switch num {
case TootPage:
ph := PlaceHolder ( view.Toots )
go func () {
toots, err := view.Acc.Statuses ( false )
if err != nil {
return
}
glib.IdleAdd ( func () {
TootListing ( view.Toots, toots, ph )
})
}()
case MediaPage:
ph := PlaceHolder ( view.Media )
go func () {
toots, err := view.Acc.Statuses ( true )
if err != nil {
return
}
glib.IdleAdd ( func () {
TootListing ( view.Media, toots, ph )
})
}()
case FollowersPage:
ph := PlaceHolder ( view.Followers )
go func () {
followers, err := view.Acc.Followers ()
if err != nil {
return
}
glib.IdleAdd ( func () {
AccountListing ( view.Followers, followers, view.Acc, ph, ACCOUNT_LISTING_FOLLOWSYOU | ACCOUNT_LISTING_FOLLOW)
})
}()
case FollowingPage:
ph := PlaceHolder ( view.Following )
go func () {
following, err := view.Acc.Following ()
if err != nil {
return
}
glib.IdleAdd ( func () {
AccountListing ( view.Following, following, view.Acc, ph, ACCOUNT_LISTING_FOLLOWSYOU | ACCOUNT_LISTING_FOLLOW )
})
}()
case FollowRequestsPage:
if view.FollowRequests != nil && view.Acc.Id == MainWin.Account.Acc.Id {
ph := PlaceHolder ( view.FollowRequests )
go func () {
followrequests, err := FollowRequests ()
if err != nil {
return
}
glib.IdleAdd ( func () {
AccountListing ( view.FollowRequests, followrequests, view.Acc, ph, ACCOUNT_LISTING_FOLLOWREQUESTS | ACCOUNT_LISTING_BLOCK | ACCOUNT_LISTING_FOLLOW )
})
}()
}
}
}
func handleInteraction ( w *gtk.Button, id string, mode string ) {
x := TootAccount{Id:id};
var err error
r, err := x.Relationship()
if err != nil {
return
// TODO notify user of error
}
var txt string
switch mode {
case "mute":
if r.Muting == false {
_, err = x.Mute();
txt = "Unmute"
} else {
_, err = x.Unmute();
txt = "Mute"
}
case "block":
if r.Blocking == false {
_,err = x.Block();
txt = "Unblock"
} else {
_,err = x.Unblock();
txt = "Block"
}
case "report":
//err = x.Report();
txt = "Report"
case "follow":
if r.Following == false {
_,err = x.Follow();
txt = "Unfollow"
} else {
_,err = x.Unfollow();
txt = "Follow"
}
case "endorse":
if r.Endorsed == false {
_,err = x.Pin()
txt = "Unpin"
} else {
_,err = x.Unpin ()
txt = "Pin"
}
case "acceptRequest":
err = x.FollowRequestsAuthorize();
txt = ""
case "rejectRequest":
err = x.FollowRequestsReject();
txt = ""
}
if err == nil && w != nil {
if txt == "" { // when accepting or rejecting a follow request, we don't need the button anymore
w.Unparent()
w.Destroy()
} else {
w.SetLabel ( txt )
}
}
}
func _mute ( w *gtk.Button, id string ) {
handleInteraction ( w, id, "mute" )
}
func _block ( w *gtk.Button, id string ) {
handleInteraction ( w, id, "block" )
}
func _report ( w *gtk.Button, id string ) {
handleInteraction ( w, id, "report" )
}
func _follow ( w *gtk.Button, id string ) {
handleInteraction ( w, id, "follow" )
}
func _acceptRequest ( w *gtk.Button, id string ) {
handleInteraction ( w, id, "acceptRequest" )
}
func _rejectRequest ( w *gtk.Button, id string ) {
handleInteraction ( w, id, "rejectRequest" )
}
func _direct ( w *gtk.Button, id string ) {
acc := TootAccount{Id:id}
ac, err := acc.Get()
if err == nil {
MentionUser ( *ac, "direct" )
}
}
// On first open: fill an Accounts-View with data from the given Account struct
func uiAccountView ( acc TootAccount, view *AccountView ) {
view.Acc = &acc
view.Name.SetText ( acc.DisplayName )
view.Handle.SetText ( "@"+acc.Acct )
note, err := htmlToPango ( acc.Note )
if err == nil {
view.Note.SetMarkup ( note )
} else {
// TODO notify the user, or maybe just log?
}
view.Notebook.SetCurrentPage ( TootPage )
view.FollowingLabel.SetText ( "Following: " + strconv.Itoa(acc.FollowingCount) )
view.FollowersLabel.SetText ( strconv.Itoa(acc.FollowersCount) + " Followers" )
view.TootsLabel.SetText ( strconv.Itoa(acc.StatusesCount) + " Toots" )
if view.FollowRequests != nil && view.Acc.Id == MainWin.Account.Acc.Id {
if view.Acc.Locked == true {
flrequests, _ := FollowRequests()
view.FollowRequestsLabel.SetText ( strconv.Itoa(len(flrequests)) + " Follow Requests" )
} else {
page, _ := view.Notebook.GetNthPage ( FollowRequestsPage )
page.ToWidget().Hide()
}
}
view.FieldsGrid.GetChildren().FreeFull ( func ( w interface{} ) {
x, ok := w.(*gtk.Widget)
if ok == true {
x.Destroy()
}
})
for k, f := range acc.Fields {
name, _ := gtk.LabelNew ( "" )
name.SetMarkup ( "<b>" + html.EscapeString ( f.Name ) + "</b>" )
name.SetHAlign ( gtk.ALIGN_START )
v, err := htmlToPango ( f.Value )
if err != nil {
// TODO log
continue;
}
value, _ := gtk.LabelNew ( "" )
value.SetMarkup ( v )
value.SetHAlign ( gtk.ALIGN_START )
view.FieldsGrid.Attach ( name, 1, k, 1,1 )
view.FieldsGrid.Attach ( value, 2, k, 1,1, )
}
view.FieldsGrid.ShowAll()
uiAccountNotebook ( acc, view, view.Notebook.GetCurrentPage() )
f, err := pixVariantGet ( acc.Avatar, 128 )
if err == nil {
view.Avatar.SetFromFile ( f )
}
f, err = cache.Get ( acc.Header )
if err == nil {
w := view.Header.GetAllocatedWidth ()
px, err := SimpleScale ( f, w, -1 )
if err == nil {
view.Header.SetFromPixbuf ( px )
}
}
rel, err := view.Acc.Relationship()
if err == nil {
if view.Action.MuteBtn != nil {
view.Action.MuteBtn.Connect ("clicked", _mute, view.Acc.Id )
if rel.Muting == false {
view.Action.MuteBtn.SetLabel ( "Mute" )
} else {
view.Action.MuteBtn.SetLabel ( "Unmute" )
}
}
if view.Action.DirectBtn != nil {
view.Action.DirectBtn.Connect ("clicked", _direct, view.Acc.Id ) // handleDirect!
}
if view.Action.BlockBtn != nil {
view.Action.BlockBtn.Connect ("clicked", _block, view.Acc.Id )
if rel.Blocking == false {
view.Action.BlockBtn.SetLabel ( "Block" )
} else {
view.Action.BlockBtn.SetLabel ( "Unblock" )
}
}
if view.Action.ReportBtn != nil {
view.Action.ReportBtn.Connect ("clicked", _report, view.Acc.Id )
}
if view.FollowBtn != nil {
view.FollowBtn.Connect ("clicked", _follow, view.Acc.Id )
if rel.Following == false {
view.FollowBtn.SetLabel ( "Follow" )
} else {
view.FollowBtn.SetLabel ( "Unfollow" )
}
}
if view.FollowsYouLabel != nil {
if rel.FollowedBy == true {
view.FollowsYouLabel.SetMarkup ( "<i>Follows You</i>" )
} else {
view.FollowsYouLabel.SetText ( "" )
}
}
} else {
// TODO notify the user
}
view.Notebook.Connect ( "switch-page" , func ( widget *gtk.Notebook, page *gtk.Widget, num int ) {
uiAccountNotebook ( *view.Acc, view, num )
log.Println ("Notebook switch-page ", page, view.Followers, num)
})
}