From d321069a5fac08510cdb12dd5cb04b888f84de4e Mon Sep 17 00:00:00 2001 From: Lain Iwakura Date: Wed, 6 Aug 2025 00:17:35 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B5=D0=B1=D0=B0=D0=BD=D1=83=D1=82=D1=8B?= =?UTF-8?q?=D0=B5=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B9=D0=BA=D0=B8?= =?UTF-8?q?=20=D1=87=D0=B5=D1=81=D1=82=D0=BD=D0=B5=D0=BE=20=D1=81=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/add_comment_screen.go | 107 +++++++++++++++++++++++++++++++++++++ ui/create_thread_screen.go | 107 +++++++++++++++++++++++++++++++++++++ ui/settings_screen.go | 63 +++++++++++----------- 3 files changed, 244 insertions(+), 33 deletions(-) create mode 100644 ui/add_comment_screen.go create mode 100644 ui/create_thread_screen.go diff --git a/ui/add_comment_screen.go b/ui/add_comment_screen.go new file mode 100644 index 0000000..fa8d52b --- /dev/null +++ b/ui/add_comment_screen.go @@ -0,0 +1,107 @@ +package ui + +import ( + "fmt" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" +) + +type AddCommentScreen struct { + uiManager *UIManager + content *fyne.Container + boardCode string + threadID int +} + +func NewAddCommentScreen(uiManager *UIManager, boardCode string, threadID int) *AddCommentScreen { + acs := &AddCommentScreen{ + uiManager: uiManager, + boardCode: boardCode, + threadID: threadID, + content: container.NewVBox(), + } + acs.setupContent() + return acs +} + +func (acs *AddCommentScreen) setupContent() { + acs.content.Objects = nil + + titleLabel := widget.NewLabel(fmt.Sprintf("Добавить комментарий в тред %d /%s/", acs.threadID, acs.boardCode)) + titleLabel.TextStyle = fyne.TextStyle{Bold: true} + acs.content.Add(titleLabel) + + textEntry := widget.NewMultiLineEntry() + textEntry.SetPlaceHolder("Текст комментария") + textEntry.Resize(fyne.NewSize(300, 200)) + acs.content.Add(textEntry) + + passcode := acs.uiManager.GetPasscode() + if passcode != "" { + passcodeLabel := widget.NewLabel("Passcode настроен") + passcodeLabel.TextStyle = fyne.TextStyle{Bold: true} + acs.content.Add(passcodeLabel) + } else { + passcodeLabel := widget.NewLabel("Passcode не настроен - постинг может быть\nограничен и могут быть неожиданные ПРОБЛЕЕМЫ\n(подробнее в настройках)") + passcodeLabel.TextStyle = fyne.TextStyle{Bold: true} + acs.content.Add(passcodeLabel) + } + + buttonsContainer := container.NewHBox() + + addButton := widget.NewButton("Добавить комментарий", func() { + text := textEntry.Text + + if text == "" { + acs.uiManager.ShowError("Ошибка", "Текст не может быть пустым") + return + } + + acs.uiManager.ShowInfo("Добавление комментария", "Отправляем комментарий...") + + passcode := acs.uiManager.GetPasscode() + err := acs.uiManager.GetAPIClient().AddComment(acs.boardCode, acs.threadID, text, passcode) + if err != nil { + acs.uiManager.ShowError("Ошибка", fmt.Sprintf("Не удалось добавить комментарий: %v", err)) + return + } + + acs.uiManager.ClearCacheForThread(acs.threadID) + + acs.uiManager.ShowInfo("Успех", "Комментарий добавлен успешно!") + + acs.uiManager.GoBack() + + if threadDetailScreen, ok := acs.uiManager.GetCurrentScreen().(*ThreadDetailScreen); ok { + threadDetailScreen.RefreshThread() + } + }) + + cancelButton := widget.NewButton("Отмена", func() { + acs.uiManager.GoBack() + }) + + buttonsContainer.Add(addButton) + buttonsContainer.Add(cancelButton) + acs.content.Add(buttonsContainer) + + acs.content.Refresh() +} + +func (acs *AddCommentScreen) GetContent() fyne.CanvasObject { + return acs.content +} + +func (acs *AddCommentScreen) GetTitle() string { + return fmt.Sprintf("Комментарий в тред %d", acs.threadID) +} + +func (acs *AddCommentScreen) OnShow() { + acs.setupContent() +} + +func (acs *AddCommentScreen) OnHide() { + // Ничего не делаем при скрытии +} diff --git a/ui/create_thread_screen.go b/ui/create_thread_screen.go new file mode 100644 index 0000000..5aa6c8f --- /dev/null +++ b/ui/create_thread_screen.go @@ -0,0 +1,107 @@ +package ui + +import ( + "fmt" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" +) + +type CreateThreadScreen struct { + uiManager *UIManager + content *fyne.Container + boardCode string +} + +func NewCreateThreadScreen(uiManager *UIManager, boardCode string) *CreateThreadScreen { + cts := &CreateThreadScreen{ + uiManager: uiManager, + boardCode: boardCode, + content: container.NewVBox(), + } + cts.setupContent() + return cts +} + +func (cts *CreateThreadScreen) setupContent() { + cts.content.Objects = nil + titleLabel := widget.NewLabel(fmt.Sprintf("Создать тред в /%s/", cts.boardCode)) + titleLabel.TextStyle = fyne.TextStyle{Bold: true} + cts.content.Add(titleLabel) + titleEntry := widget.NewEntry() + titleEntry.SetPlaceHolder("Заголовок треда") + cts.content.Add(titleEntry) + textEntry := widget.NewMultiLineEntry() + textEntry.SetPlaceHolder("Текст треда") + textEntry.Resize(fyne.NewSize(300, 200)) + cts.content.Add(textEntry) + passcode := cts.uiManager.GetPasscode() + if passcode != "" { + passcodeLabel := widget.NewLabel("Passcode настроен ✓") + passcodeLabel.TextStyle = fyne.TextStyle{Bold: true} + cts.content.Add(passcodeLabel) + } else { + passcodeLabel := widget.NewLabel("Passcode не настроен - постинг может быть ограничен\nи могут быть неожиданные ПРОБЛЕЕМЫ\n(подробнее в настройках)") + passcodeLabel.TextStyle = fyne.TextStyle{Bold: true} + cts.content.Add(passcodeLabel) + } + + buttonsContainer := container.NewHBox() + + createButton := widget.NewButton("Создать тред", func() { + title := titleEntry.Text + text := textEntry.Text + + if title == "" { + cts.uiManager.ShowError("Ошибка", "Заголовок не может быть пустым") + return + } + + if text == "" { + cts.uiManager.ShowError("Ошибка", "Текст не может быть пустым") + return + } + + cts.uiManager.ShowInfo("Создание треда", "Отправляем тред...") + + passcode := cts.uiManager.GetPasscode() + err := cts.uiManager.GetAPIClient().CreateThread(cts.boardCode, title, text, passcode) + if err != nil { + cts.uiManager.ShowError("Ошибка", fmt.Sprintf("Не удалось создать тред: %v", err)) + return + } + + cts.uiManager.ClearCacheForBoard(cts.boardCode) + + cts.uiManager.ShowInfo("Успех", "Тред создан успешно!") + cts.uiManager.GoBack() + cts.uiManager.RefreshCurrentScreen() + }) + + cancelButton := widget.NewButton("Отмена", func() { + cts.uiManager.GoBack() + }) + + buttonsContainer.Add(createButton) + buttonsContainer.Add(cancelButton) + cts.content.Add(buttonsContainer) + + cts.content.Refresh() +} + +func (cts *CreateThreadScreen) GetContent() fyne.CanvasObject { + return cts.content +} + +func (cts *CreateThreadScreen) GetTitle() string { + return fmt.Sprintf("Создать тред /%s/", cts.boardCode) +} + +func (cts *CreateThreadScreen) OnShow() { + cts.setupContent() +} + +func (cts *CreateThreadScreen) OnHide() { + // Ничего не делаем при скрытии +} diff --git a/ui/settings_screen.go b/ui/settings_screen.go index 7498090..8c0ff6c 100644 --- a/ui/settings_screen.go +++ b/ui/settings_screen.go @@ -26,9 +26,11 @@ func NewSettingsScreen(uiManager *UIManager) *SettingsScreen { func (ss *SettingsScreen) setupContent() { ss.content.RemoveAll() + contentContainer := container.NewVBox() + header := widget.NewLabel("Настройки") header.TextStyle = fyne.TextStyle{Bold: true} - ss.content.Add(header) + contentContainer.Add(header) themeLabel := widget.NewLabel("Тема:") themeSelect := widget.NewSelect([]string{"Темная", "Светлая"}, func(theme string) { @@ -47,28 +49,28 @@ func (ss *SettingsScreen) setupContent() { } themeContainer := container.NewHBox(themeLabel, themeSelect) - ss.content.Add(themeContainer) + contentContainer.Add(themeContainer) autoRefreshCheck := widget.NewCheck("Авторефреш", func(checked bool) { ss.uiManager.GetSettings().AutoRefresh = checked ss.uiManager.SaveSettings() }) autoRefreshCheck.SetChecked(ss.uiManager.GetSettings().AutoRefresh) - ss.content.Add(autoRefreshCheck) + contentContainer.Add(autoRefreshCheck) showFilesCheck := widget.NewCheck("Показывать файлы", func(checked bool) { ss.uiManager.GetSettings().ShowFiles = checked ss.uiManager.SaveSettings() }) showFilesCheck.SetChecked(ss.uiManager.GetSettings().ShowFiles) - ss.content.Add(showFilesCheck) + contentContainer.Add(showFilesCheck) compactModeCheck := widget.NewCheck("Компактный режим", func(checked bool) { ss.uiManager.GetSettings().CompactMode = checked ss.uiManager.SaveSettings() }) compactModeCheck.SetChecked(ss.uiManager.GetSettings().CompactMode) - ss.content.Add(compactModeCheck) + contentContainer.Add(compactModeCheck) pageSizeLabel := widget.NewLabel("Размер страницы:") pageSizeSelect := widget.NewSelect([]string{"5", "10", "15", "20"}, func(size string) { @@ -100,7 +102,7 @@ func (ss *SettingsScreen) setupContent() { } pageSizeContainer := container.NewHBox(pageSizeLabel, pageSizeSelect) - ss.content.Add(pageSizeContainer) + contentContainer.Add(pageSizeContainer) lastBoardLabel := widget.NewLabel("Последняя доска:") lastBoardValue := widget.NewLabel(ss.uiManager.GetLastBoard()) @@ -108,13 +110,13 @@ func (ss *SettingsScreen) setupContent() { lastBoardValue.SetText("Не выбрана") } lastBoardContainer := container.NewHBox(lastBoardLabel, lastBoardValue) - ss.content.Add(lastBoardContainer) + contentContainer.Add(lastBoardContainer) - ss.content.Add(widget.NewSeparator()) + contentContainer.Add(widget.NewSeparator()) passcodeHeader := widget.NewLabel("Passcode") passcodeHeader.TextStyle = fyne.TextStyle{Bold: true} - ss.content.Add(passcodeHeader) + contentContainer.Add(passcodeHeader) passcodeEntry := widget.NewEntry() passcodeEntry.SetPlaceHolder("Введите passcode для постинга") @@ -123,11 +125,11 @@ func (ss *SettingsScreen) setupContent() { ss.uiManager.GetSettings().Passcode = text ss.uiManager.SaveSettings() } - ss.content.Add(passcodeEntry) + contentContainer.Add(passcodeEntry) keyHeader := widget.NewLabel("Ключ аутентификации") keyHeader.TextStyle = fyne.TextStyle{Bold: true} - ss.content.Add(keyHeader) + contentContainer.Add(keyHeader) keyEntry := widget.NewEntry() keyEntry.SetPlaceHolder("Введите ключ для аутентификации") @@ -136,7 +138,7 @@ func (ss *SettingsScreen) setupContent() { ss.uiManager.GetSettings().Key = text ss.uiManager.SaveSettings() } - ss.content.Add(keyEntry) + contentContainer.Add(keyEntry) authButtonsContainer := container.NewHBox() @@ -172,23 +174,17 @@ func (ss *SettingsScreen) setupContent() { authButtonsContainer.Add(testKeyButton) authButtonsContainer.Add(testPasscodeButton) - ss.content.Add(authButtonsContainer) + contentContainer.Add(authButtonsContainer) - // Debug - debugCheck := widget.NewCheck("Debug режим", func(checked bool) { - ss.uiManager.GetAPIClient().EnableDebug(checked) - }) - ss.content.Add(debugCheck) - - ss.content.Add(widget.NewSeparator()) + contentContainer.Add(widget.NewSeparator()) cacheHeader := widget.NewLabel("Управление кэшем") cacheHeader.TextStyle = fyne.TextStyle{Bold: true} - ss.content.Add(cacheHeader) + contentContainer.Add(cacheHeader) clearBoardsCacheBtn := widget.NewButton("Очистить кэш досок", func() { cache.GetCache().Delete("boards") ss.uiManager.ShowInfo("Кэш очищен", "Кэш досок очищен") }) - ss.content.Add(clearBoardsCacheBtn) + contentContainer.Add(clearBoardsCacheBtn) clearThreadsCacheBtn := widget.NewButton("Очистить кэш тредов", func() { boards, err := ss.uiManager.GetAPIClient().GetBoards() if err == nil { @@ -198,7 +194,7 @@ func (ss *SettingsScreen) setupContent() { } ss.uiManager.ShowInfo("Кэш очищен", "Кэш тредов для всех досок очищен") }) - ss.content.Add(clearThreadsCacheBtn) + contentContainer.Add(clearThreadsCacheBtn) clearThreadDetailsCacheBtn := widget.NewButton("Очистить кэш деталей тредов", func() { // Удаляем кэш деталей тредов и комментариев // Это более сложно, так как нужно знать ID тредов @@ -206,17 +202,17 @@ func (ss *SettingsScreen) setupContent() { cache.GetCache().Clear() ss.uiManager.ShowInfo("Кэш очищен", "Кэш деталей тредов очищен") }) - ss.content.Add(clearThreadDetailsCacheBtn) + contentContainer.Add(clearThreadDetailsCacheBtn) clearAllCacheBtn := widget.NewButton("Очистить весь кэш", func() { cache.GetCache().Clear() ss.uiManager.ShowInfo("Кэш очищен", "Весь кэш очищен") }) - ss.content.Add(clearAllCacheBtn) - ss.content.Add(widget.NewSeparator()) + contentContainer.Add(clearAllCacheBtn) + contentContainer.Add(widget.NewSeparator()) resetHeader := widget.NewLabel("Сброс настроек") resetHeader.TextStyle = fyne.TextStyle{Bold: true} - ss.content.Add(resetHeader) + contentContainer.Add(resetHeader) resetButton := widget.NewButton("Сбросить настройки", func() { ss.uiManager.GetSettings().Theme = "dark" @@ -228,27 +224,28 @@ func (ss *SettingsScreen) setupContent() { ss.uiManager.SaveSettings() ss.setupContent() // Перезагружаем интерфейс }) - ss.content.Add(resetButton) + contentContainer.Add(resetButton) - ss.content.Add(widget.NewSeparator()) + contentContainer.Add(widget.NewSeparator()) aboutButton := widget.NewButton("Об аппке", func() { ss.uiManager.ShowAbout() }) - ss.content.Add(aboutButton) + contentContainer.Add(aboutButton) - ss.content.Add(widget.NewSeparator()) + contentContainer.Add(widget.NewSeparator()) infoButton := widget.NewButton("Я думаю тебя направили сюда)", func() { ss.uiManager.ShowInfoDialog() }) - ss.content.Add(infoButton) + contentContainer.Add(infoButton) + ss.content.Add(contentContainer) ss.content.Refresh() } func (ss *SettingsScreen) GetContent() fyne.CanvasObject { - return ss.content + return container.NewScroll(ss.content) } func (ss *SettingsScreen) GetTitle() string {