Leonid Nikitin 84b36dd29e
Make it possible to drag and drop multiple files
It is now possible to add multiple files before sending them to the processing queue.
2025-05-25 01:25:40 +05:00

483 lines
12 KiB
Go

package kernel
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/nicksnyder/go-i18n/v2/i18n"
"image/color"
"strconv"
"strings"
)
type LayoutContract interface {
SetContent(content fyne.CanvasObject) *fyne.Container
ChangeQueueStatus(queueId int, queue *Queue)
GetRightTabs() RightTabsContract
}
type Layout struct {
layout *fyne.Container
queueLayoutObject QueueLayoutObjectContract
localizerService LocalizerContract
rightTabsService RightTabsContract
}
func NewLayout(queueLayoutObject QueueLayoutObjectContract, localizerService LocalizerContract, rightTabsService RightTabsContract) *Layout {
layout := container.NewAdaptiveGrid(2, widget.NewLabel(""), queueLayoutObject.GetCanvasObject())
return &Layout{
layout: layout,
queueLayoutObject: queueLayoutObject,
localizerService: localizerService,
rightTabsService: rightTabsService,
}
}
func (l Layout) SetContent(content fyne.CanvasObject) *fyne.Container {
l.layout.Objects[0] = content
return l.layout
}
func (l Layout) ChangeQueueStatus(queueId int, queue *Queue) {
l.queueLayoutObject.ChangeQueueStatus(queueId, queue)
}
func (l Layout) GetRightTabs() RightTabsContract {
return l.rightTabsService
}
type QueueLayoutObjectContract interface {
GetCanvasObject() fyne.CanvasObject
ChangeQueueStatus(queueId int, queue *Queue)
}
type QueueLayoutObject struct {
QueueListContract QueueListContract
queue QueueListContract
container *fyne.Container
containerItems *fyne.Container
items map[int]QueueLayoutItem
localizerService LocalizerContract
queueStatisticsFormat *queueStatisticsFormat
ffplayService FFplayContract
}
type QueueLayoutItem struct {
CanvasObject fyne.CanvasObject
BlockMessageError *container.Scroll
StatusMessage *canvas.Text
MessageError *canvas.Text
buttonPlay *widget.Button
status *StatusContract
}
func NewQueueLayoutObject(queue QueueListContract, localizerService LocalizerContract, ffplayService FFplayContract, rightTabsService RightTabsContract, blockProgressbar *fyne.Container) *QueueLayoutObject {
title := widget.NewLabel(localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "queue"}))
title.TextStyle.Bold = true
localizerService.AddChangeCallback("queue", func(text string) {
title.Text = text
title.Refresh()
})
items := map[int]QueueLayoutItem{}
queueStatisticsFormat := newQueueStatisticsFormat(localizerService, &items)
line := canvas.NewLine(theme.Color(theme.ColorNameFocus))
line.StrokeWidth = 5
rightTabsService.GetFileQueueContainer().Add(container.NewVBox(
container.NewPadded(),
container.NewHBox(title, queueStatisticsFormat.completed.widget, queueStatisticsFormat.error.widget),
container.NewHBox(queueStatisticsFormat.inProgress.widget, queueStatisticsFormat.waiting.widget, queueStatisticsFormat.total.widget),
container.NewPadded(),
line,
container.NewPadded(),
))
queueLayoutObject := &QueueLayoutObject{
queue: queue,
container: container.NewBorder(
container.NewVBox(
blockProgressbar,
widget.NewSeparator(),
),
nil, nil, nil, container.NewVScroll(rightTabsService.GetTabs()),
),
containerItems: rightTabsService.GetFileQueueContainer(),
items: items,
localizerService: localizerService,
queueStatisticsFormat: queueStatisticsFormat,
ffplayService: ffplayService,
}
queue.AddListener(queueLayoutObject)
return queueLayoutObject
}
func (o QueueLayoutObject) GetCanvasObject() fyne.CanvasObject {
return o.container
}
func (o QueueLayoutObject) Add(id int, queue *Queue) {
statusMessage := canvas.NewText(o.getStatusTitle(queue.Status), theme.Color(theme.ColorNamePrimary))
messageError := canvas.NewText("", theme.Color(theme.ColorNameError))
buttonPlay := widget.NewButtonWithIcon("", theme.Icon(theme.IconNameMediaPlay), func() {
})
buttonPlay.Hide()
blockMessageError := container.NewHScroll(messageError)
blockMessageError.Hide()
content := container.NewVBox(
container.NewHScroll(widget.NewLabel(queue.Setting.VideoFileInput.Name)),
container.NewHBox(
buttonPlay,
statusMessage,
),
blockMessageError,
container.NewPadded(),
canvas.NewLine(theme.Color(theme.ColorNameFocus)),
container.NewPadded(),
)
o.queueStatisticsFormat.addQueue()
if o.queueStatisticsFormat.isChecked(queue.Status) == false {
content.Hide()
}
o.items[id] = QueueLayoutItem{
CanvasObject: content,
StatusMessage: statusMessage,
BlockMessageError: blockMessageError,
MessageError: messageError,
buttonPlay: buttonPlay,
status: &queue.Status,
}
o.containerItems.Add(content)
}
func (o QueueLayoutObject) Remove(id int) {
if item, ok := o.items[id]; ok {
o.container.Remove(item.CanvasObject)
o.queueStatisticsFormat.removeQueue(*item.status)
o.items[id] = QueueLayoutItem{}
}
}
func (o QueueLayoutObject) ChangeQueueStatus(queueId int, queue *Queue) {
if item, ok := o.items[queueId]; ok {
statusColor := o.getStatusColor(queue.Status)
item.StatusMessage.Text = o.getStatusTitle(queue.Status)
item.StatusMessage.Color = statusColor
fyne.Do(func() {
item.StatusMessage.Refresh()
})
if queue.Error != nil {
item.MessageError.Text = queue.Error.Error()
item.MessageError.Color = statusColor
fyne.Do(func() {
item.BlockMessageError.Show()
item.MessageError.Refresh()
})
}
if queue.Status == StatusType(Completed) {
item.buttonPlay.Show()
item.buttonPlay.OnTapped = func() {
item.buttonPlay.Disable()
go func() {
_ = o.ffplayService.Run(FFplaySetting{
PathToFile: queue.Setting.VideoFileOut.Path,
})
fyne.Do(func() {
item.buttonPlay.Enable()
})
}()
}
}
if o.queueStatisticsFormat.isChecked(queue.Status) == false && item.CanvasObject.Visible() == true {
item.CanvasObject.Hide()
} else if item.CanvasObject.Visible() == false {
item.CanvasObject.Show()
}
o.queueStatisticsFormat.changeQueue(queue.Status)
}
}
func (o QueueLayoutObject) getStatusColor(status StatusContract) color.Color {
if status == StatusType(Error) {
return theme.Color(theme.ColorNameError)
}
if status == StatusType(Completed) {
return color.RGBA{R: 49, G: 127, B: 114, A: 255}
}
return theme.Color(theme.ColorNamePrimary)
}
func (o QueueLayoutObject) getStatusTitle(status StatusContract) string {
return o.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: status.Name() + "Queue"})
}
type queueStatistics struct {
widget *widget.Check
title string
count *int64
}
type queueStatisticsFormat struct {
waiting *queueStatistics
inProgress *queueStatistics
completed *queueStatistics
error *queueStatistics
total *queueStatistics
}
func newQueueStatisticsFormat(localizerService LocalizerContract, queueItems *map[int]QueueLayoutItem) *queueStatisticsFormat {
checkWaiting := newQueueStatistics("waitingQueue", localizerService)
checkInProgress := newQueueStatistics("inProgressQueue", localizerService)
checkCompleted := newQueueStatistics("completedQueue", localizerService)
checkError := newQueueStatistics("errorQueue", localizerService)
checkTotal := newQueueStatistics("total", localizerService)
queueStatisticsFormat := &queueStatisticsFormat{
waiting: checkWaiting,
inProgress: checkInProgress,
completed: checkCompleted,
error: checkError,
total: checkTotal,
}
checkTotal.widget.OnChanged = func(b bool) {
if b == true {
queueStatisticsFormat.allCheckboxChecked()
} else {
queueStatisticsFormat.allUnCheckboxChecked()
}
queueStatisticsFormat.redrawingQueueItems(queueItems)
}
queueStatisticsFormat.waiting.widget.OnChanged = func(b bool) {
if b == true {
queueStatisticsFormat.checkboxChecked()
} else {
queueStatisticsFormat.unCheckboxChecked()
}
queueStatisticsFormat.redrawingQueueItems(queueItems)
}
queueStatisticsFormat.inProgress.widget.OnChanged = func(b bool) {
if b == true {
queueStatisticsFormat.checkboxChecked()
} else {
queueStatisticsFormat.unCheckboxChecked()
}
queueStatisticsFormat.redrawingQueueItems(queueItems)
}
queueStatisticsFormat.completed.widget.OnChanged = func(b bool) {
if b == true {
queueStatisticsFormat.checkboxChecked()
} else {
queueStatisticsFormat.unCheckboxChecked()
}
queueStatisticsFormat.redrawingQueueItems(queueItems)
}
queueStatisticsFormat.error.widget.OnChanged = func(b bool) {
if b == true {
queueStatisticsFormat.checkboxChecked()
} else {
queueStatisticsFormat.unCheckboxChecked()
}
queueStatisticsFormat.redrawingQueueItems(queueItems)
}
return queueStatisticsFormat
}
func (f queueStatisticsFormat) redrawingQueueItems(queueItems *map[int]QueueLayoutItem) {
for _, item := range *queueItems {
if f.isChecked(*item.status) == true && item.CanvasObject.Visible() == false {
item.CanvasObject.Show()
continue
}
if f.isChecked(*item.status) == false && item.CanvasObject.Visible() == true {
item.CanvasObject.Hide()
}
}
}
func (f queueStatisticsFormat) isChecked(status StatusContract) bool {
if status == StatusType(InProgress) {
return f.inProgress.widget.Checked
}
if status == StatusType(Completed) {
return f.completed.widget.Checked
}
if status == StatusType(Error) {
return f.error.widget.Checked
}
if status == StatusType(Waiting) {
return f.waiting.widget.Checked
}
return true
}
func (f queueStatisticsFormat) addQueue() {
f.waiting.add()
f.total.add()
}
func (f queueStatisticsFormat) changeQueue(status StatusContract) {
if status == StatusType(InProgress) {
f.waiting.remove()
f.inProgress.add()
return
}
if status == StatusType(Completed) {
f.inProgress.remove()
f.completed.add()
return
}
if status == StatusType(Error) {
f.inProgress.remove()
f.error.add()
return
}
}
func (f queueStatisticsFormat) removeQueue(status StatusContract) {
f.total.remove()
if status == StatusType(Completed) {
f.completed.remove()
return
}
if status == StatusType(Error) {
f.error.remove()
return
}
if status == StatusType(InProgress) {
f.inProgress.remove()
return
}
if status == StatusType(Waiting) {
f.waiting.remove()
return
}
}
func (f queueStatisticsFormat) checkboxChecked() {
if f.total.widget.Checked == true {
return
}
if f.waiting.widget.Checked == false {
return
}
if f.inProgress.widget.Checked == false {
return
}
if f.completed.widget.Checked == false {
return
}
if f.error.widget.Checked == false {
return
}
f.total.widget.Checked = true
f.total.widget.Refresh()
}
func (f queueStatisticsFormat) unCheckboxChecked() {
if f.total.widget.Checked == false {
return
}
f.total.widget.Checked = false
f.total.widget.Refresh()
}
func (f queueStatisticsFormat) allCheckboxChecked() {
f.waiting.widget.Checked = true
f.waiting.widget.Refresh()
f.inProgress.widget.Checked = true
f.inProgress.widget.Refresh()
f.completed.widget.Checked = true
f.completed.widget.Refresh()
f.error.widget.Checked = true
f.error.widget.Refresh()
}
func (f queueStatisticsFormat) allUnCheckboxChecked() {
f.waiting.widget.Checked = false
f.waiting.widget.Refresh()
f.inProgress.widget.Checked = false
f.inProgress.widget.Refresh()
f.completed.widget.Checked = false
f.completed.widget.Refresh()
f.error.widget.Checked = false
f.error.widget.Refresh()
}
func newQueueStatistics(messaigeID string, localizerService LocalizerContract) *queueStatistics {
checkbox := widget.NewCheck("", nil)
checkbox.Checked = true
count := int64(0)
title := localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: messaigeID})
queueStatistics := &queueStatistics{
widget: checkbox,
title: strings.ToLower(title),
count: &count,
}
queueStatistics.formatText(false)
localizerService.AddChangeCallback(messaigeID, func(text string) {
queueStatistics.title = strings.ToLower(text)
queueStatistics.formatText(true)
queueStatistics.widget.Refresh()
})
return queueStatistics
}
func (s queueStatistics) add() {
*s.count += 1
s.formatText(true)
}
func (s queueStatistics) remove() {
if *s.count == 0 {
return
}
*s.count -= 1
s.formatText(true)
}
func (s queueStatistics) formatText(refresh bool) {
s.widget.Text = s.title + ": " + strconv.FormatInt(*s.count, 10)
if refresh == true {
fyne.Do(func() {
s.widget.Refresh()
})
}
}