Skip to content

Commit

Permalink
feat: searchable articles
Browse files Browse the repository at this point in the history
internal restructuring of navigation module
  • Loading branch information
zMoooooritz committed Oct 6, 2024
1 parent 0fb5136 commit e238422
Show file tree
Hide file tree
Showing 17 changed files with 752 additions and 335 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ The default keybinds are as follows:
| arrows / hjkl | navigation |
| g / G | goto start / end |
| tab / shift+tab | change tabs |
| pgup / pgdown | page up / down |
| / | open search dialog |
| enter | confirm search input |
| esc | abort search input |
| f | maximize reader/viewer |
| a | show article view |
| i | show thumbnail view |
Expand Down
14 changes: 13 additions & 1 deletion configs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Settings:
HideHelpOnStartup: true
PreloadThumbnails: true
SelectorWidth: 0.3
NavigatorWidth: 0.3

# Configuration of keybinds used in the application
Keys:
Expand Down Expand Up @@ -31,6 +31,18 @@ Keys:
End:
- G
- end
PageUp:
- ctrl+b
- pgup
PageDown:
- ctrl+f
- pgdown
Search:
- "/"
Confirm:
- enter
Escape:
- esc
Quit:
- q
- esc
Expand Down
14 changes: 12 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type Configuration struct {
type Settings struct {
HideHelpOnStartup bool `yaml:"HideHelpOnStartup"`
PreloadThumbnails bool `yaml:"PreloadThumbnails"`
SelectorWidth float32 `yaml:"SelectorWidth"`
NavigatorWidth float32 `yaml:"NavigatorWidth"`
}

type Keys struct {
Expand All @@ -30,6 +30,11 @@ type Keys struct {
Full []string `yaml:"Full"`
Start []string `yaml:"Start"`
End []string `yaml:"End"`
PageUp []string `yaml:"PageUp"`
PageDown []string `yaml:"PageDown"`
Search []string `yaml:"Search"`
Confirm []string `yaml:"Confirm"`
Escape []string `yaml:"Escape"`
Quit []string `yaml:"Quit"`
ShowArticle []string `yaml:"ShowArticle"`
ShowThumbnail []string `yaml:"ShowThumbnail"`
Expand Down Expand Up @@ -88,7 +93,7 @@ func defaultConfiguration() Configuration {
Settings: Settings{
HideHelpOnStartup: false,
PreloadThumbnails: false,
SelectorWidth: 0.3,
NavigatorWidth: 0.3,
},
Keys: defaultKeys(),
Applications: Applications{},
Expand All @@ -108,6 +113,11 @@ func defaultKeys() Keys {
Start: []string{"g", "home"},
End: []string{"G", "end"},
Quit: []string{"q", "esc", "ctrl+c"},
PageUp: []string{"ctrl+b", "pgup"},
PageDown: []string{"ctrl+f", "pgdown"},
Search: []string{"/"},
Confirm: []string{"enter"},
Escape: []string{"esc"},
ShowArticle: []string{"a"},
ShowThumbnail: []string{"i"},
ShowDetails: []string{"d"},
Expand Down
40 changes: 38 additions & 2 deletions pkg/tagesschau/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import (

const (
baseUrl string = "https://www.tagesschau.de/"
apiUrl string = baseUrl + "api2u/homepage"
homepageAPI string = baseUrl + "api2u/homepage/"
searchAPI string = baseUrl + "api2u/search/"
shortNewsUrl string = baseUrl + "multimedia/sendung/tagesschau_in_100_sekunden"
)

Expand All @@ -39,6 +40,14 @@ type News struct {
RegionalNews []Article `json:"regional"`
}

type SearchResult struct {
SearchText string `json:"searchText"`
PageSize int `json:"pageSize"`
ResultPage int `json:"resultPage"`
TotalItemCount int `json:"totalItemCount"`
Articles []Article `json:"searchResults"`
}

type Article struct {
Topline string `json:"topline"`
Desc string `json:"title"`
Expand Down Expand Up @@ -125,7 +134,7 @@ func RegionIdToName(id int) (string, error) {

func LoadNews() (News, error) {
var news News
body, err := http.FetchURL(apiUrl)
body, err := http.FetchURL(homepageAPI)
if err != nil {
return news, err
}
Expand All @@ -139,6 +148,23 @@ func LoadNews() (News, error) {
return news, nil
}

func SearchArticles(searchTerm string) (SearchResult, error) {
var result SearchResult

body, err := http.FetchURL(searchAPI + "?searchText=" + searchTerm)
if err != nil {
return result, err
}

err = json.Unmarshal(body, &result)
if err != nil {
return result, err
}
result.Articles = deduplicateArticles(result.Articles)
result.Articles = removeUnreadableArticles(result.Articles)
return result, nil
}

func LoadArticle(url string) (*Article, error) {
body, err := http.FetchURL(url)
if err != nil {
Expand Down Expand Up @@ -167,6 +193,16 @@ func deduplicateArticles(articles []Article) []Article {
return deduped
}

func removeUnreadableArticles(articles []Article) []Article {
cleaned := []Article{}
for _, article := range articles {
if len(article.Content) != 0 {
cleaned = append(cleaned, article)
}
}
return cleaned
}

func GetImageURL(variants ImageVariants, imageSpec ImageSpec) string {
sizeMap := map[ImageSpec]string{
{SMALL, RECT}: variants.RectSmall,
Expand Down
149 changes: 149 additions & 0 deletions pkg/tui/base_selector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package tui

import (
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/zMoooooritz/nachrichten/pkg/config"
"github.com/zMoooooritz/nachrichten/pkg/tagesschau"
)

type SelectorType int

const (
ST_NATIONAL SelectorType = iota
ST_REGIONAL
ST_SEARCH
)

type Selector interface {
GetSelectedArticle() tagesschau.Article
SelectorType() SelectorType
SetActive(bool)
IsActive() bool
SetFocused(bool)
IsFocused() bool
SetDims(int, int)
Init() tea.Cmd
Update(tea.Msg) (Selector, tea.Cmd)
View() string
}

type BaseSelector struct {
selectorType SelectorType
shared *SharedState
isActive bool
isFocused bool
width int
height int
articles []tagesschau.Article
list list.Model
selectedIndex int
}

func NewSelector(selectorType SelectorType, shared *SharedState, isActive bool) BaseSelector {
listKeymap := ListKeymap(shared.keys)
return BaseSelector{
shared: shared,
selectorType: selectorType,
isActive: isActive,
isFocused: isActive,
list: initList(shared.style, listKeymap),
selectedIndex: 0,
}
}
func initList(s config.Style, km list.KeyMap) list.Model {
lst := list.New([]list.Item{}, NewNewsDelegate(s), 0, 0)
lst.SetFilteringEnabled(false)
lst.SetShowTitle(false)
lst.SetShowStatusBar(false)
lst.SetShowHelp(false)
lst.KeyMap = km
return lst
}

func (s *BaseSelector) rebuildList() {
var items []list.Item
for _, article := range s.articles {
items = append(items, article)
}
s.list.SetItems(items)
s.list.Select(0)
s.selectedIndex = 0
}

func (s BaseSelector) pushCurrentArticle() tea.Cmd {
return func() tea.Msg {
return ChangedActiveArticle(s.GetSelectedArticle())
}
}

func (s BaseSelector) SelectorType() SelectorType {
return s.selectorType
}

func (s *BaseSelector) GetSelectedArticle() tagesschau.Article {
return s.articles[s.selectedIndex]
}

func (s *BaseSelector) SetActive(isActive bool) {
s.isActive = isActive
}

func (s *BaseSelector) IsActive() bool {
return s.isActive
}

func (s *BaseSelector) SetFocused(isFocused bool) {
s.isFocused = isFocused
}

func (s *BaseSelector) IsFocused() bool {
return s.isFocused
}

func (s *BaseSelector) SetDims(w, h int) {
s.width = w
s.height = h
}

func (s BaseSelector) Init() tea.Cmd {
return nil
}

func (s BaseSelector) Update(msg tea.Msg) (BaseSelector, tea.Cmd) {
var (
cmds []tea.Cmd
)

switch msg := msg.(type) {
case tea.KeyMsg:
if s.shared.mode == INSERT_MODE {
break
}

switch {
case key.Matches(msg, s.shared.keymap.right):
if s.isActive {
s.isFocused = false
}
case key.Matches(msg, s.shared.keymap.left):
if s.isActive {
s.isFocused = true
}
}
}

if s.list.Index() != s.selectedIndex {
s.selectedIndex = s.list.Index()
cmds = append(cmds, s.pushCurrentArticle())
}

return s, tea.Batch(cmds...)
}

func (s BaseSelector) View() string {
s.list.SetSize(s.width, s.height)

return s.list.View()
}
Loading

0 comments on commit e238422

Please sign in to comment.