274 lines
6.9 KiB
Go
274 lines
6.9 KiB
Go
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)
|
||
|
||
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()
|
||
}
|