This commit is contained in:
2026-04-04 00:09:02 +08:00
commit 38e896363e
117 changed files with 119311 additions and 0 deletions

View File

@@ -0,0 +1,235 @@
package main
import (
"fmt"
"path/filepath"
"strings"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/widget"
)
// Вспомогательные методы
func (a *App) showError(title, message string) {
dialog.ShowError(fmt.Errorf(message), a.window)
a.statusLabel.SetText("❌ " + title)
}
func (a *App) showSuccess(title, message string) {
dialog.ShowInformation(title, message, a.window)
}
func (a *App) detectMimeType() string {
ext := strings.ToLower(filepath.Ext(a.fileName))
mimeTypes := map[string]string{
".txt": "text/plain",
".pdf": "application/pdf",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".zip": "application/zip",
".doc": "application/msword",
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
}
if mime, ok := mimeTypes[ext]; ok {
return mime
}
return "application/octet-stream"
}
// // Это делал DeepSeek оно криво, но работает. Оставлю это так, потому что всё равно планирую не использовать больше fyne
type JournalEntryWidget struct {
widget.BaseWidget
event journalctlEntry
label *widget.Label
}
func NewJournalEntryWidget(event journalctlEntry) *JournalEntryWidget {
j := &JournalEntryWidget{
event: event,
}
j.ExtendBaseWidget(j)
return j
}
func (j *JournalEntryWidget) CreateRenderer() fyne.WidgetRenderer {
j.label = widget.NewLabel(j.formatEventText())
j.label.Wrapping = fyne.TextWrapBreak
j.label.Selectable = true
return widget.NewSimpleRenderer(j.label)
}
func (j *JournalEntryWidget) formatEventText() string {
return fmt.Sprintf("%s :: %s :: %s :: %s :: %s",
j.event.Timestamp, j.event.CommandLine, j.event.CommandName,
j.event.SyslogIdentifier, j.event.Message)
}
func (j *JournalEntryWidget) UpdateEvent(event journalctlEntry) {
j.event = event
if j.label != nil {
j.label.SetText(j.formatEventText())
}
j.Refresh()
}
//
//
//
//
// func (a *App) isTextFile() bool {
// ext := strings.ToLower(filepath.Ext(a.fileName))
// textExts := []string{".txt", ".csv", ".json", ".xml", ".yaml", ".yml", ".md", ".go", ".py", ".js"}
// for _, textExt := range textExts {
// if ext == textExt {
// return true
// }
// }ц=
// // Проверяем содержимое (простейшая проверка)
// if len(a.fileContent) == 0 {
// return false
// }
// // Если файл содержит null-байты, это скорее бинарный файл
// for _, b := range a.fileContent {
// if b == 0 {
// return false
// }
// }
// return true
// }
// type TextStats struct {
// lines int
// words int
// chars int
// bytes int
// }
// func (a *App) calculateTextStats() TextStats {
// if len(a.fileContent) == 0 {
// return TextStats{}
// }
// content := string(a.fileContent)
// stats := TextStats{
// bytes: len(a.fileContent),
// chars: len(content),
// lines: strings.Count(content, "\n") + 1,
// words: len(strings.Fields(content)),
// }
// return stats
// }
// Это делал DeepSeek оно криво, но работает. Оставлю это так, потому что всё равно планирую не использовать больше fyne
// Кастомный виджет для элемента списка с динамической высотой
type JournalListItem struct {
widget.BaseWidget
event journalctlEntry
label *widget.Label
}
func NewJournalListItem(event journalctlEntry) *JournalListItem {
j := &JournalListItem{
event: event,
}
j.ExtendBaseWidget(j)
return j
}
func (j *JournalListItem) CreateRenderer() fyne.WidgetRenderer {
j.label = widget.NewLabel(j.formatText())
j.label.Wrapping = fyne.TextWrapBreak
j.label.Selectable = true
return &journalListItemRenderer{
item: j,
label: j.label,
}
}
func (j *JournalListItem) formatText() string {
return fmt.Sprintf("%s :: %s :: %s :: %s :: %s",
j.event.Timestamp, j.event.CommandLine, j.event.CommandName,
j.event.SyslogIdentifier, j.event.Message)
}
func (j *JournalListItem) Update(event journalctlEntry) {
j.event = event
if j.label != nil {
j.label.SetText(j.formatText())
}
j.Refresh()
}
type journalListItemRenderer struct {
item *JournalListItem
label *widget.Label
}
func (r *journalListItemRenderer) Layout(size fyne.Size) {
// Рассчитываем высоту label на основе его содержимого
minSize := r.label.MinSize()
labelHeight := minSize.Height
// Если высота label больше 50, используем её, иначе минимальную
height := labelHeight
if height < 50 {
height = 50
}
r.label.Resize(fyne.NewSize(size.Width, height))
r.label.Move(fyne.NewPos(0, 0))
}
func (r *journalListItemRenderer) MinSize() fyne.Size {
minSize := r.label.MinSize()
if minSize.Height < 50 {
minSize.Height = 50
}
return minSize
}
func (r *journalListItemRenderer) Refresh() {
r.label.Refresh()
}
func (r *journalListItemRenderer) Objects() []fyne.CanvasObject {
return []fyne.CanvasObject{r.label}
}
func (r *journalListItemRenderer) Destroy() {}
//
//
//
//
//
//
//
//
//
//
// Вспомогательные функции
func formatFileSize(bytes int64) string {
const unit = 1024
if bytes < unit {
return fmt.Sprintf("%d Б", bytes)
}
div, exp := int64(unit), 0
for n := bytes / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cБ", float64(bytes)/float64(div), "КМГТП"[exp])
}