package ui import ( "fmt" "log" "strings" "time" "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 debouncer *Debouncer currentPage int pageSize int totalPages int pageContainer *fyne.Container } func NewThreadsScreen(uiManager *UIManager, board *models.Board) *ThreadsScreen { screen := &ThreadsScreen{ uiManager: uiManager, board: board, loading: false, pageSize: uiManager.GetSettings().PageSize, } screen.debouncer = NewDebouncer(100*time.Millisecond, func() { screen.displayThreads() }) 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.debouncer.Trigger() }) }() } 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) buttonsContainer := container.NewHBox() createThreadButton := widget.NewButton("Создать тред", func() { createThreadScreen := NewCreateThreadScreen(ts.uiManager, ts.board.Code) ts.uiManager.PushScreen(createThreadScreen) }) buttonsContainer.Add(createThreadButton) ts.content.Add(buttonsContainer) if len(ts.threads) == 0 { ts.content.Add(widget.NewLabel("Тредов не найдено")) ts.content.Refresh() return } ts.totalPages = (len(ts.threads) + ts.pageSize - 1) / ts.pageSize ts.pageContainer = container.NewVBox() start := ts.currentPage * ts.pageSize end := start + ts.pageSize if end > len(ts.threads) { end = len(ts.threads) } for i := start; i < end; i++ { thread := &ts.threads[i] threadCard := ts.createThreadCard(thread) ts.pageContainer.Add(threadCard) } ts.addPaginationControls() ts.content.Add(ts.pageContainer) ts.content.Refresh() } func (ts *ThreadsScreen) createThreadCard(thread *models.Thread) fyne.CanvasObject { title := fmt.Sprintf("#%d: %s", thread.ID, thread.Title) if len(title) > 20 { title = title[:17] + "..." } info := fmt.Sprintf("Дата: %s", 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 && ts.uiManager.GetSettings().ShowFiles { 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() } func (ts *ThreadsScreen) addPaginationControls() { if ts.totalPages <= 1 { return } paginationContainer := container.NewHBox() prevButton := widget.NewButton("←", func() { if ts.currentPage > 0 { ts.currentPage-- ts.displayThreads() } }) if ts.currentPage == 0 { prevButton.Disable() } paginationContainer.Add(prevButton) pageInfo := widget.NewLabel(fmt.Sprintf("Страница %d из %d", ts.currentPage+1, ts.totalPages)) paginationContainer.Add(pageInfo) nextButton := widget.NewButton("→", func() { if ts.currentPage < ts.totalPages-1 { ts.currentPage++ ts.displayThreads() } }) if ts.currentPage >= ts.totalPages-1 { nextButton.Disable() } paginationContainer.Add(nextButton) ts.pageContainer.Add(paginationContainer) } func (ts *ThreadsScreen) goToPage(page int) { if page >= 0 && page < ts.totalPages { ts.currentPage = page ts.displayThreads() } }