Browse Source

1.0.9 (#149)

* use default posting setting

* implement preferences

* bump version

* update mod

* user and avatar on the right user

* update docs
pull/156/head 1.0.9
Rasmus Lindroth 4 years ago committed by GitHub
parent
commit
157bc5075e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      README.md
  2. 8
      api/user.go
  3. 34
      config.example.ini
  4. 30
      config/config.go
  5. 34
      config/default_config.go
  6. 2
      go.mod
  7. 4
      go.sum
  8. 2
      main.go
  9. 6
      ui/cmdbar.go
  10. 4
      ui/commands.go
  11. 27
      ui/composeview.go
  12. 95
      ui/input.go
  13. 25
      ui/open.go
  14. 27
      ui/pollview.go
  15. 356
      ui/preferenceview.go
  16. 3
      ui/statusbar.go
  17. 19
      ui/tutview.go
  18. 9
      ui/view.go

1
README.md

@ -38,6 +38,7 @@ You can find Linux binaries under [releases](https://github.com/RasmusLindroth/t
* `:h` `:help` view help
* `:lists` show a list of your lists
* `:muting` lists users that you have muted
* `:preferences` update your profile and some other settings
* `:profile` go to your profile
* `:requests` see following requests
* `:saved` alias for bookmarks

8
api/user.go

@ -79,3 +79,11 @@ func (ac *AccountClient) FollowRequestAccept(u *mastodon.Account) error {
func (ac *AccountClient) FollowRequestDeny(u *mastodon.Account) error {
return ac.Client.FollowRequestReject(context.Background(), u.ID)
}
func (ac *AccountClient) SavePreferences(p *mastodon.Profile) error {
acc, err := ac.Client.AccountUpdate(context.Background(), p)
if err == nil {
ac.Me = acc
}
return err
}

34
config.example.ini

@ -137,7 +137,7 @@ leader-timeout=1000
#
# Available commands: home, direct, local, federated, compose, blocking,
# bookmarks, saved, favorited, boosts, favorites, following, followers, muting,
# profile, notifications, lists, tag, window
# preferences, profile, notifications, lists, tag, window
#
# The shortcuts are up to you, but keep them quite short and make sure they
# don't collide. If you have one shortcut that is "f" and an other one that is
@ -639,3 +639,35 @@ poll-multi-toggle="Toggle [M]ultiple",'m','M'
# Change the expiration of poll
# default="E[X]pires",'x','X'
poll-expiration="E[X]pires",'x','X'
# Change display name
# default="[N]ame",'n','N'
preference-name="[N]ame",'n','N'
# Change default visibility of toots
# default="[V]isibility",'v','V'
preference-visibility="[V]isibility",'v','V'
# Change bio in profile
# default="[B]io",'b','B'
preference-bio="[B]io",'b','B'
# Save your preferences
# default="[S]ave",'s','S'
preference-save="[S]ave",'s','S'
# Edit profile fields
# default="[F]ields",'f','F'
preference-fields="[F]ields",'f','F'
# Add new field
# default="[A]dd",'a','A'
preference-fields-add="[A]dd",'a','A'
# Edit current field
# default="[E]dit",'e','E'
preference-fields-edit="[E]dit",'e','E'
# Delete current field
# default="[D]elete",'d','D'
preference-fields-delete="[D]elete",'d','D'

30
config/config.go

@ -65,6 +65,7 @@ const (
LeaderFollowing
LeaderFollowers
LeaderMuting
LeaderPreferences
LeaderProfile
LeaderNotifications
LeaderLists
@ -375,6 +376,15 @@ type Input struct {
PollDelete Key
PollMultiToggle Key
PollExpiration Key
PreferenceName Key
PreferenceVisibility Key
PreferenceBio Key
PreferenceSave Key
PreferenceFields Key
PreferenceFieldsAdd Key
PreferenceFieldsEdit Key
PreferenceFieldsDelete Key
}
func parseColor(input string, def string, xrdb map[string]string) tcell.Color {
@ -660,6 +670,8 @@ func parseGeneral(cfg *ini.File) General {
la.Command = LeaderFollowers
case "muting":
la.Command = LeaderMuting
case "preferences":
la.Command = LeaderPreferences
case "profile":
la.Command = LeaderProfile
case "notifications":
@ -1050,6 +1062,15 @@ func parseInput(cfg *ini.File) Input {
PollDelete: inputStrOrErr([]string{"\"[D]elete\"", "'d'", "'D'"}, false),
PollMultiToggle: inputStrOrErr([]string{"\"Toggle [M]ultiple\"", "'m'", "'M'"}, false),
PollExpiration: inputStrOrErr([]string{"\"E[X]pires\"", "'x'", "'X'"}, false),
PreferenceName: inputStrOrErr([]string{"\"[N]ame\"", "'n'", "'N'"}, false),
PreferenceBio: inputStrOrErr([]string{"\"[B]io\"", "'b'", "'B'"}, false),
PreferenceVisibility: inputStrOrErr([]string{"\"[V]isibility\"", "'v'", "'V'"}, false),
PreferenceSave: inputStrOrErr([]string{"\"[S]ave\"", "'s'", "'S'"}, false),
PreferenceFields: inputStrOrErr([]string{"\"[F]ields\"", "'f'", "'F'"}, false),
PreferenceFieldsAdd: inputStrOrErr([]string{"\"[A]dd\"", "'a'", "'A'"}, false),
PreferenceFieldsEdit: inputStrOrErr([]string{"\"[E]dit\"", "'e'", "'E'"}, false),
PreferenceFieldsDelete: inputStrOrErr([]string{"\"[D]elete\"", "'d'", "'D'"}, false),
}
ic.GlobalDown = inputOrErr(cfg, "global-down", false, ic.GlobalDown)
ic.GlobalUp = inputOrErr(cfg, "global-up", false, ic.GlobalUp)
@ -1114,6 +1135,15 @@ func parseInput(cfg *ini.File) Input {
ic.PollDelete = inputOrErr(cfg, "poll-delete", false, ic.PollDelete)
ic.PollMultiToggle = inputOrErr(cfg, "poll-multi-toggle", false, ic.PollMultiToggle)
ic.PollExpiration = inputOrErr(cfg, "poll-expiration", false, ic.PollExpiration)
ic.PreferenceName = inputOrErr(cfg, "preference-name", false, ic.PreferenceName)
ic.PreferenceVisibility = inputOrErr(cfg, "preference-visibility", false, ic.PreferenceVisibility)
ic.PreferenceBio = inputOrErr(cfg, "preference-bio", false, ic.PreferenceBio)
ic.PreferenceSave = inputOrErr(cfg, "preference-save", false, ic.PreferenceSave)
ic.PreferenceFields = inputOrErr(cfg, "preference-fields", false, ic.PreferenceFields)
ic.PreferenceFieldsAdd = inputOrErr(cfg, "preference-fields-add", false, ic.PreferenceFieldsAdd)
ic.PreferenceFieldsEdit = inputOrErr(cfg, "preference-fields-edit", false, ic.PreferenceFieldsEdit)
ic.PreferenceFieldsDelete = inputOrErr(cfg, "preference-fields-delete", false, ic.PreferenceFieldsDelete)
return ic
}

34
config/default_config.go

@ -139,7 +139,7 @@ leader-timeout=1000
#
# Available commands: home, direct, local, federated, compose, blocking,
# bookmarks, saved, favorited, boosts, favorites, following, followers, muting,
# profile, notifications, lists, tag, window
# preferences, profile, notifications, lists, tag, window
#
# The shortcuts are up to you, but keep them quite short and make sure they
# don't collide. If you have one shortcut that is "f" and an other one that is
@ -641,4 +641,36 @@ poll-multi-toggle="Toggle [M]ultiple",'m','M'
# Change the expiration of poll
# default="E[X]pires",'x','X'
poll-expiration="E[X]pires",'x','X'
# Change display name
# default="[N]ame",'n','N'
preference-name="[N]ame",'n','N'
# Change default visibility of toots
# default="[V]isibility",'v','V'
preference-visibility="[V]isibility",'v','V'
# Change bio in profile
# default="[B]io",'b','B'
preference-bio="[B]io",'b','B'
# Save your preferences
# default="[S]ave",'s','S'
preference-save="[S]ave",'s','S'
# Edit profile fields
# default="[F]ields",'f','F'
preference-fields="[F]ields",'f','F'
# Add new field
# default="[A]dd",'a','A'
preference-fields-add="[A]dd",'a','A'
# Edit current field
# default="[E]dit",'e','E'
preference-fields-edit="[E]dit",'e','E'
# Delete current field
# default="[D]elete",'d','D'
preference-fields-delete="[D]elete",'d','D'
`

2
go.mod

@ -3,7 +3,7 @@ module github.com/RasmusLindroth/tut
go 1.17
require (
github.com/RasmusLindroth/go-mastodon v0.0.6
github.com/RasmusLindroth/go-mastodon v0.0.7
github.com/atotto/clipboard v0.1.4
github.com/gdamore/tcell/v2 v2.5.1
github.com/gen2brain/beeep v0.0.0-20220402123239-6a3042f4b71a

4
go.sum

@ -1,5 +1,5 @@
github.com/RasmusLindroth/go-mastodon v0.0.6 h1:dhVXungiJeRKIE2ZRUJrPibBJ7YkeM4eVyeg3+q6Juk=
github.com/RasmusLindroth/go-mastodon v0.0.6/go.mod h1:4L0oyiNwq1tUoiByczzhSikxR9RiANzELtZgexxKpPM=
github.com/RasmusLindroth/go-mastodon v0.0.7 h1:iGgkkvDrPHTiAyACUehLH5zragSHCUSbhcYdQEBIn48=
github.com/RasmusLindroth/go-mastodon v0.0.7/go.mod h1:4L0oyiNwq1tUoiByczzhSikxR9RiANzELtZgexxKpPM=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=

2
main.go

@ -10,7 +10,7 @@ import (
"github.com/rivo/tview"
)
const version = "1.0.8"
const version = "1.0.9"
func main() {
util.MakeDirs()

6
ui/cmdbar.go

@ -100,6 +100,10 @@ func (c *CmdBar) DoneFunc(key tcell.Key) {
case ":profile":
c.tutView.ProfileCommand()
c.Back()
case ":preferences":
c.tutView.PreferencesCommand()
c.ClearInput()
c.View.Autocomplete()
case ":timeline", ":tl":
if len(parts) < 2 {
break
@ -166,7 +170,7 @@ func (c *CmdBar) DoneFunc(key tcell.Key) {
func (c *CmdBar) Autocomplete(curr string) []string {
var entries []string
words := strings.Split(":blocking,:boosts,:bookmarks,:compose,:favorites,:favorited,:followers,:following,:help,:h,:lists,:muting,:profile,:requests,:saved,:tag,:timeline,:tl,:user,:window,:quit,:q", ",")
words := strings.Split(":blocking,:boosts,:bookmarks,:compose,:favorites,:favorited,:followers,:following,:help,:h,:lists,:muting,:preferences,:profile,:requests,:saved,:tag,:timeline,:tl,:user,:window,:quit,:q", ",")
if curr == "" {
return entries
}

4
ui/commands.go

@ -163,3 +163,7 @@ func (tv *TutView) ProfileCommand() {
NewUserFeed(tv, item),
)
}
func (tv *TutView) PreferencesCommand() {
tv.SetPage(PreferenceFocus)
}

27
ui/composeview.go

@ -40,7 +40,18 @@ type ComposeView struct {
msg *msgToot
}
var visibilities = []string{mastodon.VisibilityPublic, mastodon.VisibilityUnlisted, mastodon.VisibilityFollowersOnly, mastodon.VisibilityDirectMessage}
var visibilities = map[string]int{
mastodon.VisibilityPublic: 0,
mastodon.VisibilityUnlisted: 1,
mastodon.VisibilityFollowersOnly: 2,
mastodon.VisibilityDirectMessage: 3,
}
var visibilitiesStr = []string{
mastodon.VisibilityPublic,
mastodon.VisibilityUnlisted,
mastodon.VisibilityFollowersOnly,
mastodon.VisibilityDirectMessage,
}
func NewComposeView(tv *TutView) *ComposeView {
cv := &ComposeView{
@ -122,6 +133,11 @@ func (cv *ComposeView) SetStatus(status *mastodon.Status) {
cv.tutView.PollView.Reset()
cv.media.Reset()
msg := &msgToot{}
me := cv.tutView.tut.Client.Me
visibility := mastodon.VisibilityPublic
if me.Source != nil && me.Source.Privacy != nil {
visibility = *me.Source.Privacy
}
if status != nil {
if status.Reblog != nil {
status = status.Reblog
@ -131,8 +147,11 @@ func (cv *ComposeView) SetStatus(status *mastodon.Status) {
msg.Sensitive = true
msg.SpoilerText = status.SpoilerText
}
msg.Visibility = status.Visibility
if visibilities[status.Visibility] > visibilities[visibility] {
visibility = status.Visibility
}
}
msg.Visibility = visibility
cv.msg = msg
cv.msg.Text = cv.getAccs()
if cv.tutView.tut.Config.General.QuoteReply {
@ -140,13 +159,13 @@ func (cv *ComposeView) SetStatus(status *mastodon.Status) {
}
cv.visibility.SetLabel("Visibility: ")
index := 0
for i, v := range visibilities {
for i, v := range visibilitiesStr {
if msg.Visibility == v {
index = i
break
}
}
cv.visibility.SetOptions(visibilities, cv.visibilitySelected)
cv.visibility.SetOptions(visibilitiesStr, cv.visibilitySelected)
cv.visibility.SetCurrentOption(index)
cv.visibility.SetInputCapture(cv.visibilityInput)
cv.UpdateContent()

95
ui/input.go

@ -50,6 +50,8 @@ func (tv *TutView) Input(event *tcell.EventKey) *tcell.EventKey {
return tv.InputVote(event)
case HelpFocus:
return tv.InputHelp(event)
case PreferenceFocus:
return tv.InputPreference(event)
default:
return event
}
@ -122,6 +124,8 @@ func (tv *TutView) InputLeaderKey(event *tcell.EventKey) *tcell.EventKey {
tv.FollowersCommand()
case config.LeaderMuting:
tv.MutingCommand()
case config.LeaderPreferences:
tv.PreferencesCommand()
case config.LeaderProfile:
tv.ProfileCommand()
case config.LeaderNotifications:
@ -258,7 +262,7 @@ func (tv *TutView) InputItem(event *tcell.EventKey) *tcell.EventKey {
}
switch item.Type() {
case api.StatusType:
return tv.InputStatus(event, item, item.Raw().(*mastodon.Status))
return tv.InputStatus(event, item, item.Raw().(*mastodon.Status), nil)
case api.UserType, api.ProfileType:
if ft == feed.FollowRequests {
return tv.InputUser(event, item.Raw().(*api.User), true)
@ -271,15 +275,17 @@ func (tv *TutView) InputItem(event *tcell.EventKey) *tcell.EventKey {
case "follow":
return tv.InputUser(event, nd.User.Raw().(*api.User), false)
case "favourite":
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status))
user := nd.User.Raw().(*api.User)
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), user.Data)
case "reblog":
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status))
user := nd.User.Raw().(*api.User)
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), user.Data)
case "mention":
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status))
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), nil)
case "status":
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status))
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), nil)
case "poll":
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status))
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), nil)
case "follow_request":
return tv.InputUser(event, nd.User.Raw().(*api.User), true)
}
@ -290,7 +296,7 @@ func (tv *TutView) InputItem(event *tcell.EventKey) *tcell.EventKey {
return event
}
func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mastodon.Status) *tcell.EventKey {
func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mastodon.Status, nAcc *mastodon.Account) *tcell.EventKey {
sr := util.StatusOrReblog(status)
hasMedia := len(sr.MediaAttachments) > 0
@ -303,7 +309,11 @@ func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mas
bookmarked := sr.Bookmarked
if tv.tut.Config.Input.StatusAvatar.Match(event.Key(), event.Rune()) {
openAvatar(tv, sr.Account)
if nAcc != nil {
openAvatar(tv, *nAcc)
} else {
openAvatar(tv, sr.Account)
}
return nil
}
if tv.tut.Config.Input.StatusBoost.Match(event.Key(), event.Rune()) {
@ -413,7 +423,11 @@ func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mas
return nil
}
if tv.tut.Config.Input.StatusUser.Match(event.Key(), event.Rune()) {
user, err := tv.tut.Client.GetUserByID(status.Account.ID)
id := status.Account.ID
if nAcc != nil {
id = nAcc.ID
}
user, err := tv.tut.Client.GetUserByID(id)
if err != nil {
return nil
}
@ -774,6 +788,69 @@ func (tv *TutView) InputVote(event *tcell.EventKey) *tcell.EventKey {
return event
}
func (tv *TutView) InputPreference(event *tcell.EventKey) *tcell.EventKey {
if tv.PreferenceView.HasFieldFocus() {
return tv.InputPreferenceFields(event)
}
if tv.tut.Config.Input.PreferenceFields.Match(event.Key(), event.Rune()) {
tv.PreferenceView.FieldFocus()
return nil
}
if tv.tut.Config.Input.PreferenceName.Match(event.Key(), event.Rune()) {
tv.PreferenceView.EditDisplayname()
return nil
}
if tv.tut.Config.Input.PreferenceVisibility.Match(event.Key(), event.Rune()) {
tv.PreferenceView.FocusVisibility()
return nil
}
if tv.tut.Config.Input.PreferenceBio.Match(event.Key(), event.Rune()) {
tv.PreferenceView.EditBio()
return nil
}
if tv.tut.Config.Input.PreferenceSave.Match(event.Key(), event.Rune()) {
tv.PreferenceView.Save()
return nil
}
if tv.tut.Config.Input.GlobalBack.Match(event.Key(), event.Rune()) ||
tv.tut.Config.Input.GlobalExit.Match(event.Key(), event.Rune()) {
tv.ModalView.Run(
"Do you want exit the preference view?", func() {
tv.FocusMainNoHistory()
})
return nil
}
return event
}
func (tv *TutView) InputPreferenceFields(event *tcell.EventKey) *tcell.EventKey {
if tv.tut.Config.Input.GlobalUp.Match(event.Key(), event.Rune()) {
tv.PreferenceView.PrevField()
return nil
}
if tv.tut.Config.Input.GlobalDown.Match(event.Key(), event.Rune()) {
tv.PreferenceView.NextField()
return nil
}
if tv.tut.Config.Input.PreferenceFieldsAdd.Match(event.Key(), event.Rune()) {
tv.PreferenceView.AddField()
return nil
}
if tv.tut.Config.Input.PreferenceFieldsEdit.Match(event.Key(), event.Rune()) {
tv.PreferenceView.EditField()
return nil
}
if tv.tut.Config.Input.PreferenceFieldsDelete.Match(event.Key(), event.Rune()) {
tv.PreferenceView.DeleteField()
return nil
}
if tv.tut.Config.Input.GlobalBack.Match(event.Key(), event.Rune()) ||
tv.tut.Config.Input.GlobalExit.Match(event.Key(), event.Rune()) {
tv.PreferenceView.MainFocus()
return nil
}
return event
}
func (tv *TutView) InputCmdView(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyEnter:

25
ui/open.go

@ -5,6 +5,7 @@ import (
"os"
"os/exec"
"strings"
"unicode/utf8"
)
func openURL(tv *TutView, url string) {
@ -51,6 +52,30 @@ func openCustom(tv *TutView, program string, args []string, terminal bool, url s
}
}
func OpenEditorLengthLimit(tv *TutView, s string, limit int) (string, bool, error) {
text, err := OpenEditor(tv, s)
if err != nil {
return text, false, err
}
s = strings.TrimSpace(text)
if len(s) == 0 {
return "", false, nil
}
if utf8.RuneCountInString(s) > limit {
ns := ""
i := 0
for _, r := range s {
if i >= limit {
break
}
ns += string(r)
i++
}
s = ns
}
return s, true, nil
}
func OpenEditor(tv *TutView, content string) (string, error) {
editor, exists := os.LookupEnv("EDITOR")
if !exists || editor == "" {

27
ui/pollview.go

@ -3,7 +3,6 @@ package ui
import (
"fmt"
"strings"
"unicode/utf8"
"github.com/RasmusLindroth/go-mastodon"
"github.com/RasmusLindroth/tut/config"
@ -130,39 +129,18 @@ func (p *PollView) Next() {
}
}
func checkOption(s string) (string, bool) {
s = strings.TrimSpace(s)
if len(s) == 0 {
return "", false
}
if utf8.RuneCountInString(s) > 25 {
ns := ""
i := 0
for _, r := range s {
if i >= 25 {
break
}
ns += string(r)
i++
}
s = ns
}
return s, true
}
func (p *PollView) Add() {
if p.list.GetItemCount() > 3 {
p.tutView.ShowError("You can only have a maximum of 4 options.")
return
}
text, err := OpenEditor(p.tutView, "")
text, valid, err := OpenEditorLengthLimit(p.tutView, "", 25)
if err != nil {
p.tutView.ShowError(
fmt.Sprintf("Couldn't open editor. Error: %v", err),
)
return
}
text, valid := checkOption(text)
if !valid {
return
}
@ -177,14 +155,13 @@ func (p *PollView) Edit() {
return
}
text, _ := p.list.GetItemText(p.list.GetCurrentItem())
text, err := OpenEditor(p.tutView, text)
text, valid, err := OpenEditorLengthLimit(p.tutView, text, 25)
if err != nil {
p.tutView.ShowError(
fmt.Sprintf("Couldn't open editor. Error: %v", err),
)
return
}
text, valid := checkOption(text)
if !valid {
return
}

356
ui/preferenceview.go

@ -0,0 +1,356 @@
package ui
import (
"fmt"
"strings"
"github.com/RasmusLindroth/go-mastodon"
"github.com/RasmusLindroth/tut/config"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
var visibilitiesPrefStr = []string{
mastodon.VisibilityPublic,
mastodon.VisibilityUnlisted,
mastodon.VisibilityFollowersOnly,
}
type preferences struct {
displayname string
bio string
fields []mastodon.Field
visibility string
}
type PreferenceView struct {
tutView *TutView
shared *Shared
View *tview.Flex
displayName *tview.TextView
bio *tview.TextView
fields *tview.List
visibility *tview.DropDown
controls *tview.TextView
preferences *preferences
fieldFocus bool
}
func NewPreferenceView(tv *TutView) *PreferenceView {
p := &PreferenceView{
tutView: tv,
shared: tv.Shared,
displayName: NewTextView(tv.tut.Config),
bio: NewTextView(tv.tut.Config),
fields: NewList(tv.tut.Config),
visibility: NewDropDown(tv.tut.Config),
controls: NewTextView(tv.tut.Config),
preferences: &preferences{},
}
p.View = preferenceViewUI(p)
p.MainFocus()
p.Update()
return p
}
func preferenceViewUI(p *PreferenceView) *tview.Flex {
p.visibility.SetLabel("Default toot visibility: ")
p.visibility.SetOptions(visibilitiesPrefStr, p.visibilitySelected)
return tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(p.shared.Top.View, 1, 0, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexColumn).
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(p.displayName, 1, 0, false).
AddItem(p.visibility, 2, 0, false).
AddItem(p.fields, 0, 1, false), 0, 1, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(p.bio, 0, 1, false), 0, 1, false), 0, 1, false).
AddItem(p.controls, 1, 0, false).
AddItem(p.shared.Bottom.View, 2, 0, false)
}
func (p *PreferenceView) Update() {
pf := &preferences{}
me := p.tutView.tut.Client.Me
pf.displayname = me.DisplayName
if me.Source != nil {
if me.Source.Note != nil {
pf.bio = *me.Source.Note
}
if me.Source.Fields != nil {
for _, f := range *me.Source.Fields {
pf.fields = append(pf.fields, mastodon.Field{
Name: f.Name,
Value: f.Value,
})
}
}
if me.Source.Privacy != nil {
pf.visibility = *me.Source.Privacy
}
}
p.preferences = pf
p.update()
}
func (p *PreferenceView) update() {
pf := p.preferences
p.displayName.SetText(fmt.Sprintf("Display name: %s", tview.Escape(pf.displayname)))
p.bio.SetText(fmt.Sprintf("Bio:\n%s", tview.Escape(pf.bio)))
p.fields.Clear()
for _, f := range pf.fields {
p.fields.AddItem(fmt.Sprintf("%s: %s\n", tview.Escape(f.Name), tview.Escape(f.Value)), "", 0, nil)
}
index := 0
for i, v := range visibilitiesPrefStr {
if pf.visibility == v {
index = i
break
}
}
p.visibility.SetCurrentOption(index)
}
func (p *PreferenceView) HasFieldFocus() bool {
return p.fieldFocus
}
func (p *PreferenceView) FieldFocus() {
p.fieldFocus = true
var items []string
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFieldsAdd, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFieldsEdit, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFieldsDelete, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.GlobalBack, true))
p.controls.SetText(strings.Join(items, " "))
cnf := p.tutView.tut.Config
p.fields.SetSelectedBackgroundColor(cnf.Style.ListSelectedBackground)
p.fields.SetSelectedTextColor(cnf.Style.ListSelectedText)
}
func (p *PreferenceView) MainFocus() {
p.fieldFocus = false
var items []string
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceName, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceVisibility, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceBio, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFields, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceSave, true))
p.controls.SetText(strings.Join(items, " "))
cnf := p.tutView.tut.Config
p.fields.SetSelectedBackgroundColor(cnf.Style.Background)
p.fields.SetSelectedTextColor(cnf.Style.Text)
}
func (p *PreferenceView) PrevField() {
index := p.fields.GetCurrentItem()
if index-1 >= 0 {
p.fields.SetCurrentItem(index - 1)
}
}
func (p *PreferenceView) NextField() {
index := p.fields.GetCurrentItem()
if index+1 < p.fields.GetItemCount() {
p.fields.SetCurrentItem(index + 1)
}
}
func (p *PreferenceView) AddField() {
if p.fields.GetItemCount() > 3 {
p.tutView.ShowError("You can have a maximum of four fields.")
return
}
name, valid, err := OpenEditorLengthLimit(p.tutView, "name", 255)
if err != nil {
p.tutView.ShowError(
fmt.Sprintf("Couldn't add name. Error: %v\n", err),
)
return
}
if !valid {
p.tutView.ShowError("Name can't be empty.")
return
}
value, valid, err := OpenEditorLengthLimit(p.tutView, "value", 255)
if err != nil {
p.tutView.ShowError(
fmt.Sprintf("Couldn't add value. Error: %v\n", err),
)
return
}
if !valid {
p.tutView.ShowError("Value can't be empty.")
return
}
field := mastodon.Field{
Name: name,
Value: value,
}
p.preferences.fields = append(p.preferences.fields, field)
p.update()
p.fields.SetCurrentItem(p.fields.GetItemCount() - 1)
}
func (p *PreferenceView) EditField() {
if p.fields.GetItemCount() == 0 {
return
}
index := p.fields.GetCurrentItem()
if index < 0 || index >= len(p.preferences.fields) {
return
}
curr := p.preferences.fields[index]
name, valid, err := OpenEditorLengthLimit(p.tutView, curr.Name, 255)
if err != nil {
p.tutView.ShowError(
fmt.Sprintf("Couldn't edit name. Error: %v\n", err),
)
return
}
if !valid {
p.tutView.ShowError("Name can't be empty.")
return
}
value, valid, err := OpenEditorLengthLimit(p.tutView, curr.Value, 255)
if err != nil {
p.tutView.ShowError(
fmt.Sprintf("Couldn't edit value. Error: %v\n", err),
)
return
}
if !valid {
p.tutView.ShowError("Value can't be empty.")
return
}
field := mastodon.Field{
Name: name,
Value: value,
}
p.preferences.fields[index] = field
p.update()
}
func (p *PreferenceView) DeleteField() {
if p.fields.GetItemCount() == 0 {
return
}
index := p.fields.GetCurrentItem()
if index < 0 || index >= len(p.preferences.fields) {
return
}
p.fields.RemoveItem(index)
p.preferences.fields = append(p.preferences.fields[:index], p.preferences.fields[index+1:]...)
p.update()
}
func (p *PreferenceView) EditBio() {
bio := p.preferences.bio
text, _, err := OpenEditorLengthLimit(p.tutView, bio, 500)
if err != nil {
p.tutView.ShowError(
fmt.Sprintf("Couldn't edit bio. Error: %v\n", err),
)
return
}
p.preferences.bio = text
p.update()
}
func (p *PreferenceView) EditDisplayname() {
dn := p.preferences.displayname
text, _, err := OpenEditorLengthLimit(p.tutView, dn, 30)
if err != nil {
p.tutView.ShowError(
fmt.Sprintf("Couldn't edit display name. Error: %v\n", err),
)
return
}
p.preferences.displayname = text
p.update()
}
func (p *PreferenceView) visibilityInput(event *tcell.EventKey) *tcell.EventKey {
if p.tutView.tut.Config.Input.GlobalDown.Match(event.Key(), event.Rune()) {
return tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone)
}
if p.tutView.tut.Config.Input.GlobalUp.Match(event.Key(), event.Rune()) {
return tcell.NewEventKey(tcell.KeyUp, 0, tcell.ModNone)
}
if p.tutView.tut.Config.Input.GlobalExit.Match(event.Key(), event.Rune()) ||
p.tutView.tut.Config.Input.GlobalBack.Match(event.Key(), event.Rune()) {
p.exitVisibility()
return nil
}
return event
}
func (p *PreferenceView) exitVisibility() {
p.tutView.tut.App.SetInputCapture(p.tutView.Input)
p.tutView.tut.App.SetFocus(p.tutView.View)
}
func (p *PreferenceView) visibilitySelected(s string, index int) {
_, p.preferences.visibility = p.visibility.GetCurrentOption()
p.exitVisibility()
}
func (p *PreferenceView) FocusVisibility() {
p.tutView.tut.App.SetInputCapture(p.visibilityInput)
p.tutView.tut.App.SetFocus(p.visibility)
ev := tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone)
p.tutView.tut.App.QueueEvent(ev)
}
func (p *PreferenceView) Save() {
og := &preferences{}
me := p.tutView.tut.Client.Me
og.displayname = me.DisplayName
if me.Source != nil {
if me.Source.Note != nil {
og.bio = *me.Source.Note
}
if me.Source.Fields != nil {
for _, f := range *me.Source.Fields {
og.fields = append(og.fields, mastodon.Field{
Name: f.Name,
Value: f.Value,
})
}
}
if me.Source.Privacy != nil {
og.visibility = *me.Source.Privacy
}
}
profile := mastodon.Profile{
Source: &mastodon.AccountSource{},
}
if og.displayname != p.preferences.displayname {
profile.DisplayName = &p.preferences.displayname
}
if og.bio != p.preferences.bio {
profile.Note = &p.preferences.bio
}
if og.visibility != p.preferences.visibility {
profile.Source.Privacy = &p.preferences.visibility
}
profile.Fields = &p.preferences.fields
err := p.tutView.tut.Client.SavePreferences(&profile)
if err != nil {
p.tutView.ShowError(
fmt.Sprintf("Couldn't update preferences. Error: %v\n", err),
)
return
}
p.tutView.SetPage(MainFocus)
}

3
ui/statusbar.go

@ -31,6 +31,7 @@ const (
UserMode
VoteMode
PollMode
PreferenceMode
)
func (sb *StatusBar) SetMode(m ViewMode) {
@ -61,5 +62,7 @@ func (sb *StatusBar) SetMode(m ViewMode) {
sb.View.SetText("-- SELECT USER --")
case PollMode:
sb.View.SetText("-- CREATE POLL --")
case PreferenceMode:
sb.View.SetText("-- PREFERENCES --")
}
}

19
ui/tutview.go

@ -45,14 +45,15 @@ type TutView struct {
Shared *Shared
View *tview.Pages
LoginView *LoginView
MainView *MainView
LinkView *LinkView
ComposeView *ComposeView
VoteView *VoteView
PollView *PollView
HelpView *HelpView
ModalView *ModalView
LoginView *LoginView
MainView *MainView
LinkView *LinkView
ComposeView *ComposeView
VoteView *VoteView
PollView *PollView
PreferenceView *PreferenceView
HelpView *HelpView
ModalView *ModalView
FileList []string
}
@ -163,6 +164,7 @@ func (tv *TutView) loggedIn(acc auth.Account) {
tv.ComposeView = NewComposeView(tv)
tv.VoteView = NewVoteView(tv)
tv.PollView = NewPollView(tv)
tv.PreferenceView = NewPreferenceView(tv)
tv.HelpView = NewHelpView(tv)
tv.ModalView = NewModalView(tv)
@ -172,6 +174,7 @@ func (tv *TutView) loggedIn(acc auth.Account) {
tv.View.AddPage("vote", tv.VoteView.View, true, false)
tv.View.AddPage("help", tv.HelpView.View, true, false)
tv.View.AddPage("poll", tv.PollView.View, true, false)
tv.View.AddPage("preference", tv.PreferenceView.View, true, false)
tv.View.AddPage("modal", tv.ModalView.View, true, false)
tv.SetPage(MainFocus)
}

9
ui/view.go

@ -20,6 +20,7 @@ const (
VoteFocus
HelpFocus
PollFocus
PreferenceFocus
)
func (tv *TutView) GetCurrentFeed() *Feed {
@ -143,7 +144,13 @@ func (tv *TutView) SetPage(f PageFocusAt) {
tv.tut.App.SetFocus(tv.View)
tv.Shared.Bottom.StatusBar.SetMode(PollMode)
tv.Shared.Top.SetText("create a poll")
case PreferenceFocus:
tv.PageFocus = PreferenceFocus
tv.PreferenceView.Update()
tv.View.SwitchToPage("preference")
tv.tut.App.SetFocus(tv.View)
tv.Shared.Bottom.StatusBar.SetMode(PreferenceMode)
tv.Shared.Top.SetText("preferences")
}
tv.ShouldSync()
}

Loading…
Cancel
Save