mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
Merge branch 'master' of github.com:3mard/wtf into 3mard-master
This commit is contained in:
commit
d62356f930
@ -40,6 +40,7 @@ import (
|
|||||||
"github.com/wtfutil/wtf/modules/newrelic"
|
"github.com/wtfutil/wtf/modules/newrelic"
|
||||||
"github.com/wtfutil/wtf/modules/opsgenie"
|
"github.com/wtfutil/wtf/modules/opsgenie"
|
||||||
"github.com/wtfutil/wtf/modules/pagerduty"
|
"github.com/wtfutil/wtf/modules/pagerduty"
|
||||||
|
"github.com/wtfutil/wtf/modules/pocket"
|
||||||
"github.com/wtfutil/wtf/modules/power"
|
"github.com/wtfutil/wtf/modules/power"
|
||||||
"github.com/wtfutil/wtf/modules/resourceusage"
|
"github.com/wtfutil/wtf/modules/resourceusage"
|
||||||
"github.com/wtfutil/wtf/modules/rollbar"
|
"github.com/wtfutil/wtf/modules/rollbar"
|
||||||
@ -202,6 +203,9 @@ func MakeWidget(
|
|||||||
case "prettyweather":
|
case "prettyweather":
|
||||||
settings := prettyweather.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
settings := prettyweather.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||||
widget = prettyweather.NewWidget(app, settings)
|
widget = prettyweather.NewWidget(app, settings)
|
||||||
|
case "pocket":
|
||||||
|
settings := pocket.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||||
|
widget = pocket.NewWidget(app, pages, settings)
|
||||||
case "resourceusage":
|
case "resourceusage":
|
||||||
settings := resourceusage.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
settings := resourceusage.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||||
widget = resourceusage.NewWidget(app, settings)
|
widget = resourceusage.NewWidget(app, settings)
|
||||||
|
261
modules/pocket/client.go
Normal file
261
modules/pocket/client.go
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
package pocket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client pocket client Documention at https://getpocket.com/developer/docs/overview
|
||||||
|
type Client struct {
|
||||||
|
consumerKey string
|
||||||
|
accessToken *string
|
||||||
|
baseURL string
|
||||||
|
redirectURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewClient returns a new PocketClient
|
||||||
|
func NewClient(consumerKey, redirectURL string) *Client {
|
||||||
|
return &Client{
|
||||||
|
consumerKey: consumerKey,
|
||||||
|
redirectURL: redirectURL,
|
||||||
|
baseURL: "https://getpocket.com/v3",
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Item represents link in pocket api
|
||||||
|
type Item struct {
|
||||||
|
ItemID string `json:"item_id"`
|
||||||
|
ResolvedID string `json:"resolved_id"`
|
||||||
|
GivenURL string `json:"given_url"`
|
||||||
|
GivenTitle string `json:"given_title"`
|
||||||
|
Favorite string `json:"favorite"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
TimeAdded string `json:"time_added"`
|
||||||
|
TimeUpdated string `json:"time_updated"`
|
||||||
|
TimeRead string `json:"time_read"`
|
||||||
|
TimeFavorited string `json:"time_favorited"`
|
||||||
|
SortID int `json:"sort_id"`
|
||||||
|
ResolvedTitle string `json:"resolved_title"`
|
||||||
|
ResolvedURL string `json:"resolved_url"`
|
||||||
|
Excerpt string `json:"excerpt"`
|
||||||
|
IsArticle string `json:"is_article"`
|
||||||
|
IsIndex string `json:"is_index"`
|
||||||
|
HasVideo string `json:"has_video"`
|
||||||
|
HasImage string `json:"has_image"`
|
||||||
|
WordCount string `json:"word_count"`
|
||||||
|
Lang string `json:"lang"`
|
||||||
|
TimeToRead int `json:"time_to_read"`
|
||||||
|
TopImageURL string `json:"top_image_url"`
|
||||||
|
ListenDurationEstimate int `json:"listen_duration_estimate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//ItemLists represent list of links
|
||||||
|
type ItemLists struct {
|
||||||
|
Status int `json:"status"`
|
||||||
|
Complete int `json:"complete"`
|
||||||
|
List map[string]Item `json:"list"`
|
||||||
|
Since int `json:"since"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type request struct {
|
||||||
|
requestBody interface{}
|
||||||
|
method string
|
||||||
|
result interface{}
|
||||||
|
headers map[string]string
|
||||||
|
url string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) request(req request, result interface{}) error {
|
||||||
|
jsonValues, err := json.Marshal(req.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
request, err := http.NewRequest(req.method, req.url, bytes.NewBuffer(jsonValues))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range req.headers {
|
||||||
|
request.Header.Add(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(request)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
responseBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf(`server responded with [%d]:%s,url:%s`, resp.StatusCode, responseBody, req.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(responseBody, &result); err != nil {
|
||||||
|
return fmt.Errorf(`Could not unmarshal url [%s]
|
||||||
|
response [%s] request[%s] error:%v`, req.url, responseBody, jsonValues, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type obtainRequestTokenRequest struct {
|
||||||
|
ConsumerKey string `json:"consumer_key"`
|
||||||
|
RedirectURI string `json:"redirect_uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//ObtainRequestToken get request token to be used in the auth workflow
|
||||||
|
func (client *Client) ObtainRequestToken() (code string, err error) {
|
||||||
|
url := fmt.Sprintf("%s/oauth/request", client.baseURL)
|
||||||
|
requestData := obtainRequestTokenRequest{ConsumerKey: client.consumerKey, RedirectURI: client.redirectURL}
|
||||||
|
|
||||||
|
var responseData map[string]string
|
||||||
|
req := request{
|
||||||
|
method: "POST",
|
||||||
|
url: url,
|
||||||
|
requestBody: requestData,
|
||||||
|
}
|
||||||
|
req.headers = map[string]string{
|
||||||
|
"X-Accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
err = client.request(req, &responseData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return code, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseData["code"], nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//CreateAuthLink create authorization link to redirect the user to
|
||||||
|
func (client *Client) CreateAuthLink(requestToken string) string {
|
||||||
|
return fmt.Sprintf("https://getpocket.com/auth/authorize?request_token=%s&redirect_uri=%s", requestToken, client.redirectURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
type accessTokenRequest struct {
|
||||||
|
ConsumerKey string `json:"consumer_key"`
|
||||||
|
RequestCode string `json:"code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// accessTokenResponse represents
|
||||||
|
type accessTokenResponse struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetAccessToken exchange request token for accesstoken
|
||||||
|
func (client *Client) GetAccessToken(requestToken string) (accessToken string, err error) {
|
||||||
|
url := fmt.Sprintf("%s/oauth/authorize", client.baseURL)
|
||||||
|
requestData := accessTokenRequest{
|
||||||
|
ConsumerKey: client.consumerKey,
|
||||||
|
RequestCode: requestToken,
|
||||||
|
}
|
||||||
|
req := request{
|
||||||
|
method: "POST",
|
||||||
|
url: url,
|
||||||
|
requestBody: requestData,
|
||||||
|
}
|
||||||
|
req.headers = map[string]string{
|
||||||
|
"X-Accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
var response accessTokenResponse
|
||||||
|
err = client.request(req, &response)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return response.AccessToken, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*LinkState represents links states to be retrived
|
||||||
|
According to the api https://getpocket.com/developer/docs/v3/retrieve
|
||||||
|
there are 3 states:
|
||||||
|
1-archive
|
||||||
|
2-unread
|
||||||
|
3-all
|
||||||
|
however archive does not really well work and returns links that are in the
|
||||||
|
unread list
|
||||||
|
buy inspecting getpocket I found out that there is an undocumanted read state
|
||||||
|
*/
|
||||||
|
type LinkState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
//Read links that has been read (undocumanted)
|
||||||
|
Read LinkState = "read"
|
||||||
|
//Unread links has not been read
|
||||||
|
Unread LinkState = "unread"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetLinks retrive links of a given states https://getpocket.com/developer/docs/v3/retrieve
|
||||||
|
func (client *Client) GetLinks(state LinkState) (response ItemLists, err error) {
|
||||||
|
url := fmt.Sprintf("%s/get?sort=newest&state=%s&consumer_key=%s&access_token=%s", client.baseURL, state, client.consumerKey, *client.accessToken)
|
||||||
|
req := request{
|
||||||
|
method: "GET",
|
||||||
|
url: url,
|
||||||
|
}
|
||||||
|
req.headers = map[string]string{
|
||||||
|
"X-Accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.request(req, &response)
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Action represents a mutation to link
|
||||||
|
type Action string
|
||||||
|
|
||||||
|
const (
|
||||||
|
//Archive to put the link in the archived list (read list)
|
||||||
|
Archive Action = "archive"
|
||||||
|
//ReAdd to put the link back in the to reed list
|
||||||
|
ReAdd Action = "readd"
|
||||||
|
)
|
||||||
|
|
||||||
|
type actionParams struct {
|
||||||
|
Action Action `json:"action"`
|
||||||
|
ItemID string `json:"item_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//ModifyLink change the state of the link
|
||||||
|
func (client *Client) ModifyLink(action Action, itemID string) (ok bool, err error) {
|
||||||
|
|
||||||
|
actions := []actionParams{
|
||||||
|
{
|
||||||
|
Action: action,
|
||||||
|
ItemID: itemID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
urlActionParm, err := json.Marshal(actions)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("%s/send?consumer_key=%s&access_token=%s&actions=%s", client.baseURL, client.consumerKey, *client.accessToken, urlActionParm)
|
||||||
|
|
||||||
|
req := request{
|
||||||
|
method: "GET",
|
||||||
|
url: url,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.request(req, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
|
||||||
|
}
|
19
modules/pocket/item_service.go
Normal file
19
modules/pocket/item_service.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package pocket
|
||||||
|
|
||||||
|
import "sort"
|
||||||
|
|
||||||
|
type sortByTimeAdded []Item
|
||||||
|
|
||||||
|
func (a sortByTimeAdded) Len() int { return len(a) }
|
||||||
|
func (a sortByTimeAdded) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
func (a sortByTimeAdded) Less(i, j int) bool { return a[i].TimeAdded > a[j].TimeAdded }
|
||||||
|
|
||||||
|
func orderItemResponseByKey(response ItemLists) []Item {
|
||||||
|
|
||||||
|
var items sortByTimeAdded
|
||||||
|
for _, v := range response.List {
|
||||||
|
items = append(items, v)
|
||||||
|
}
|
||||||
|
sort.Sort(items)
|
||||||
|
return items
|
||||||
|
}
|
13
modules/pocket/keyboard.go
Normal file
13
modules/pocket/keyboard.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package pocket
|
||||||
|
|
||||||
|
import "github.com/gdamore/tcell"
|
||||||
|
|
||||||
|
func (widget *Widget) initializeKeyboardControls() {
|
||||||
|
|
||||||
|
widget.InitializeCommonControls(widget.Refresh)
|
||||||
|
widget.SetKeyboardChar("a", widget.toggleLink, "Toggle Link")
|
||||||
|
widget.SetKeyboardChar("t", widget.toggleView, "Toggle view (links ,archived links)")
|
||||||
|
widget.SetKeyboardKey(tcell.KeyDown, widget.Next, "Select Next Link")
|
||||||
|
widget.SetKeyboardKey(tcell.KeyUp, widget.Prev, "Select Previous Link")
|
||||||
|
widget.SetKeyboardKey(tcell.KeyEnter, widget.openLink, "Open Link in the browser")
|
||||||
|
}
|
27
modules/pocket/settings.go
Normal file
27
modules/pocket/settings.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package pocket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/olebedev/config"
|
||||||
|
"github.com/wtfutil/wtf/cfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultFocusable = true
|
||||||
|
defaultTitle = "Pocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Settings struct {
|
||||||
|
common *cfg.Common
|
||||||
|
consumerKey string
|
||||||
|
requestKey *string
|
||||||
|
accessToken *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *config.Config) *Settings {
|
||||||
|
settings := Settings{
|
||||||
|
common: cfg.NewCommonSettingsFromModule(name, defaultTitle, defaultFocusable, ymlConfig, globalConfig),
|
||||||
|
consumerKey: ymlConfig.UString("consumerKey"),
|
||||||
|
}
|
||||||
|
|
||||||
|
return &settings
|
||||||
|
}
|
232
modules/pocket/widget.go
Normal file
232
modules/pocket/widget.go
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
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
|
||||||
|
view.KeyboardWidget
|
||||||
|
|
||||||
|
settings *Settings
|
||||||
|
client *Client
|
||||||
|
items []Item
|
||||||
|
archivedView bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
|
||||||
|
widget := Widget{
|
||||||
|
KeyboardWidget: view.NewKeyboardWidget(app, pages, settings.common),
|
||||||
|
ScrollableWidget: view.NewScrollableWidget(app, settings.common),
|
||||||
|
settings: settings,
|
||||||
|
client: NewClient(settings.consumerKey, "http://localhost"),
|
||||||
|
archivedView: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.CommonSettings()
|
||||||
|
widget.View.SetInputCapture(widget.InputCapture)
|
||||||
|
widget.SetRenderFunction(widget.Render)
|
||||||
|
widget.View.SetScrollable(true)
|
||||||
|
widget.View.SetRegions(true)
|
||||||
|
widget.KeyboardWidget.SetView(widget.View)
|
||||||
|
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 == true {
|
||||||
|
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 %v", 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 == true {
|
||||||
|
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.common.Colors.RowTheme.EvenForeground, widget.settings.common.Colors.RowTheme.EvenBackground
|
||||||
|
text := item.ResolvedTitle
|
||||||
|
if isSelected == true {
|
||||||
|
foreColor = widget.settings.common.Colors.RowTheme.HighlightedForeground
|
||||||
|
backColor = widget.settings.common.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 == true {
|
||||||
|
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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user