MobileMkch/ui/thread_detail_screen.go
2025-08-05 23:54:04 +03:00

290 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package ui
import (
"fmt"
"log"
"net/url"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/widget"
"MobileMkch/models"
)
type ThreadDetailScreen struct {
uiManager *UIManager
board *models.Board
thread *models.Thread
threadDetail *models.ThreadDetail
comments []models.Comment
content *fyne.Container
loading bool
}
func NewThreadDetailScreen(uiManager *UIManager, board *models.Board, thread *models.Thread) *ThreadDetailScreen {
screen := &ThreadDetailScreen{
uiManager: uiManager,
board: board,
thread: thread,
loading: false,
}
screen.setupContent()
return screen
}
func (tds *ThreadDetailScreen) setupContent() {
tds.content = container.NewVBox()
header := widget.NewLabel(fmt.Sprintf("#%d: %s", tds.thread.ID, tds.thread.Title))
header.TextStyle = fyne.TextStyle{Bold: true}
header.Wrapping = fyne.TextWrapWord
tds.content.Add(header)
tds.content.Add(widget.NewLabel("Загрузка деталей треда..."))
}
func (tds *ThreadDetailScreen) GetContent() fyne.CanvasObject {
return container.NewScroll(tds.content)
}
func (tds *ThreadDetailScreen) GetTitle() string {
return fmt.Sprintf("#%d", tds.thread.ID)
}
func (tds *ThreadDetailScreen) OnShow() {
if !tds.loading {
tds.loadThreadDetail()
}
}
func (tds *ThreadDetailScreen) OnHide() {
// Ничего не делаем
}
func (tds *ThreadDetailScreen) loadThreadDetail() {
tds.loading = true
tds.showLoading()
go func() {
defer func() {
tds.loading = false
}()
threadDetail, comments, err := tds.uiManager.GetAPIClient().GetFullThread(tds.board.Code, tds.thread.ID)
if err != nil {
log.Printf("Ошибка загрузки треда: %v", err)
fyne.Do(func() {
tds.showError(fmt.Sprintf("Ошибка загрузки треда:\n%v", err))
})
return
}
tds.threadDetail = threadDetail
tds.comments = comments
fyne.Do(func() {
tds.displayThreadDetail()
})
}()
}
func (tds *ThreadDetailScreen) showLoading() {
tds.content.RemoveAll()
header := widget.NewLabel(fmt.Sprintf("#%d: %s", tds.thread.ID, tds.thread.Title))
header.TextStyle = fyne.TextStyle{Bold: true}
header.Wrapping = fyne.TextWrapWord
tds.content.Add(header)
progressBar := widget.NewProgressBarInfinite()
tds.content.Add(progressBar)
progressBar.Start()
tds.content.Add(widget.NewLabel("Загрузка треда и комментариев..."))
tds.content.Refresh()
}
func (tds *ThreadDetailScreen) showError(message string) {
tds.content.RemoveAll()
header := widget.NewLabel(fmt.Sprintf("#%d: %s", tds.thread.ID, tds.thread.Title))
header.TextStyle = fyne.TextStyle{Bold: true}
header.Wrapping = fyne.TextWrapWord
tds.content.Add(header)
errorLabel := widget.NewLabel("❌ " + message)
errorLabel.Wrapping = fyne.TextWrapWord
tds.content.Add(errorLabel)
retryButton := widget.NewButton("Повторить", func() {
tds.loadThreadDetail()
})
tds.content.Add(retryButton)
tds.content.Refresh()
}
func (tds *ThreadDetailScreen) displayThreadDetail() {
tds.content.RemoveAll()
if tds.threadDetail == nil {
tds.showError("Не удалось загрузить тред")
return
}
header := widget.NewLabel(fmt.Sprintf("#%d: %s", tds.threadDetail.ID, tds.threadDetail.Title))
header.TextStyle = fyne.TextStyle{Bold: true}
header.Wrapping = fyne.TextWrapWord
tds.content.Add(header)
buttonsContainer := container.NewHBox()
addCommentButton := widget.NewButton("Добавить комментарий", func() {
addCommentScreen := NewAddCommentScreen(tds.uiManager, tds.board.Code, tds.thread.ID)
tds.uiManager.PushScreen(addCommentScreen)
})
buttonsContainer.Add(addCommentButton)
refreshButton := widget.NewButton("Обновить", func() {
tds.uiManager.ClearCacheForThread(tds.thread.ID)
tds.loadThreadDetail()
})
buttonsContainer.Add(refreshButton)
tds.content.Add(buttonsContainer)
threadContainer := tds.createThreadContainer(tds.threadDetail)
tds.content.Add(threadContainer)
tds.content.Add(widget.NewSeparator())
commentsHeader := widget.NewLabel(fmt.Sprintf("Комментарии (%d):", len(tds.comments)))
commentsHeader.TextStyle = fyne.TextStyle{Bold: true}
tds.content.Add(commentsHeader)
if len(tds.comments) == 0 {
tds.content.Add(widget.NewLabel("Комментариев пока нет"))
} else {
for i := range tds.comments {
comment := &tds.comments[i]
commentContainer := tds.createCommentContainer(comment)
tds.content.Add(commentContainer)
if i < len(tds.comments)-1 {
tds.content.Add(widget.NewSeparator())
}
}
}
tds.content.Refresh()
}
func (tds *ThreadDetailScreen) createThreadContainer(thread *models.ThreadDetail) *fyne.Container {
container := container.NewVBox()
info := fmt.Sprintf("Дата: %s",
thread.GetCreationTime().Format("02.01.2006 15:04"))
infoLabel := widget.NewLabel(info)
infoLabel.TextStyle = fyne.TextStyle{Italic: true}
container.Add(infoLabel)
if len(thread.Files) > 0 && tds.uiManager.GetSettings().ShowFiles {
filesContainer := tds.createFilesContainer(thread.Files)
container.Add(filesContainer)
}
if thread.Text != "" {
textLabel := widget.NewLabel(thread.Text)
textLabel.Wrapping = fyne.TextWrapWord
container.Add(textLabel)
}
return container
}
func (tds *ThreadDetailScreen) createCommentContainer(comment *models.Comment) *fyne.Container {
container := container.NewVBox()
info := fmt.Sprintf("ID: %d | Дата: %s",
comment.ID,
comment.GetCreationTime().Format("02.01.2006 15:04"))
infoLabel := widget.NewLabel(info)
infoLabel.TextStyle = fyne.TextStyle{Italic: true}
container.Add(infoLabel)
if len(comment.Files) > 0 && tds.uiManager.GetSettings().ShowFiles {
filesContainer := tds.createFilesContainer(comment.Files)
container.Add(filesContainer)
}
if comment.Text != "" {
text := comment.FormatText()
textLabel := widget.NewLabel(text)
textLabel.Wrapping = fyne.TextWrapWord
container.Add(textLabel)
}
return container
}
func (tds *ThreadDetailScreen) createFilesContainer(files []string) *fyne.Container {
if len(files) == 0 {
return container.NewVBox()
}
filesContainer := container.New(layout.NewGridLayout(2))
for _, filePath := range files {
fileInfo := models.GetFileInfo(filePath)
fileWidget := tds.createFileWidget(fileInfo)
filesContainer.Add(fileWidget)
}
return container.NewVBox(
widget.NewLabel(fmt.Sprintf("📎 Файлы (%d):", len(files))),
filesContainer,
)
}
func (tds *ThreadDetailScreen) createFileWidget(fileInfo models.FileInfo) fyne.CanvasObject {
if fileInfo.IsImage {
button := widget.NewButton(fmt.Sprintf("🖼️ %s", fileInfo.Filename), func() {
tds.openFile(fileInfo.URL)
})
return button
} else if fileInfo.IsVideo {
button := widget.NewButton(fmt.Sprintf("🎬 %s", fileInfo.Filename), func() {
tds.openFile(fileInfo.URL)
})
return button
} else {
button := widget.NewButton(fmt.Sprintf("📄 %s", fileInfo.Filename), func() {
tds.openFile(fileInfo.URL)
})
return button
}
}
func (tds *ThreadDetailScreen) openFile(fileURL string) {
parsedURL, err := url.Parse(fileURL)
if err != nil {
tds.uiManager.ShowError("Ошибка", "Не удалось открыть файл")
return
}
err = fyne.CurrentApp().OpenURL(parsedURL)
if err != nil {
tds.uiManager.ShowError("Ошибка", "Не удалось открыть файл в браузере")
}
}
func (tds *ThreadDetailScreen) RefreshThread() {
tds.loadThreadDetail()
}