1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00
wtf/modules/pocket/widget.go
Chris Cummer fd794707cd
☢️ WTF-1031 Support multiple simultaneous configurations (#1032)
* WTF-1031 Rename WtfApp.app to WtfApp.tviewApp

Signed-off-by: Chris Cummer <chriscummer@me.com>

* WTF-1031 Add scaffolding for main to support multiple WtfApp instances

Signed-off-by: Chris Cummer <chriscummer@me.com>

* WTF-1031 WIP

Signed-off-by: Chris Cummer <chriscummer@me.com>

* Remove common functionality from KeyboardWidget and into Base

Signed-off-by: Chris Cummer <chriscummer@me.com>

* Augment with some descriptive comments

Signed-off-by: Chris Cummer <chriscummer@me.com>

* Add full support for multiple app instances via the AppManager.

Still to do:

* Config support for multiple apps/multiple config files
* The ability to switch between apps

Signed-off-by: Chris Cummer <chriscummer@me.com>

* Move SetTerminal out of main and into its own file

Signed-off-by: Chris Cummer <chriscummer@me.com>
2020-12-21 03:25:41 -08:00

229 lines
5.5 KiB
Go

package pocket
import (
"fmt"
"io/ioutil"
"github.com/rivo/tview"
"github.com/wtfutil/wtf/cfg"
"github.com/wtfutil/wtf/logger"
"github.com/wtfutil/wtf/utils"
"github.com/wtfutil/wtf/view"
"gopkg.in/yaml.v2"
)
type Widget struct {
view.ScrollableWidget
settings *Settings
client *Client
items []Item
archivedView bool
}
func NewWidget(tviewApp *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
ScrollableWidget: view.NewScrollableWidget(tviewApp, nil, settings.Common),
settings: settings,
client: NewClient(settings.consumerKey, "http://localhost"),
archivedView: false,
}
widget.CommonSettings()
widget.SetRenderFunction(widget.Render)
widget.View.SetScrollable(true)
widget.View.SetRegions(true)
widget.initializeKeyboardControls()
widget.Selected = -1
widget.SetItemCount(0)
return &widget
}
/* -------------------- Exported Functions -------------------- */
func (widget *Widget) Render() {
widget.Redraw(widget.content)
}
func (widget *Widget) Refresh() {
if widget.client.accessToken == nil {
metaData, err := readMetaDataFromDisk()
if err != nil || metaData.AccessToken == nil {
widget.Redraw(widget.authorizeWorkFlow)
return
}
widget.client.accessToken = metaData.AccessToken
}
state := Unread
if widget.archivedView {
state = Read
}
response, err := widget.client.GetLinks(state)
if err != nil {
widget.SetItemCount(0)
}
widget.items = orderItemResponseByKey(response)
widget.SetItemCount(len(widget.items))
widget.Redraw(widget.content)
}
/* -------------------- Unexported Functions -------------------- */
type pocketMetaData struct {
AccessToken *string
}
func writeMetaDataToDisk(metaData pocketMetaData) error {
fileData, err := yaml.Marshal(metaData)
if err != nil {
return fmt.Errorf("could not write token to disk %w", err)
}
wtfConfigDir, err := cfg.WtfConfigDir()
if err != nil {
return nil
}
filePath := fmt.Sprintf("%s/%s", wtfConfigDir, "pocket.data")
err = ioutil.WriteFile(filePath, fileData, 0644)
return err
}
func readMetaDataFromDisk() (pocketMetaData, error) {
wtfConfigDir, err := cfg.WtfConfigDir()
var metaData pocketMetaData
if err != nil {
return metaData, err
}
filePath := fmt.Sprintf("%s/%s", wtfConfigDir, "pocket.data")
fileData, err := utils.ReadFileBytes(filePath)
if err != nil {
return metaData, err
}
err = yaml.Unmarshal(fileData, &metaData)
return metaData, err
}
/*
Authorization workflow is documented at https://getpocket.com/developer/docs/authentication
broken to 4 steps :
1- Obtain a platform consumer key from http://getpocket.com/developer/apps/new.
2- Obtain a request token
3- Redirect user to Pocket to continue authorization
4- Receive the callback from Pocket, this wont be used
5- Convert a request token into a Pocket access token
*/
func (widget *Widget) authorizeWorkFlow() (string, string, bool) {
title := widget.CommonSettings().Title
if widget.settings.requestKey == nil {
requestToken, err := widget.client.ObtainRequestToken()
if err != nil {
logger.Log(err.Error())
return title, err.Error(), true
}
widget.settings.requestKey = &requestToken
redirectURL := widget.client.CreateAuthLink(requestToken)
content := fmt.Sprintf("Please click on %s to Authorize the app", redirectURL)
return title, content, true
}
if widget.settings.accessToken == nil {
accessToken, err := widget.client.GetAccessToken(*widget.settings.requestKey)
if err != nil {
logger.Log(err.Error())
redirectURL := widget.client.CreateAuthLink(*widget.settings.requestKey)
content := fmt.Sprintf("Please click on %s to Authorize the app", redirectURL)
return title, content, true
}
content := "Authorized"
widget.settings.accessToken = &accessToken
metaData := pocketMetaData{
AccessToken: &accessToken,
}
err = writeMetaDataToDisk(metaData)
if err != nil {
content = err.Error()
}
return title, content, true
}
content := "Authorized"
return title, content, true
}
func (widget *Widget) toggleView() {
widget.archivedView = !widget.archivedView
widget.Refresh()
}
func (widget *Widget) openLink() {
sel := widget.GetSelected()
if sel >= 0 && widget.items != nil && sel < len(widget.items) {
item := &widget.items[sel]
utils.OpenFile(item.GivenURL)
}
}
func (widget *Widget) toggleLink() {
sel := widget.GetSelected()
action := Archive
if widget.archivedView {
action = ReAdd
}
if sel >= 0 && widget.items != nil && sel < len(widget.items) {
item := &widget.items[sel]
_, err := widget.client.ModifyLink(action, item.ItemID)
if err != nil {
logger.Log(err.Error())
}
}
widget.Refresh()
}
func (widget *Widget) formatItem(item Item, isSelected bool) string {
foreColor, backColor := widget.settings.Colors.RowTheme.EvenForeground, widget.settings.Colors.RowTheme.EvenBackground
text := item.ResolvedTitle
if isSelected {
foreColor = widget.settings.Colors.RowTheme.HighlightedForeground
backColor = widget.settings.Colors.RowTheme.HighlightedBackground
}
return fmt.Sprintf("[%s:%s]%s[white]", foreColor, backColor, tview.Escape(text))
}
func (widget *Widget) content() (string, string, bool) {
title := widget.CommonSettings().Title
currentViewTitle := "Reading List"
if widget.archivedView {
currentViewTitle = "Archived list"
}
title = fmt.Sprintf("%s-%s", title, currentViewTitle)
content := ""
for i, v := range widget.items {
content += widget.formatItem(v, i == widget.Selected) + "\n"
}
return title, content, false
}