Implemented conversation threading, fixed #6

pull/24/head
マリウス 3 years ago
parent 7d5da5d80c
commit 19adc94508
No known key found for this signature in database
GPG Key ID: 272ED814BF63261F

@ -214,8 +214,11 @@ func (db *Database) GetArticleByID(id string) (models.Article, error) {
return article, nil return article, nil
} }
func (db *Database) ListArticles() ([]models.Article, error) { func (db *Database) ListArticles() ([]*models.Article, []*models.Article, error) {
var articles []models.Article var articles []*models.Article
var articlesMap map[string]*models.Article
articlesMap = make(map[string]*models.Article)
_, err := db.Store.Query(db.ctx, func(e interface{})(bool, error) { _, err := db.Store.Query(db.ctx, func(e interface{})(bool, error) {
entity := e.(map[string]interface{}) entity := e.(map[string]interface{})
@ -223,20 +226,36 @@ func (db *Database) ListArticles() ([]models.Article, error) {
var article models.Article var article models.Article
err := mapstructure.Decode(entity, &article) err := mapstructure.Decode(entity, &article)
if err == nil { if err == nil {
articles = append(articles, article) // TODO: Not sure why mapstructure won't convert this field and simply
// leave it ""
if entity["in-reply-to-id"] != nil {
article.InReplyToID = entity["in-reply-to-id"].(string)
}
articles = append(articles, &article)
articlesMap[article.ID] = articles[(len(articles) - 1)]
} }
return true, err return true, err
} }
return false, nil return false, nil
}) })
if err != nil { if err != nil {
return articles, err return articles, nil, err
} }
sort.SliceStable(articles, func(i, j int) bool { sort.SliceStable(articles, func(i, j int) bool {
return articles[i].Date > articles[j].Date return articles[i].Date > articles[j].Date
}) })
return articles, nil var articlesRoots []*models.Article
for i := 0; i < len(articles); i++ {
if articles[i].InReplyToID != "" {
(*articlesMap[articles[i].InReplyToID]).Replies =
append((*articlesMap[articles[i].InReplyToID]).Replies, articles[i])
} else {
articlesRoots = append(articlesRoots, articles[i])
}
}
return articles, articlesRoots, nil
} }

@ -16,6 +16,8 @@ type Article struct {
Date int64 `mmapstructure:"date" json:"date" validate:"required,number"` Date int64 `mmapstructure:"date" json:"date" validate:"required,number"`
Organization string `mmapstructure:"organization" json:"organization" validate:"printascii"` Organization string `mmapstructure:"organization" json:"organization" validate:"printascii"`
Body string `mmapstructure:"body" json:"body" validate:"required,min=3,max=524288"` Body string `mmapstructure:"body" json:"body" validate:"required,min=3,max=524288"`
Replies []*Article `mmapstructure:"-" json:"-" validate:"-"`
} }
func NewArticle() (*Article) { func NewArticle() (*Article) {

@ -42,10 +42,12 @@ func main() {
log.Panicln(err) log.Panicln(err)
} }
var articles []models.Article var articles []*models.Article
var articlesRoots []*models.Article
TUI := tui.Init(&EMBEDFS, cfg, logger) TUI := tui.Init(&EMBEDFS, cfg, logger)
TUI.ArticlesDatasource = &articles TUI.ArticlesDatasource = &articles
TUI.ArticlesRoots = &articlesRoots
db, err := database.NewDatabase(ctx, cfg.ConnectionString, cfg.CachePath, logger) db, err := database.NewDatabase(ctx, cfg.ConnectionString, cfg.CachePath, logger)
if err != nil { if err != nil {
@ -54,7 +56,7 @@ func main() {
defer db.Disconnect() defer db.Disconnect()
TUI.CallbackRefreshArticles = func() (error) { TUI.CallbackRefreshArticles = func() (error) {
articles, err = db.ListArticles() articles, articlesRoots, err = db.ListArticles()
return err return err
} }
TUI.CallbackSubmitArticle = func(article *models.Article) (error) { TUI.CallbackSubmitArticle = func(article *models.Article) (error) {
@ -63,7 +65,7 @@ func main() {
err = db.Connect(func(address string) { err = db.Connect(func(address string) {
TUI.Views["mainscreen"].(*tui.Mainscreen).SetFooter(address) TUI.Views["mainscreen"].(*tui.Mainscreen).SetFooter(address)
articles, _ = db.ListArticles() articles, articlesRoots, _ = db.ListArticles()
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
TUI.SetView("mainscreen", true) TUI.SetView("mainscreen", true)

@ -169,41 +169,52 @@ func (mainscreen *Mainscreen) GetDefaultFocus() (tview.Primitive) {
return mainscreen.Articles return mainscreen.Articles
} }
func(mainscreen *Mainscreen) Refresh() { func(mainscreen *Mainscreen) addNodeToArticlesList(level int, articlesNode *[]*models.Article, selectedGroup int, previousGroupsList []string) {
selectedGroup := mainscreen.CurrentGroupSelected // fmt.Fprintf(os.Stderr, "%s Node has %d items\n", strings.Repeat(" ", level * 3), len(*articlesNode))
selectedArticle := mainscreen.CurrentArticleSelected
previousGroupsList := mainscreen.GroupsList for i := 0; i < len(*articlesNode); i++ {
mainscreen.GroupsList = []string{} article := (*articlesNode)[i]
// previousGroupsMap := mainscreen.GroupsMap
mainscreen.GroupsMap = make(map[string]GroupMapEntry)
mainscreen.Groups.Clear()
mainscreen.ArticlesList = []*models.Article{} // fmt.Fprintf(os.Stderr, "%s Item has ID %s and is in reply of ID %s and has %d replies\n", strings.Repeat(" ", level * 3), article.ID, article.InReplyToID, len(article.Replies))
mainscreen.Articles.Clear()
mainscreen.GroupsList = append(mainscreen.GroupsList, "*")
mainscreen.GroupsMap["*"] = GroupMapEntry{
Index: 0,
}
for i := 0; i < len(*mainscreen.T.ArticlesDatasource); i++ {
article := (*mainscreen.T.ArticlesDatasource)[i]
if selectedGroup == 0 || if selectedGroup == 0 ||
(selectedGroup != 0 && (selectedGroup != 0 &&
article.Newsgroup == previousGroupsList[selectedGroup]) { article.Newsgroup == previousGroupsList[selectedGroup]) {
prefix := ""
if level > 0 {
if i < (len(*articlesNode) - 1) || len(article.Replies) > 0 {
prefix = "[gray]├[-]"
} else {
prefix = "[gray]└[-]"
}
}
prefixSub := " "
if len(article.Replies) > 0 || (level > 0 && i < (len(*articlesNode) - 1)) {
prefixSub = "[gray]│[-]"
}
mainscreen.Articles.AddItem( mainscreen.Articles.AddItem(
fmt.Sprintf( fmt.Sprintf(
"%s", "%s%s%s",
prefix,
strings.Repeat(" ", level),
article.Subject, article.Subject,
), ),
fmt.Sprintf( fmt.Sprintf(
" on [darkgray]%s[-] by [darkgray]%s[-] in [darkgray]%s[-]", "%s%s on [darkgray]%s[-] by [darkgray]%s[-] in [darkgray]%s[-]",
prefixSub,
strings.Repeat(" ", level),
MillisecondsToDate(article.Date), MillisecondsToDate(article.Date),
article.From, article.From,
article.Newsgroup, article.Newsgroup,
), 0, nil) ), 0, nil)
mainscreen.ArticlesList = append(mainscreen.ArticlesList, &article) mainscreen.ArticlesList = append(mainscreen.ArticlesList, article)
if len(article.Replies) > 0 {
mainscreen.addNodeToArticlesList((level + 1), &article.Replies, selectedGroup, previousGroupsList)
}
} }
if _, ok := mainscreen.GroupsMap[article.Newsgroup]; !ok { if _, ok := mainscreen.GroupsMap[article.Newsgroup]; !ok {
@ -213,6 +224,27 @@ func(mainscreen *Mainscreen) Refresh() {
} }
} }
} }
}
func(mainscreen *Mainscreen) Refresh() {
selectedGroup := mainscreen.CurrentGroupSelected
selectedArticle := mainscreen.CurrentArticleSelected
previousGroupsList := mainscreen.GroupsList
mainscreen.GroupsList = []string{}
// previousGroupsMap := mainscreen.GroupsMap
mainscreen.GroupsMap = make(map[string]GroupMapEntry)
mainscreen.Groups.Clear()
mainscreen.ArticlesList = []*models.Article{}
mainscreen.Articles.Clear()
mainscreen.GroupsList = append(mainscreen.GroupsList, "*")
mainscreen.GroupsMap["*"] = GroupMapEntry{
Index: 0,
}
mainscreen.addNodeToArticlesList(0, mainscreen.T.ArticlesRoots, selectedGroup, previousGroupsList)
sort.Strings(mainscreen.GroupsList) sort.Strings(mainscreen.GroupsList)
for idx, group := range mainscreen.GroupsList { for idx, group := range mainscreen.GroupsList {

@ -22,7 +22,8 @@ type TUI struct {
ModalVisible bool ModalVisible bool
ModalButtons map[string]ModalButton ModalButtons map[string]ModalButton
ArticlesDatasource *[]models.Article ArticlesDatasource *[]*models.Article
ArticlesRoots *[]*models.Article
CallbackRefreshArticles func() (error) CallbackRefreshArticles func() (error)
CallbackSubmitArticle func(article *models.Article) (error) CallbackSubmitArticle func(article *models.Article) (error)

Loading…
Cancel
Save