package ui import ( "fmt" "log" "strings" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/widget" "MobileMkch/models" ) type ThreadsScreen struct { uiManager *UIManager board *models.Board content *fyne.Container threads []models.Thread loading bool } func NewThreadsScreen(uiManager *UIManager, board *models.Board) *ThreadsScreen { screen := &ThreadsScreen{ uiManager: uiManager, board: board, loading: false, } screen.setupContent() return screen } func (ts *ThreadsScreen) setupContent() { ts.content = container.NewVBox() header := widget.NewLabel(fmt.Sprintf("/%s/ - %s", ts.board.Code, ts.board.Description)) header.TextStyle = fyne.TextStyle{Bold: true} ts.content.Add(header) ts.content.Add(widget.NewLabel("Загрузка тредов...")) } func (ts *ThreadsScreen) GetContent() fyne.CanvasObject { return container.NewScroll(ts.content) } func (ts *ThreadsScreen) GetTitle() string { return fmt.Sprintf("/%s/", ts.board.Code) } func (ts *ThreadsScreen) OnShow() { if !ts.loading { ts.loadThreads() } } func (ts *ThreadsScreen) OnHide() { // Ничего не делаем } func (ts *ThreadsScreen) loadThreads() { ts.loading = true ts.showLoading() go func() { defer func() { ts.loading = false }() threads, err := ts.uiManager.GetAPIClient().GetThreads(ts.board.Code) if err != nil { log.Printf("Ошибка загрузки тредов: %v", err) fyne.Do(func() { ts.showError(fmt.Sprintf("Ошибка загрузки тредов:\n%v", err)) }) return } ts.threads = threads fyne.Do(func() { ts.displayThreads() }) }() } func (ts *ThreadsScreen) showLoading() { ts.content.RemoveAll() header := widget.NewLabel(fmt.Sprintf("/%s/ - %s", ts.board.Code, ts.board.Description)) header.TextStyle = fyne.TextStyle{Bold: true} ts.content.Add(header) progressBar := widget.NewProgressBarInfinite() ts.content.Add(progressBar) progressBar.Start() ts.content.Add(widget.NewLabel("Загрузка тредов...")) ts.content.Refresh() } func (ts *ThreadsScreen) showError(message string) { ts.content.RemoveAll() header := widget.NewLabel(fmt.Sprintf("/%s/ - %s", ts.board.Code, ts.board.Description)) header.TextStyle = fyne.TextStyle{Bold: true} ts.content.Add(header) errorLabel := widget.NewLabel("❌ " + message) errorLabel.Wrapping = fyne.TextWrapWord ts.content.Add(errorLabel) retryButton := widget.NewButton("Повторить", func() { ts.loadThreads() }) ts.content.Add(retryButton) ts.content.Refresh() } func (ts *ThreadsScreen) displayThreads() { ts.content.RemoveAll() header := widget.NewLabel(fmt.Sprintf("/%s/ - %s", ts.board.Code, ts.board.Description)) header.TextStyle = fyne.TextStyle{Bold: true} ts.content.Add(header) if len(ts.threads) == 0 { ts.content.Add(widget.NewLabel("Тредов не найдено")) ts.content.Refresh() return } for i := range ts.threads { thread := ts.threads[i] threadCard := ts.createThreadCard(&thread) ts.content.Add(threadCard) } ts.content.Refresh() } func (ts *ThreadsScreen) createThreadCard(thread *models.Thread) fyne.CanvasObject { title := fmt.Sprintf("#%d: %s", thread.ID, thread.Title) if len(title) > 50 { title = title[:47] + "..." } info := fmt.Sprintf("Автор: %s | %s", thread.Author, thread.GetCreationTime().Format("02.01.2006 15:04")) if thread.IsPinned() { info += " | 📌 Закреплён" } if rating := thread.GetRatingValue(); rating != 0 { info += fmt.Sprintf(" | ⭐ %d", rating) } if len(thread.Files) > 0 { info += fmt.Sprintf(" | 📎 %d", len(thread.Files)) } preview := thread.Text preview = strings.ReplaceAll(preview, "\n", " ") preview = strings.ReplaceAll(preview, "\r", " ") if len(preview) > 90 { maxLen := 50 if len(preview) < maxLen { maxLen = len(preview) } preview = preview[:maxLen] + "..." } buttonText := fmt.Sprintf("%s\n%s\n%s", title, info, preview) button := widget.NewButton(buttonText, func() { ts.uiManager.ShowThreadDetail(ts.board, thread) }) return button } func (ts *ThreadsScreen) RefreshThreads() { ts.loadThreads() }