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() }) } }