diff --git a/convertor/view.go b/convertor/view.go index 2ac293d..0510768 100644 --- a/convertor/view.go +++ b/convertor/view.go @@ -5,11 +5,9 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "github.com/nicksnyder/go-i18n/v2/i18n" "image/color" "path/filepath" @@ -17,7 +15,7 @@ import ( type ViewContract interface { Main( - runConvert func(setting HandleConvertSetting, progressbar *widget.ProgressBar) error, + runConvert func(setting HandleConvertSetting), ) SelectFFPath( ffmpegPath string, @@ -29,12 +27,11 @@ type ViewContract interface { } type View struct { - w fyne.Window - localizerService localizer.ServiceContract + app kernel.AppContract } type HandleConvertSetting struct { - VideoFileInput *File + VideoFileInput kernel.File DirectoryForSave string OverwriteOutputFiles bool } @@ -45,15 +42,14 @@ type enableFormConversionStruct struct { form *widget.Form } -func NewView(w fyne.Window, localizerService localizer.ServiceContract) *View { +func NewView(app kernel.AppContract) *View { return &View{ - w: w, - localizerService: localizerService, + app: app, } } func (v View) Main( - runConvert func(setting HandleConvertSetting, progressbar *widget.ProgressBar) error, + runConvert func(setting HandleConvertSetting), ) { form := &widget.Form{} @@ -61,13 +57,11 @@ func (v View) Main( conversionMessage.TextSize = 16 conversionMessage.TextStyle = fyne.TextStyle{Bold: true} - progress := widget.NewProgressBar() - - fileVideoForConversion, fileVideoForConversionMessage, fileInput := v.getButtonFileVideoForConversion(form, progress, conversionMessage) + fileVideoForConversion, fileVideoForConversionMessage, fileInput := v.getButtonFileVideoForConversion(form, conversionMessage) buttonForSelectedDir, buttonForSelectedDirMessage, pathToSaveDirectory := v.getButtonForSelectingDirectoryForSaving() isOverwriteOutputFiles := false - checkboxOverwriteOutputFilesTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + checkboxOverwriteOutputFilesTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "checkboxOverwriteOutputFilesTitle", }) checkboxOverwriteOutputFiles := widget.NewCheck(checkboxOverwriteOutputFilesTitle, func(b bool) { @@ -76,14 +70,14 @@ func (v View) Main( form.Items = []*widget.FormItem{ { - Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "fileVideoForConversionTitle"}), + Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{MessageID: "fileVideoForConversionTitle"}), Widget: fileVideoForConversion, }, { Widget: container.NewHScroll(fileVideoForConversionMessage), }, { - Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "buttonForSelectedDirTitle"}), + Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{MessageID: "buttonForSelectedDirTitle"}), Widget: buttonForSelectedDir, }, { @@ -93,7 +87,7 @@ func (v View) Main( Widget: checkboxOverwriteOutputFiles, }, } - form.SubmitText = v.localizerService.GetMessage(&i18n.LocalizeConfig{ + form.SubmitText = v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "converterVideoFilesSubmitTitle", }) @@ -105,7 +99,7 @@ func (v View) Main( form.OnSubmit = func() { if len(*pathToSaveDirectory) == 0 { - showConversionMessage(conversionMessage, errors.New(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + showConversionMessage(conversionMessage, errors.New(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "errorSelectedFolderSave", }))) enableFormConversion(enableFormConversionStruct) @@ -118,71 +112,61 @@ func (v View) Main( form.Disable() setting := HandleConvertSetting{ - VideoFileInput: fileInput, + VideoFileInput: *fileInput, DirectoryForSave: *pathToSaveDirectory, OverwriteOutputFiles: isOverwriteOutputFiles, } - err := runConvert(setting, progress) - if err != nil { - showConversionMessage(conversionMessage, err) - enableFormConversion(enableFormConversionStruct) - return - } + runConvert(setting) enableFormConversion(enableFormConversionStruct) + + fileVideoForConversionMessage.Text = "" + form.Disable() } - converterVideoFilesTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + converterVideoFilesTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "converterVideoFilesTitle", }) - v.w.SetContent(widget.NewCard(converterVideoFilesTitle, "", container.NewVBox(form, conversionMessage, progress))) + v.app.GetWindow().SetContent(widget.NewCard(converterVideoFilesTitle, "", container.NewVBox(form, conversionMessage))) form.Disable() } -func (v View) getButtonFileVideoForConversion(form *widget.Form, progress *widget.ProgressBar, conversionMessage *canvas.Text) (*widget.Button, *canvas.Text, *File) { - fileInput := &File{} +func (v View) getButtonFileVideoForConversion(form *widget.Form, conversionMessage *canvas.Text) (*widget.Button, *canvas.Text, *kernel.File) { + fileInput := &kernel.File{} fileVideoForConversionMessage := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255}) fileVideoForConversionMessage.TextSize = 16 fileVideoForConversionMessage.TextStyle = fyne.TextStyle{Bold: true} - buttonTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + buttonTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "choose", }) var locationURI fyne.ListableURI button := widget.NewButton(buttonTitle, func() { - fileDialog := dialog.NewFileOpen( - func(r fyne.URIReadCloser, err error) { - if err != nil { - fileVideoForConversionMessage.Text = err.Error() - setStringErrorStyle(fileVideoForConversionMessage) - return - } - if r == nil { - return - } + v.app.GetWindow().NewFileOpen(func(r fyne.URIReadCloser, err error) { + if err != nil { + fileVideoForConversionMessage.Text = err.Error() + setStringErrorStyle(fileVideoForConversionMessage) + return + } + if r == nil { + return + } - fileInput.Path = r.URI().Path() - fileInput.Name = r.URI().Name() - fileInput.Ext = r.URI().Extension() + fileInput.Path = r.URI().Path() + fileInput.Name = r.URI().Name() + fileInput.Ext = r.URI().Extension() - fileVideoForConversionMessage.Text = r.URI().Path() - setStringSuccessStyle(fileVideoForConversionMessage) + fileVideoForConversionMessage.Text = r.URI().Path() + setStringSuccessStyle(fileVideoForConversionMessage) - form.Enable() - progress.Value = 0 - progress.Refresh() - conversionMessage.Text = "" + form.Enable() + conversionMessage.Text = "" - listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path())) - locationURI, err = storage.ListerForURI(listableURI) - }, v.w) - helper.FileDialogResize(fileDialog, v.w) - fileDialog.Show() - if locationURI != nil { - fileDialog.SetLocation(locationURI) - } + listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path())) + locationURI, err = storage.ListerForURI(listableURI) + }, locationURI) }) return button, fileVideoForConversionMessage, fileInput @@ -196,36 +180,30 @@ func (v View) getButtonForSelectingDirectoryForSaving() (button *widget.Button, path := "" dirPath = &path - buttonTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + buttonTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "choose", }) var locationURI fyne.ListableURI button = widget.NewButton(buttonTitle, func() { - fileDialog := dialog.NewFolderOpen( - func(r fyne.ListableURI, err error) { - if err != nil { - buttonMessage.Text = err.Error() - setStringErrorStyle(buttonMessage) - return - } - if r == nil { - return - } + v.app.GetWindow().NewFolderOpen(func(r fyne.ListableURI, err error) { + if err != nil { + buttonMessage.Text = err.Error() + setStringErrorStyle(buttonMessage) + return + } + if r == nil { + return + } - path = r.Path() + path = r.Path() - buttonMessage.Text = r.Path() - setStringSuccessStyle(buttonMessage) - locationURI, _ = storage.ListerForURI(r) + buttonMessage.Text = r.Path() + setStringSuccessStyle(buttonMessage) + locationURI, _ = storage.ListerForURI(r) - }, v.w) - helper.FileDialogResize(fileDialog, v.w) - fileDialog.Show() - if locationURI != nil { - fileDialog.SetLocation(locationURI) - } + }, locationURI) }) return diff --git a/convertor/view_setting.go b/convertor/view_setting.go index 703259f..62e8ad5 100644 --- a/convertor/view_setting.go +++ b/convertor/view_setting.go @@ -4,10 +4,8 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper" "github.com/nicksnyder/go-i18n/v2/i18n" "image/color" "net/url" @@ -37,13 +35,13 @@ func (v View) SelectFFPath( form := &widget.Form{ Items: []*widget.FormItem{ { - Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{ + Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "titleDownloadLink", }), Widget: link, }, { - Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{ + Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "pathToFfmpeg", }), Widget: buttonFFmpeg, @@ -52,7 +50,7 @@ func (v View) SelectFFPath( Widget: container.NewHScroll(buttonFFmpegMessage), }, { - Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{ + Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "pathToFfprobe", }), Widget: buttonFFprobe, @@ -64,7 +62,7 @@ func (v View) SelectFFPath( Widget: errorMessage, }, }, - SubmitText: v.localizerService.GetMessage(&i18n.LocalizeConfig{ + SubmitText: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "save", }), OnSubmit: func() { @@ -76,15 +74,15 @@ func (v View) SelectFFPath( } if cancel != nil { form.OnCancel = cancel - form.CancelText = v.localizerService.GetMessage(&i18n.LocalizeConfig{ + form.CancelText = v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "cancel", }) } - selectFFPathTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + selectFFPathTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "selectFFPathTitle", }) - v.w.SetContent(widget.NewCard(selectFFPathTitle, "", container.NewVBox( + v.app.GetWindow().SetContent(widget.NewCard(selectFFPathTitle, "", container.NewVBox( form, v.blockDownloadFFmpeg(donwloadFFmpeg), ))) @@ -97,7 +95,7 @@ func (v View) getButtonSelectFile(path string) (filePath *string, button *widget buttonMessage.TextSize = 16 buttonMessage.TextStyle = fyne.TextStyle{Bold: true} - buttonTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + buttonTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "choose", }) @@ -108,30 +106,24 @@ func (v View) getButtonSelectFile(path string) (filePath *string, button *widget } button = widget.NewButton(buttonTitle, func() { - fileDialog := dialog.NewFileOpen( - func(r fyne.URIReadCloser, err error) { - if err != nil { - buttonMessage.Text = err.Error() - setStringErrorStyle(buttonMessage) - return - } - if r == nil { - return - } + v.app.GetWindow().NewFileOpen(func(r fyne.URIReadCloser, err error) { + if err != nil { + buttonMessage.Text = err.Error() + setStringErrorStyle(buttonMessage) + return + } + if r == nil { + return + } - path = r.URI().Path() + path = r.URI().Path() - buttonMessage.Text = r.URI().Path() - setStringSuccessStyle(buttonMessage) + buttonMessage.Text = r.URI().Path() + setStringSuccessStyle(buttonMessage) - listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path())) - locationURI, _ = storage.ListerForURI(listableURI) - }, v.w) - helper.FileDialogResize(fileDialog, v.w) - fileDialog.Show() - if locationURI != nil { - fileDialog.SetLocation(locationURI) - } + listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path())) + locationURI, _ = storage.ListerForURI(listableURI) + }, locationURI) }) return diff --git a/error/view.go b/error/view.go index f34d72b..4845ab0 100644 --- a/error/view.go +++ b/error/view.go @@ -1,9 +1,9 @@ package error import ( - "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/widget" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" "github.com/nicksnyder/go-i18n/v2/i18n" ) @@ -13,23 +13,21 @@ type ViewContract interface { } type View struct { - w fyne.Window - localizerService localizer.ServiceContract + app kernel.AppContract } -func NewView(w fyne.Window, localizerService localizer.ServiceContract) *View { +func NewView(app kernel.AppContract) *View { return &View{ - w: w, - localizerService: localizerService, + app: app, } } func (v View) PanicError(err error) { - messageHead := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + messageHead := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "error", }) - v.w.SetContent(container.NewBorder( + v.app.GetWindow().SetContent(container.NewBorder( container.NewVBox( widget.NewLabel(messageHead), widget.NewLabel(err.Error()), @@ -37,21 +35,21 @@ func (v View) PanicError(err error) { nil, nil, nil, - localizer.LanguageSelectionForm(v.localizerService, func(lang localizer.Lang) { + localizer.LanguageSelectionForm(v.app.GetLocalizerService(), func(lang kernel.Lang) { v.PanicError(err) }), )) } func (v View) PanicErrorWriteDirectoryData() { - message := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + message := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "errorDatabase", }) - messageHead := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + messageHead := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "error", }) - v.w.SetContent(container.NewBorder( + v.app.GetWindow().SetContent(container.NewBorder( container.NewVBox( widget.NewLabel(messageHead), widget.NewLabel(message), @@ -59,7 +57,7 @@ func (v View) PanicErrorWriteDirectoryData() { nil, nil, nil, - localizer.LanguageSelectionForm(v.localizerService, func(lang localizer.Lang) { + localizer.LanguageSelectionForm(v.app.GetLocalizerService(), func(lang kernel.Lang) { v.PanicErrorWriteDirectoryData() }), )) diff --git a/handler/convertor.go b/handler/convertor.go index 5a2cff1..909e908 100644 --- a/handler/convertor.go +++ b/handler/convertor.go @@ -1,17 +1,11 @@ package handler import ( - "bufio" "errors" - "fyne.io/fyne/v2/widget" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/convertor" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "github.com/nicksnyder/go-i18n/v2/i18n" - "io" - "regexp" - "strconv" - "strings" ) type ConvertorHandlerContract interface { @@ -22,23 +16,20 @@ type ConvertorHandlerContract interface { } type ConvertorHandler struct { - convertorService convertor.ServiceContract + app kernel.AppContract convertorView convertor.ViewContract convertorRepository convertor.RepositoryContract - localizerService localizer.ServiceContract } func NewConvertorHandler( - convertorService convertor.ServiceContract, + app kernel.AppContract, convertorView convertor.ViewContract, convertorRepository convertor.RepositoryContract, - localizerService localizer.ServiceContract, ) *ConvertorHandler { return &ConvertorHandler{ - convertorService: convertorService, + app: app, convertorView: convertorView, convertorRepository: convertorRepository, - localizerService: localizerService, } } @@ -57,32 +48,23 @@ func (h ConvertorHandler) FfPathSelection() { } func (h ConvertorHandler) GetFfmpegVersion() (string, error) { - return h.convertorService.GetFFmpegVesrion() + return h.app.GetConvertorService().GetFFmpegVesrion() } func (h ConvertorHandler) GetFfprobeVersion() (string, error) { - return h.convertorService.GetFFprobeVersion() + return h.app.GetConvertorService().GetFFprobeVersion() } -func (h ConvertorHandler) runConvert(setting convertor.HandleConvertSetting, progressbar *widget.ProgressBar) error { - totalDuration, err := h.convertorService.GetTotalDuration(setting.VideoFileInput) - if err != nil { - return err - } - progress := NewProgress(totalDuration, progressbar, h.localizerService) - - return h.convertorService.RunConvert( - convertor.ConvertSetting{ - VideoFileInput: setting.VideoFileInput, - VideoFileOut: &convertor.File{ - Path: setting.DirectoryForSave + helper.PathSeparator() + setting.VideoFileInput.Name + ".mp4", - Name: setting.VideoFileInput.Name, - Ext: ".mp4", - }, - OverwriteOutputFiles: setting.OverwriteOutputFiles, +func (h ConvertorHandler) runConvert(setting convertor.HandleConvertSetting) { + h.app.GetQueue().Add(&kernel.ConvertSetting{ + VideoFileInput: setting.VideoFileInput, + VideoFileOut: kernel.File{ + Path: setting.DirectoryForSave + helper.PathSeparator() + setting.VideoFileInput.Name + ".mp4", + Name: setting.VideoFileInput.Name, + Ext: ".mp4", }, - progress, - ) + OverwriteOutputFiles: setting.OverwriteOutputFiles, + }) } func (h ConvertorHandler) checkingFFPathUtilities() bool { @@ -92,11 +74,11 @@ func (h ConvertorHandler) checkingFFPathUtilities() bool { pathsToFF := getPathsToFF() for _, item := range pathsToFF { - ffmpegChecking, _ := h.convertorService.ChangeFFmpegPath(item.FFmpeg) + ffmpegChecking, _ := h.app.GetConvertorService().ChangeFFmpegPath(item.FFmpeg) if ffmpegChecking == false { continue } - ffprobeChecking, _ := h.convertorService.ChangeFFprobePath(item.FFprobe) + ffprobeChecking, _ := h.app.GetConvertorService().ChangeFFprobePath(item.FFprobe) if ffprobeChecking == false { continue } @@ -109,17 +91,17 @@ func (h ConvertorHandler) checkingFFPathUtilities() bool { } func (h ConvertorHandler) saveSettingFFPath(ffmpegPath string, ffprobePath string) error { - ffmpegChecking, _ := h.convertorService.ChangeFFmpegPath(ffmpegPath) + ffmpegChecking, _ := h.app.GetConvertorService().ChangeFFmpegPath(ffmpegPath) if ffmpegChecking == false { - errorText := h.localizerService.GetMessage(&i18n.LocalizeConfig{ + errorText := h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "errorFFmpeg", }) return errors.New(errorText) } - ffprobeChecking, _ := h.convertorService.ChangeFFprobePath(ffprobePath) + ffprobeChecking, _ := h.app.GetConvertorService().ChangeFFprobePath(ffprobePath) if ffprobeChecking == false { - errorText := h.localizerService.GetMessage(&i18n.LocalizeConfig{ + errorText := h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "errorFFprobe", }) return errors.New(errorText) @@ -134,105 +116,15 @@ func (h ConvertorHandler) saveSettingFFPath(ffmpegPath string, ffprobePath strin } func (h ConvertorHandler) checkingFFPath() bool { - _, err := h.convertorService.GetFFmpegVesrion() + _, err := h.app.GetConvertorService().GetFFmpegVesrion() if err != nil { return false } - _, err = h.convertorService.GetFFprobeVersion() + _, err = h.app.GetConvertorService().GetFFprobeVersion() if err != nil { return false } return true } - -type Progress struct { - totalDuration float64 - progressbar *widget.ProgressBar - protocol string - localizerService localizer.ServiceContract -} - -func NewProgress(totalDuration float64, progressbar *widget.ProgressBar, localizerService localizer.ServiceContract) Progress { - return Progress{ - totalDuration: totalDuration, - progressbar: progressbar, - protocol: "pipe:", - localizerService: localizerService, - } -} - -func (p Progress) GetProtocole() string { - return p.protocol -} - -func (p Progress) Run(stdOut io.ReadCloser, stdErr io.ReadCloser) error { - isProcessCompleted := false - var errorText string - - p.progressbar.Value = 0 - p.progressbar.Max = p.totalDuration - p.progressbar.Refresh() - - progress := 0.0 - - go func() { - scannerErr := bufio.NewReader(stdErr) - for { - line, _, err := scannerErr.ReadLine() - if err != nil { - if err == io.EOF { - break - } - continue - } - data := strings.TrimSpace(string(line)) - errorText = data - } - }() - - scannerOut := bufio.NewReader(stdOut) - for { - line, _, err := scannerOut.ReadLine() - if err != nil { - if err == io.EOF { - break - } - continue - } - data := strings.TrimSpace(string(line)) - if strings.Contains(data, "progress=end") { - p.progressbar.Value = p.totalDuration - p.progressbar.Refresh() - isProcessCompleted = true - break - } - - re := regexp.MustCompile(`frame=(\d+)`) - a := re.FindAllStringSubmatch(data, -1) - - if len(a) > 0 && len(a[len(a)-1]) > 0 { - c, err := strconv.Atoi(a[len(a)-1][len(a[len(a)-1])-1]) - if err != nil { - continue - } - progress = float64(c) - } - if p.progressbar.Value != progress { - p.progressbar.Value = progress - p.progressbar.Refresh() - } - } - - if isProcessCompleted == false { - if len(errorText) == 0 { - errorText = p.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "errorConverter", - }) - } - return errors.New(errorText) - } - - return nil -} diff --git a/handler/convertor_anyos.go b/handler/convertor_anyos.go index 4db2fd4..409c524 100644 --- a/handler/convertor_anyos.go +++ b/handler/convertor_anyos.go @@ -6,11 +6,11 @@ package handler import ( "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/convertor" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" ) -func getPathsToFF() []convertor.FFPathUtilities { - return []convertor.FFPathUtilities{{"ffmpeg/bin/ffmpeg", "ffmpeg/bin/ffprobe"}, {"ffmpeg", "ffprobe"}} +func getPathsToFF() []kernel.FFPathUtilities { + return []kernel.FFPathUtilities{{"ffmpeg/bin/ffmpeg", "ffmpeg/bin/ffprobe"}, {"ffmpeg", "ffprobe"}} } func (h ConvertorHandler) downloadFFmpeg(progressBar *widget.ProgressBar, progressMessage *canvas.Text) (err error) { diff --git a/handler/convertor_windows.go b/handler/convertor_windows.go index 79732c5..14984fc 100644 --- a/handler/convertor_windows.go +++ b/handler/convertor_windows.go @@ -8,7 +8,7 @@ import ( "errors" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/convertor" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "github.com/nicksnyder/go-i18n/v2/i18n" "io" "net/http" @@ -17,8 +17,8 @@ import ( "strings" ) -func getPathsToFF() []convertor.FFPathUtilities { - return []convertor.FFPathUtilities{{"ffmpeg\\bin\\ffmpeg.exe", "ffmpeg\\bin\\ffprobe.exe"}} +func getPathsToFF() []kernel.FFPathUtilities { + return []kernel.FFPathUtilities{{"ffmpeg\\bin\\ffmpeg.exe", "ffmpeg\\bin\\ffprobe.exe"}} } func (h ConvertorHandler) downloadFFmpeg(progressBar *widget.ProgressBar, progressMessage *canvas.Text) (err error) { diff --git a/handler/main.go b/handler/main.go index 48b99a4..e2e6398 100644 --- a/handler/main.go +++ b/handler/main.go @@ -1,27 +1,28 @@ package handler import ( + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" ) type MainHandler struct { + app kernel.AppContract convertorHandler ConvertorHandlerContract menuHandler MenuHandlerContract localizerRepository localizer.RepositoryContract - localizerService localizer.ServiceContract } func NewMainHandler( + app kernel.AppContract, convertorHandler ConvertorHandlerContract, menuHandler MenuHandlerContract, localizerRepository localizer.RepositoryContract, - localizerService localizer.ServiceContract, ) *MainHandler { return &MainHandler{ + app: app, convertorHandler: convertorHandler, menuHandler: menuHandler, localizerRepository: localizerRepository, - localizerService: localizerService, } } @@ -31,7 +32,7 @@ func (h MainHandler) Start() { h.menuHandler.LanguageSelection() return } - _ = h.localizerService.SetCurrentLanguageByCode(language) + _ = h.app.GetLocalizerService().SetCurrentLanguageByCode(language) h.convertorHandler.MainConvertor() } diff --git a/handler/menu.go b/handler/menu.go index eabbef2..ca38d52 100644 --- a/handler/menu.go +++ b/handler/menu.go @@ -2,6 +2,7 @@ package handler import ( "fyne.io/fyne/v2" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/menu" "github.com/nicksnyder/go-i18n/v2/i18n" @@ -12,34 +13,30 @@ type MenuHandlerContract interface { LanguageSelection() } -type menuItems struct { - menuItem map[string]*fyne.MenuItem - menu map[string]*fyne.Menu -} - type MenuHandler struct { + app kernel.AppContract convertorHandler ConvertorHandlerContract menuView menu.ViewContract - localizerService localizer.ServiceContract localizerView localizer.ViewContract localizerRepository localizer.RepositoryContract - menuItems *menuItems + localizerListener localizerListenerContract } func NewMenuHandler( + app kernel.AppContract, convertorHandler ConvertorHandlerContract, menuView menu.ViewContract, - localizerService localizer.ServiceContract, localizerView localizer.ViewContract, localizerRepository localizer.RepositoryContract, + localizerListener localizerListenerContract, ) *MenuHandler { return &MenuHandler{ + app: app, convertorHandler: convertorHandler, menuView: menuView, - localizerService: localizerService, localizerView: localizerView, localizerRepository: localizerRepository, - menuItems: &menuItems{menuItem: map[string]*fyne.MenuItem{}, menu: map[string]*fyne.Menu{}}, + localizerListener: localizerListener, } } @@ -51,40 +48,40 @@ func (h MenuHandler) GetMainMenu() *fyne.MainMenu { } func (h MenuHandler) getMenuSettings() *fyne.Menu { - quit := fyne.NewMenuItem(h.localizerService.GetMessage(&i18n.LocalizeConfig{ + quit := fyne.NewMenuItem(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "exit", }), nil) quit.IsQuit = true - h.menuItems.menuItem["exit"] = quit + h.localizerListener.AddMenuItem("exit", quit) - languageSelection := fyne.NewMenuItem(h.localizerService.GetMessage(&i18n.LocalizeConfig{ + languageSelection := fyne.NewMenuItem(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "changeLanguage", }), h.LanguageSelection) - h.menuItems.menuItem["changeLanguage"] = languageSelection + h.localizerListener.AddMenuItem("changeLanguage", languageSelection) - ffPathSelection := fyne.NewMenuItem(h.localizerService.GetMessage(&i18n.LocalizeConfig{ + ffPathSelection := fyne.NewMenuItem(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "changeFFPath", }), h.convertorHandler.FfPathSelection) - h.menuItems.menuItem["changeFFPath"] = ffPathSelection + h.localizerListener.AddMenuItem("changeFFPath", ffPathSelection) - settings := fyne.NewMenu(h.localizerService.GetMessage(&i18n.LocalizeConfig{ + settings := fyne.NewMenu(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "settings", }), languageSelection, ffPathSelection, quit) - h.menuItems.menu["settings"] = settings + h.localizerListener.AddMenu("settings", settings) return settings } func (h MenuHandler) getMenuHelp() *fyne.Menu { - about := fyne.NewMenuItem(h.localizerService.GetMessage(&i18n.LocalizeConfig{ + about := fyne.NewMenuItem(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "about", }), h.openAbout) - h.menuItems.menuItem["about"] = about + h.localizerListener.AddMenuItem("about", about) - help := fyne.NewMenu(h.localizerService.GetMessage(&i18n.LocalizeConfig{ + help := fyne.NewMenu(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "help", }), about) - h.menuItems.menu["help"] = help + h.localizerListener.AddMenu("help", help) return help } @@ -92,13 +89,13 @@ func (h MenuHandler) getMenuHelp() *fyne.Menu { func (h MenuHandler) openAbout() { ffmpeg, err := h.convertorHandler.GetFfmpegVersion() if err != nil { - ffmpeg = h.localizerService.GetMessage(&i18n.LocalizeConfig{ + ffmpeg = h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "errorFFmpegVersion", }) } ffprobe, err := h.convertorHandler.GetFfprobeVersion() if err != nil { - ffprobe = h.localizerService.GetMessage(&i18n.LocalizeConfig{ + ffprobe = h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "errorFFprobeVersion", }) } @@ -107,19 +104,46 @@ func (h MenuHandler) openAbout() { } func (h MenuHandler) LanguageSelection() { - h.localizerView.LanguageSelection(func(lang localizer.Lang) { + h.localizerView.LanguageSelection(func(lang kernel.Lang) { _, _ = h.localizerRepository.Save(lang.Code) - h.menuMessageReload() h.convertorHandler.MainConvertor() }) } -func (h MenuHandler) menuMessageReload() { - for messageID, menu := range h.menuItems.menuItem { - menu.Label = h.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: messageID}) +type menuItems struct { + menuItem map[string]*fyne.MenuItem + menu map[string]*fyne.Menu +} + +type LocalizerListener struct { + menuItems *menuItems +} + +type localizerListenerContract interface { + AddMenu(messageID string, menu *fyne.Menu) + AddMenuItem(messageID string, menuItem *fyne.MenuItem) +} + +func NewLocalizerListener() *LocalizerListener { + return &LocalizerListener{ + &menuItems{menuItem: map[string]*fyne.MenuItem{}, menu: map[string]*fyne.Menu{}}, } - for messageID, menu := range h.menuItems.menu { - menu.Label = h.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: messageID}) +} + +func (l LocalizerListener) AddMenu(messageID string, menu *fyne.Menu) { + l.menuItems.menu[messageID] = menu +} + +func (l LocalizerListener) AddMenuItem(messageID string, menuItem *fyne.MenuItem) { + l.menuItems.menuItem[messageID] = menuItem +} + +func (l LocalizerListener) Change(localizerService kernel.LocalizerContract) { + for messageID, menu := range l.menuItems.menuItem { + menu.Label = localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: messageID}) + } + for messageID, menu := range l.menuItems.menu { + menu.Label = localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: messageID}) menu.Refresh() } } diff --git a/kernel/app.go b/kernel/app.go new file mode 100644 index 0000000..54a82f1 --- /dev/null +++ b/kernel/app.go @@ -0,0 +1,105 @@ +package kernel + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "time" +) + +type AppContract interface { + GetAppFyne() fyne.App + GetWindow() WindowContract + GetQueue() QueueListContract + GetLocalizerService() LocalizerContract + GetConvertorService() ConvertorContract + AfterClosing() + RunConvertor() +} + +type App struct { + AppFyne fyne.App + Window WindowContract + Queue QueueListContract + + localizerService LocalizerContract + convertorService ConvertorContract +} + +func NewApp( + metadata *fyne.AppMetadata, + localizerService LocalizerContract, + queue QueueListContract, + queueLayoutObject QueueLayoutObjectContract, + convertorService ConvertorContract, +) *App { + app.SetMetadata(*metadata) + a := app.New() + + return &App{ + AppFyne: a, + Window: newWindow(a.NewWindow("GUI for FFmpeg"), NewLayout(queueLayoutObject, localizerService)), + Queue: queue, + + localizerService: localizerService, + convertorService: convertorService, + } +} + +func (a App) GetAppFyne() fyne.App { + return a.AppFyne +} + +func (a App) GetQueue() QueueListContract { + return a.Queue +} + +func (a App) GetWindow() WindowContract { + return a.Window +} + +func (a App) GetLocalizerService() LocalizerContract { + return a.localizerService +} + +func (a App) GetConvertorService() ConvertorContract { + return a.convertorService +} + +func (a App) AfterClosing() { + for _, cmd := range a.convertorService.GetRunningProcesses() { + _ = cmd.Process.Kill() + } +} + +func (a App) RunConvertor() { + go func() { + for { + time.Sleep(time.Millisecond * 3000) + queueId, queue := a.Queue.Next() + if queue == nil { + continue + } + queue.Status = StatusType(InProgress) + a.Window.GetLayout().ChangeQueueStatus(queueId, queue) + + totalDuration, err := a.convertorService.GetTotalDuration(&queue.Setting.VideoFileInput) + if err != nil { + queue.Status = StatusType(Error) + queue.Error = err + a.Window.GetLayout().ChangeQueueStatus(queueId, queue) + continue + } + progress := a.Window.GetLayout().NewProgressbar(queueId, totalDuration) + + err = a.convertorService.RunConvert(*queue.Setting, progress) + if err != nil { + queue.Status = StatusType(Error) + queue.Error = err + a.Window.GetLayout().ChangeQueueStatus(queueId, queue) + continue + } + queue.Status = StatusType(Completed) + a.Window.GetLayout().ChangeQueueStatus(queueId, queue) + } + }() +} diff --git a/convertor/service.go b/kernel/convertor.go similarity index 80% rename from convertor/service.go rename to kernel/convertor.go index 9b89f1f..8441fa1 100644 --- a/convertor/service.go +++ b/kernel/convertor.go @@ -1,4 +1,4 @@ -package convertor +package kernel import ( "errors" @@ -10,7 +10,7 @@ import ( "strings" ) -type ServiceContract interface { +type ConvertorContract interface { RunConvert(setting ConvertSetting, progress ProgressContract) error GetTotalDuration(file *File) (float64, error) GetFFmpegVesrion() (string, error) @@ -35,35 +35,23 @@ type runningProcesses struct { numberOfStarts int } -type Service struct { +type Convertor struct { ffPathUtilities *FFPathUtilities runningProcesses runningProcesses } -type File struct { - Path string - Name string - Ext string -} - -type ConvertSetting struct { - VideoFileInput *File - VideoFileOut *File - OverwriteOutputFiles bool -} - type ConvertData struct { totalDuration float64 } -func NewService(ffPathUtilities FFPathUtilities) *Service { - return &Service{ - ffPathUtilities: &ffPathUtilities, +func NewService(ffPathUtilities *FFPathUtilities) *Convertor { + return &Convertor{ + ffPathUtilities: ffPathUtilities, runningProcesses: runningProcesses{items: map[int]*exec.Cmd{}, numberOfStarts: 0}, } } -func (s Service) RunConvert(setting ConvertSetting, progress ProgressContract) error { +func (s Convertor) RunConvert(setting ConvertSetting, progress ProgressContract) error { overwriteOutputFiles := "-n" if setting.OverwriteOutputFiles == true { overwriteOutputFiles = "-y" @@ -103,7 +91,7 @@ func (s Service) RunConvert(setting ConvertSetting, progress ProgressContract) e return nil } -func (s Service) GetTotalDuration(file *File) (duration float64, err error) { +func (s Convertor) GetTotalDuration(file *File) (duration float64, err error) { args := []string{"-v", "error", "-select_streams", "v:0", "-count_packets", "-show_entries", "stream=nb_read_packets", "-of", "csv=p=0", file.Path} cmd := exec.Command(s.ffPathUtilities.FFprobe, args...) helper.PrepareBackgroundCommand(cmd) @@ -118,7 +106,7 @@ func (s Service) GetTotalDuration(file *File) (duration float64, err error) { return strconv.ParseFloat(strings.TrimSpace(string(out)), 64) } -func (s Service) GetFFmpegVesrion() (string, error) { +func (s Convertor) GetFFmpegVesrion() (string, error) { cmd := exec.Command(s.ffPathUtilities.FFmpeg, "-version") helper.PrepareBackgroundCommand(cmd) out, err := cmd.CombinedOutput() @@ -129,7 +117,7 @@ func (s Service) GetFFmpegVesrion() (string, error) { return text[0], nil } -func (s Service) GetFFprobeVersion() (string, error) { +func (s Convertor) GetFFprobeVersion() (string, error) { cmd := exec.Command(s.ffPathUtilities.FFprobe, "-version") helper.PrepareBackgroundCommand(cmd) out, err := cmd.CombinedOutput() @@ -140,7 +128,7 @@ func (s Service) GetFFprobeVersion() (string, error) { return text[0], nil } -func (s Service) ChangeFFmpegPath(path string) (bool, error) { +func (s Convertor) ChangeFFmpegPath(path string) (bool, error) { cmd := exec.Command(path, "-version") helper.PrepareBackgroundCommand(cmd) out, err := cmd.CombinedOutput() @@ -154,7 +142,7 @@ func (s Service) ChangeFFmpegPath(path string) (bool, error) { return true, nil } -func (s Service) ChangeFFprobePath(path string) (bool, error) { +func (s Convertor) ChangeFFprobePath(path string) (bool, error) { cmd := exec.Command(path, "-version") helper.PrepareBackgroundCommand(cmd) out, err := cmd.CombinedOutput() @@ -168,6 +156,6 @@ func (s Service) ChangeFFprobePath(path string) (bool, error) { return true, nil } -func (s Service) GetRunningProcesses() map[int]*exec.Cmd { +func (s Convertor) GetRunningProcesses() map[int]*exec.Cmd { return s.runningProcesses.items } diff --git a/kernel/error.go b/kernel/error.go new file mode 100644 index 0000000..7f03ea1 --- /dev/null +++ b/kernel/error.go @@ -0,0 +1,20 @@ +package kernel + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" +) + +func PanicErrorLang(err error, metadata *fyne.AppMetadata) { + app.SetMetadata(*metadata) + a := app.New() + window := a.NewWindow("GUI for FFmpeg") + window.SetContent(container.NewVBox( + widget.NewLabel("Произошла ошибка!"), + widget.NewLabel("произошла ошибка при получении языковых переводах. \n\r"+err.Error()), + )) + window.ShowAndRun() + panic(err.Error()) +} diff --git a/kernel/layout.go b/kernel/layout.go new file mode 100644 index 0000000..4b740d4 --- /dev/null +++ b/kernel/layout.go @@ -0,0 +1,288 @@ +package kernel + +import ( + "bufio" + "errors" + "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" + "io" + "regexp" + "strconv" + "strings" +) + +type LayoutContract interface { + SetContent(content fyne.CanvasObject) *fyne.Container + NewProgressbar(queueId int, totalDuration float64) ProgressContract + ChangeQueueStatus(queueId int, queue *Queue) +} + +type Layout struct { + layout *fyne.Container + queueLayoutObject QueueLayoutObjectContract + localizerService LocalizerContract +} + +func NewLayout(queueLayoutObject QueueLayoutObjectContract, localizerService LocalizerContract) *Layout { + layout := container.NewAdaptiveGrid(2, widget.NewLabel(""), container.NewVScroll(queueLayoutObject.GetCanvasObject())) + + return &Layout{ + layout: layout, + queueLayoutObject: queueLayoutObject, + localizerService: localizerService, + } +} + +func (l Layout) SetContent(content fyne.CanvasObject) *fyne.Container { + l.layout.Objects[0] = content + return l.layout +} + +func (l Layout) NewProgressbar(queueId int, totalDuration float64) ProgressContract { + progressbar := l.queueLayoutObject.GetProgressbar(queueId) + return NewProgress(totalDuration, progressbar, l.localizerService) +} + +func (l Layout) ChangeQueueStatus(queueId int, queue *Queue) { + l.queueLayoutObject.ChangeQueueStatus(queueId, queue) +} + +type QueueLayoutObjectContract interface { + GetCanvasObject() fyne.CanvasObject + GetProgressbar(queueId int) *widget.ProgressBar + ChangeQueueStatus(queueId int, queue *Queue) +} + +type QueueLayoutObject struct { + QueueListContract QueueListContract + + queue QueueListContract + container *fyne.Container + items map[int]QueueLayoutItem + localizerService LocalizerContract + layoutLocalizerListener LayoutLocalizerListenerContract +} + +type QueueLayoutItem struct { + CanvasObject fyne.CanvasObject + ProgressBar *widget.ProgressBar + StatusMessage *canvas.Text + MessageError *canvas.Text +} + +func NewQueueLayoutObject(queue QueueListContract, localizerService LocalizerContract, layoutLocalizerListener LayoutLocalizerListenerContract) *QueueLayoutObject { + title := widget.NewLabel(localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "queue"}) + ":") + title.TextStyle.Bold = true + + layoutLocalizerListener.AddItem("queue", title) + + queueLayoutObject := &QueueLayoutObject{ + queue: queue, + container: container.NewVBox(title), + items: map[int]QueueLayoutItem{}, + localizerService: localizerService, + layoutLocalizerListener: layoutLocalizerListener, + } + + queue.AddListener(queueLayoutObject) + + return queueLayoutObject +} + +func (o QueueLayoutObject) GetCanvasObject() fyne.CanvasObject { + return o.container +} + +func (o QueueLayoutObject) GetProgressbar(queueId int) *widget.ProgressBar { + if item, ok := o.items[queueId]; ok { + return item.ProgressBar + } + return widget.NewProgressBar() +} + +func (o QueueLayoutObject) Add(id int, queue *Queue) { + progressBar := widget.NewProgressBar() + statusMessage := canvas.NewText(o.getStatusTitle(queue.Status), theme.PrimaryColor()) + messageError := canvas.NewText("", theme.ErrorColor()) + + content := container.NewVBox( + container.NewHScroll(widget.NewLabel(queue.Setting.VideoFileInput.Name)), + progressBar, + container.NewHScroll(statusMessage), + container.NewHScroll(messageError), + canvas.NewLine(theme.FocusColor()), + container.NewPadded(), + ) + o.items[id] = QueueLayoutItem{ + CanvasObject: content, + ProgressBar: progressBar, + StatusMessage: statusMessage, + MessageError: messageError, + } + o.container.Add(content) +} + +func (o QueueLayoutObject) Remove(id int) { + if item, ok := o.items[id]; ok { + o.container.Remove(item.CanvasObject) + 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 + item.StatusMessage.Refresh() + if queue.Error != nil { + item.MessageError.Text = queue.Error.Error() + item.MessageError.Color = statusColor + item.MessageError.Refresh() + } + } +} + +func (o QueueLayoutObject) getStatusColor(status StatusContract) color.Color { + if status == StatusType(Error) { + return theme.ErrorColor() + } + + if status == StatusType(Completed) { + return color.RGBA{R: 49, G: 127, B: 114, A: 255} + } + + return theme.PrimaryColor() +} + +func (o QueueLayoutObject) getStatusTitle(status StatusContract) string { + return o.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: status.name()}) +} + +type Progress struct { + totalDuration float64 + progressbar *widget.ProgressBar + protocol string + localizerService LocalizerContract +} + +func NewProgress(totalDuration float64, progressbar *widget.ProgressBar, localizerService LocalizerContract) Progress { + return Progress{ + totalDuration: totalDuration, + progressbar: progressbar, + protocol: "pipe:", + localizerService: localizerService, + } +} + +func (p Progress) GetProtocole() string { + return p.protocol +} + +func (p Progress) Run(stdOut io.ReadCloser, stdErr io.ReadCloser) error { + isProcessCompleted := false + var errorText string + + p.progressbar.Value = 0 + p.progressbar.Max = p.totalDuration + p.progressbar.Refresh() + + progress := 0.0 + + go func() { + scannerErr := bufio.NewReader(stdErr) + for { + line, _, err := scannerErr.ReadLine() + if err != nil { + if err == io.EOF { + break + } + continue + } + data := strings.TrimSpace(string(line)) + errorText = data + } + }() + + scannerOut := bufio.NewReader(stdOut) + for { + line, _, err := scannerOut.ReadLine() + if err != nil { + if err == io.EOF { + break + } + continue + } + data := strings.TrimSpace(string(line)) + if strings.Contains(data, "progress=end") { + p.progressbar.Value = p.totalDuration + p.progressbar.Refresh() + isProcessCompleted = true + break + } + + re := regexp.MustCompile(`frame=(\d+)`) + a := re.FindAllStringSubmatch(data, -1) + + if len(a) > 0 && len(a[len(a)-1]) > 0 { + c, err := strconv.Atoi(a[len(a)-1][len(a[len(a)-1])-1]) + if err != nil { + continue + } + progress = float64(c) + } + if p.progressbar.Value != progress { + p.progressbar.Value = progress + p.progressbar.Refresh() + } + } + + if isProcessCompleted == false { + if len(errorText) == 0 { + errorText = p.localizerService.GetMessage(&i18n.LocalizeConfig{ + MessageID: "errorConverter", + }) + } + return errors.New(errorText) + } + + return nil +} + +type LayoutLocalizerItem struct { + messageID string + object *widget.Label +} + +type LayoutLocalizerListener struct { + itemCurrentId int + items map[int]*LayoutLocalizerItem +} + +type LayoutLocalizerListenerContract interface { + AddItem(messageID string, object *widget.Label) +} + +func NewLayoutLocalizerListener() *LayoutLocalizerListener { + return &LayoutLocalizerListener{ + itemCurrentId: 0, + items: map[int]*LayoutLocalizerItem{}, + } +} + +func (l LayoutLocalizerListener) AddItem(messageID string, object *widget.Label) { + l.itemCurrentId += 1 + l.items[l.itemCurrentId] = &LayoutLocalizerItem{messageID: messageID, object: object} +} + +func (l LayoutLocalizerListener) Change(localizerService LocalizerContract) { + for _, item := range l.items { + item.object.Text = localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: item.messageID}) + item.object.Refresh() + } +} diff --git a/localizer/service.go b/kernel/localizer.go similarity index 62% rename from localizer/service.go rename to kernel/localizer.go index 1b27594..e002125 100644 --- a/localizer/service.go +++ b/kernel/localizer.go @@ -1,4 +1,4 @@ -package localizer +package kernel import ( "github.com/BurntSushi/toml" @@ -10,12 +10,17 @@ import ( "sort" ) -type ServiceContract interface { +type LocalizerContract interface { GetLanguages() []Lang GetMessage(localizeConfig *i18n.LocalizeConfig) string SetCurrentLanguage(lang Lang) error SetCurrentLanguageByCode(code string) error GetCurrentLanguage() *CurrentLanguage + AddListener(listener LocalizerListenerContract) +} + +type LocalizerListenerContract interface { + Change(localizerService LocalizerContract) } type Lang struct { @@ -29,13 +34,14 @@ type CurrentLanguage struct { localizerDefault *i18n.Localizer } -type Service struct { - bundle *i18n.Bundle - languages []Lang - currentLanguage *CurrentLanguage +type Localizer struct { + bundle *i18n.Bundle + languages []Lang + currentLanguage *CurrentLanguage + localizerListener map[int]LocalizerListenerContract } -func NewService(directory string, languageDefault language.Tag) (*Service, error) { +func NewLocalizer(directory string, languageDefault language.Tag) (*Localizer, error) { bundle := i18n.NewBundle(languageDefault) bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal) @@ -46,7 +52,7 @@ func NewService(directory string, languageDefault language.Tag) (*Service, error localizerDefault := i18n.NewLocalizer(bundle, languageDefault.String()) - return &Service{ + return &Localizer{ bundle: bundle, languages: languages, currentLanguage: &CurrentLanguage{ @@ -57,6 +63,7 @@ func NewService(directory string, languageDefault language.Tag) (*Service, error localizer: localizerDefault, localizerDefault: localizerDefault, }, + localizerListener: map[int]LocalizerListenerContract{}, }, nil } @@ -81,14 +88,14 @@ func initLanguages(directory string, bundle *i18n.Bundle) ([]Lang, error) { return languages, nil } -func (s Service) GetLanguages() []Lang { - return s.languages +func (l Localizer) GetLanguages() []Lang { + return l.languages } -func (s Service) GetMessage(localizeConfig *i18n.LocalizeConfig) string { - message, err := s.GetCurrentLanguage().localizer.Localize(localizeConfig) +func (l Localizer) GetMessage(localizeConfig *i18n.LocalizeConfig) string { + message, err := l.GetCurrentLanguage().localizer.Localize(localizeConfig) if err != nil { - message, err = s.GetCurrentLanguage().localizerDefault.Localize(localizeConfig) + message, err = l.GetCurrentLanguage().localizerDefault.Localize(localizeConfig) if err != nil { return err.Error() } @@ -96,23 +103,34 @@ func (s Service) GetMessage(localizeConfig *i18n.LocalizeConfig) string { return message } -func (s Service) SetCurrentLanguage(lang Lang) error { - s.currentLanguage.Lang = lang - s.currentLanguage.localizer = i18n.NewLocalizer(s.bundle, lang.Code) +func (l Localizer) SetCurrentLanguage(lang Lang) error { + l.currentLanguage.Lang = lang + l.currentLanguage.localizer = i18n.NewLocalizer(l.bundle, lang.Code) + l.eventSetCurrentLanguage() return nil } -func (s Service) SetCurrentLanguageByCode(code string) error { +func (l Localizer) SetCurrentLanguageByCode(code string) error { lang, err := language.Parse(code) if err != nil { return err } title := cases.Title(lang).String(display.Self.Name(lang)) - return s.SetCurrentLanguage(Lang{Code: lang.String(), Title: title}) + return l.SetCurrentLanguage(Lang{Code: lang.String(), Title: title}) } -func (s Service) GetCurrentLanguage() *CurrentLanguage { - return s.currentLanguage +func (l Localizer) GetCurrentLanguage() *CurrentLanguage { + return l.currentLanguage +} + +func (l Localizer) AddListener(listener LocalizerListenerContract) { + l.localizerListener[len(l.localizerListener)] = listener +} + +func (l Localizer) eventSetCurrentLanguage() { + for _, listener := range l.localizerListener { + listener.Change(l) + } } type languagesSort []Lang diff --git a/kernel/queue.go b/kernel/queue.go new file mode 100644 index 0000000..d820fa6 --- /dev/null +++ b/kernel/queue.go @@ -0,0 +1,137 @@ +package kernel + +import ( + "errors" +) + +type Queue struct { + Setting *ConvertSetting + Status StatusContract + Error error +} + +type File struct { + Path string + Name string + Ext string +} + +type ConvertSetting struct { + VideoFileInput File + VideoFileOut File + OverwriteOutputFiles bool +} + +type StatusContract interface { + name() string + ordinal() int +} + +const ( + Waiting = iota + InProgress + Completed + Error +) + +type StatusType uint + +var statusTypeStrings = []string{ + "waiting", + "inProgress", + "completed", + "error", +} + +func (status StatusType) name() string { + return statusTypeStrings[status] +} + +func (status StatusType) ordinal() int { + return int(status) +} + +type QueueListenerContract interface { + Add(key int, queue *Queue) + Remove(key int) +} + +type QueueListContract interface { + AddListener(queueListener QueueListenerContract) + GetItems() map[int]*Queue + Add(setting *ConvertSetting) + Remove(key int) + GetItem(key int) (*Queue, error) + Next() (key int, queue *Queue) +} + +type QueueList struct { + currentKey *int + items map[int]*Queue + queueListener map[int]QueueListenerContract +} + +func NewQueueList() *QueueList { + currentKey := 0 + return &QueueList{ + currentKey: ¤tKey, + items: map[int]*Queue{}, + queueListener: map[int]QueueListenerContract{}, + } +} + +func (l QueueList) GetItems() map[int]*Queue { + return l.items +} + +func (l QueueList) Add(setting *ConvertSetting) { + queue := Queue{ + Setting: setting, + Status: StatusType(Waiting), + } + + *l.currentKey += 1 + l.items[*l.currentKey] = &queue + l.eventAdd(*l.currentKey, &queue) +} + +func (l QueueList) Remove(key int) { + if _, ok := l.items[key]; ok { + delete(l.items, key) + l.eventRemove(key) + } +} + +func (l QueueList) GetItem(key int) (*Queue, error) { + if item, ok := l.items[key]; ok { + return item, nil + } + + return nil, errors.New("key not found") +} + +func (l QueueList) AddListener(queueListener QueueListenerContract) { + l.queueListener[len(l.queueListener)] = queueListener +} + +func (l QueueList) eventAdd(key int, queue *Queue) { + for _, listener := range l.queueListener { + listener.Add(key, queue) + } +} + +func (l QueueList) eventRemove(key int) { + for _, listener := range l.queueListener { + listener.Remove(key) + } +} + +func (l QueueList) Next() (key int, queue *Queue) { + statusWaiting := StatusType(Waiting) + for key, item := range l.items { + if item.Status == statusWaiting { + return key, item + } + } + return -1, nil +} diff --git a/kernel/window.go b/kernel/window.go new file mode 100644 index 0000000..d60971b --- /dev/null +++ b/kernel/window.go @@ -0,0 +1,67 @@ +package kernel + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/dialog" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper" +) + +type WindowContract interface { + SetContent(content fyne.CanvasObject) + SetMainMenu(menu *fyne.MainMenu) + NewFileOpen(callback func(fyne.URIReadCloser, error), location fyne.ListableURI) *dialog.FileDialog + NewFolderOpen(callback func(fyne.ListableURI, error), location fyne.ListableURI) *dialog.FileDialog + ShowAndRun() + GetLayout() LayoutContract +} + +type Window struct { + windowFyne fyne.Window + layout LayoutContract +} + +func newWindow(w fyne.Window, layout LayoutContract) Window { + w.Resize(fyne.Size{Width: 799, Height: 599}) + w.CenterOnScreen() + + return Window{ + windowFyne: w, + layout: layout, + } +} + +func (w Window) SetContent(content fyne.CanvasObject) { + w.windowFyne.SetContent(w.layout.SetContent(content)) +} + +func (w Window) NewFileOpen(callback func(fyne.URIReadCloser, error), location fyne.ListableURI) *dialog.FileDialog { + fileDialog := dialog.NewFileOpen(callback, w.windowFyne) + helper.FileDialogResize(fileDialog, w.windowFyne) + fileDialog.Show() + if location != nil { + fileDialog.SetLocation(location) + } + return fileDialog +} + +func (w Window) NewFolderOpen(callback func(fyne.ListableURI, error), location fyne.ListableURI) *dialog.FileDialog { + fileDialog := dialog.NewFolderOpen(callback, w.windowFyne) + helper.FileDialogResize(fileDialog, w.windowFyne) + fileDialog.Show() + if location != nil { + fileDialog.SetLocation(location) + } + return fileDialog +} + +func (w Window) SetMainMenu(menu *fyne.MainMenu) { + w.windowFyne.SetMainMenu(menu) +} + +func (w Window) ShowAndRun() { + w.windowFyne.ShowAndRun() +} + +func (w Window) GetLayout() LayoutContract { + return w.layout +} diff --git a/languages/active.en.toml b/languages/active.en.toml index 2ffafeb..499b140 100644 --- a/languages/active.en.toml +++ b/languages/active.en.toml @@ -38,6 +38,10 @@ other = "Allow file to be overwritten" hash = "sha1-f60bb5f761024d973834b5e9d25ceebce2c85f94" other = "choose" +[completed] +hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe" +other = "Completed" + [converterVideoFilesSubmitTitle] hash = "sha1-7ac460f3c24c9952082f2db6e4d62f752598709c" other = "Convert" @@ -110,6 +114,10 @@ other = "File for conversion:" hash = "sha1-6a45cef900c668effcb2ab10da05855c1fd10f6f" other = "Help" +[inProgress] +hash = "sha1-eff79c40e2100ae5fadf3a7d99336025edcca8b5" +other = "In Progress" + [languageSelectionFormHead] hash = "sha1-0ff5fa82cf684112660128cba1711297acf11003" other = "Switch language" @@ -142,6 +150,10 @@ other = "Project website" hash = "sha1-fa2e4994a301bb24bc2a8fa166e5486ea95a7475" other = "**Program version:** {{.Version}}" +[queue] +hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8" +other = "Queue" + [save] hash = "sha1-4864057d626a868fa60f999bed3191d61d045ddc" other = "Save" @@ -165,3 +177,7 @@ other = "You can download it from here" [unzipRun] hash = "sha1-c554dad13026668a1f6adf3171837c5d51bbac36" other = "Unpacked..." + +[waiting] +hash = "sha1-307429dd84150877080c4bbff2b340d1e7dadff2" +other = "Waiting" diff --git a/languages/active.kk.toml b/languages/active.kk.toml index 990a3ad..d443d8a 100644 --- a/languages/active.kk.toml +++ b/languages/active.kk.toml @@ -38,6 +38,10 @@ other = "Файлды қайта жазуға рұқсат беріңіз" hash = "sha1-f60bb5f761024d973834b5e9d25ceebce2c85f94" other = "таңдау" +[completed] +hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe" +other = "Дайын" + [converterVideoFilesSubmitTitle] hash = "sha1-7ac460f3c24c9952082f2db6e4d62f752598709c" other = "Файлды түрлендіру" @@ -110,6 +114,10 @@ other = "Түрлендіруге арналған файл:" hash = "sha1-6a45cef900c668effcb2ab10da05855c1fd10f6f" other = "Анықтама" +[inProgress] +hash = "sha1-eff79c40e2100ae5fadf3a7d99336025edcca8b5" +other = "Орындалуда" + [languageSelectionFormHead] hash = "sha1-0ff5fa82cf684112660128cba1711297acf11003" other = "Тілді ауыстыру" @@ -142,6 +150,10 @@ other = "Жобаның веб-сайты" hash = "sha1-fa2e4994a301bb24bc2a8fa166e5486ea95a7475" other = "**Бағдарлама нұсқасы:** {{.Version}}" +[queue] +hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8" +other = "Кезек" + [save] hash = "sha1-4864057d626a868fa60f999bed3191d61d045ddc" other = "Сақтау" @@ -165,3 +177,7 @@ other = "Сіз оны осы жерден жүктей аласыз" [unzipRun] hash = "sha1-c554dad13026668a1f6adf3171837c5d51bbac36" other = "Орамнан шығарылуда..." + +[waiting] +hash = "sha1-307429dd84150877080c4bbff2b340d1e7dadff2" +other = "Күту" diff --git a/languages/active.ru.toml b/languages/active.ru.toml index 7d94ea8..b163e1b 100644 --- a/languages/active.ru.toml +++ b/languages/active.ru.toml @@ -8,6 +8,7 @@ changeFFPath = "FFmpeg и FFprobe" changeLanguage = "Поменять язык" checkboxOverwriteOutputFilesTitle = "Разрешить перезаписать файл" choose = "выбрать" +completed = "Готово" converterVideoFilesSubmitTitle = "Конвертировать" converterVideoFilesTitle = "Конвертор видео файлов в mp4" download = "Скачать" @@ -26,6 +27,7 @@ ffmpegLGPL = "Это программное обеспечение исполь ffmpegTrademark = "**FFmpeg** — торговая марка **[Fabrice Bellard](http://bellard.org/)** , создателя проекта **[FFmpeg](https://ffmpeg.org/about.html)**." fileVideoForConversionTitle = "Файл для ковертации:" help = "Справка" +inProgress = "Выполняется" languageSelectionFormHead = "Переключить язык" languageSelectionHead = "Выберите язык" licenseLink = "Сведения о лицензии" @@ -34,9 +36,11 @@ pathToFfmpeg = "Путь к FFmpeg:" pathToFfprobe = "Путь к FFprobe:" programmLink = "Сайт проекта" programmVersion = "**Версия программы:** {{.Version}}" +queue = "Очередь" save = "Сохранить" selectFFPathTitle = "Укажите путь к FFmpeg и к FFprobe" settings = "Настройки" testFF = "Проверка FFmpeg на работоспособность..." titleDownloadLink = "Скачать можно от сюда" unzipRun = "Распаковывается..." +waiting = "В очереди" diff --git a/languages/translate.en.toml b/languages/translate.en.toml index 81cb622..acb16ac 100644 --- a/languages/translate.en.toml +++ b/languages/translate.en.toml @@ -1,3 +1,15 @@ -[testFF] -hash = "sha1-f5b8ed88e9609963035d2235be0a79bbec619976" -other = "Checking FFmpeg for serviceability..." +[completed] +hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe" +other = "Completed" + +[inProgress] +hash = "sha1-eff79c40e2100ae5fadf3a7d99336025edcca8b5" +other = "In Progress" + +[queue] +hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8" +other = "Queue" + +[waiting] +hash = "sha1-307429dd84150877080c4bbff2b340d1e7dadff2" +other = "Waiting" diff --git a/languages/translate.kk.toml b/languages/translate.kk.toml index 8e64112..93b8581 100644 --- a/languages/translate.kk.toml +++ b/languages/translate.kk.toml @@ -1,3 +1,15 @@ -[testFF] -hash = "sha1-f5b8ed88e9609963035d2235be0a79bbec619976" -other = "FFmpeg функционалдығы тексерілуде..." +[completed] +hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe" +other = "Дайын" + +[inProgress] +hash = "sha1-eff79c40e2100ae5fadf3a7d99336025edcca8b5" +other = "Орындалуда" + +[queue] +hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8" +other = "Кезек" + +[waiting] +hash = "sha1-307429dd84150877080c4bbff2b340d1e7dadff2" +other = "Күту" diff --git a/localizer/view.go b/localizer/view.go index 351d9c9..c0e5af6 100644 --- a/localizer/view.go +++ b/localizer/view.go @@ -3,27 +3,26 @@ package localizer import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/widget" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "github.com/nicksnyder/go-i18n/v2/i18n" ) type ViewContract interface { - LanguageSelection(funcSelected func(lang Lang)) + LanguageSelection(funcSelected func(lang kernel.Lang)) } type View struct { - w fyne.Window - localizerService ServiceContract + app kernel.AppContract } -func NewView(w fyne.Window, localizerService ServiceContract) *View { +func NewView(app kernel.AppContract) *View { return &View{ - w: w, - localizerService: localizerService, + app: app, } } -func (v View) LanguageSelection(funcSelected func(lang Lang)) { - languages := v.localizerService.GetLanguages() +func (v View) LanguageSelection(funcSelected func(lang kernel.Lang)) { + languages := v.app.GetLocalizerService().GetLanguages() listView := widget.NewList( func() int { return len(languages) @@ -36,18 +35,17 @@ func (v View) LanguageSelection(funcSelected func(lang Lang)) { block.SetText(languages[i].Title) }) listView.OnSelected = func(id widget.ListItemID) { - _ = v.localizerService.SetCurrentLanguage(languages[id]) + _ = v.app.GetLocalizerService().SetCurrentLanguage(languages[id]) funcSelected(languages[id]) } - messageHead := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + messageHead := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "languageSelectionHead", }) - - v.w.SetContent(widget.NewCard(messageHead, "", listView)) + v.app.GetWindow().SetContent(widget.NewCard(messageHead, "", listView)) } -func LanguageSelectionForm(localizerService ServiceContract, funcSelected func(lang Lang)) fyne.CanvasObject { +func LanguageSelectionForm(localizerService kernel.LocalizerContract, funcSelected func(lang kernel.Lang)) fyne.CanvasObject { languages := localizerService.GetLanguages() currentLanguage := localizerService.GetCurrentLanguage() listView := widget.NewList( diff --git a/main.go b/main.go index 8b1dbc1..88a0e94 100644 --- a/main.go +++ b/main.go @@ -3,12 +3,10 @@ package main import ( "errors" "fyne.io/fyne/v2" - "fyne.io/fyne/v2/app" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/widget" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/convertor" error2 "git.kor-elf.net/kor-elf/gui-for-ffmpeg/error" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/handler" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/menu" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/migration" @@ -20,36 +18,50 @@ import ( "os" ) -const appVersion string = "0.3.1" +var app kernel.AppContract +var ffPathUtilities *kernel.FFPathUtilities + +func init() { + iconResource, _ := fyne.LoadResourceFromPath("icon.png") + appMetadata := &fyne.AppMetadata{ + ID: "net.kor-elf.projects.gui-for-ffmpeg", + Name: "GUI for FFmpeg", + Version: "0.4.0", + Icon: iconResource, + } + + localizerService, err := kernel.NewLocalizer("languages", language.Russian) + if err != nil { + kernel.PanicErrorLang(err, appMetadata) + } + + ffPathUtilities = &kernel.FFPathUtilities{FFmpeg: "", FFprobe: ""} + convertorService := kernel.NewService(ffPathUtilities) + layoutLocalizerListener := kernel.NewLayoutLocalizerListener() + localizerService.AddListener(layoutLocalizerListener) + + queue := kernel.NewQueueList() + app = kernel.NewApp( + appMetadata, + localizerService, + queue, + kernel.NewQueueLayoutObject(queue, localizerService, layoutLocalizerListener), + convertorService, + ) +} func main() { - a := app.New() - iconResource, err := fyne.LoadResourceFromPath("icon.png") - if err == nil { - a.SetIcon(iconResource) - } - w := a.NewWindow("GUI for FFmpeg") - w.Resize(fyne.Size{Width: 800, Height: 600}) - w.CenterOnScreen() - - localizerService, err := localizer.NewService("languages", language.Russian) - if err != nil { - panicErrorLang(w, err) - w.ShowAndRun() - return - } - - errorView := error2.NewView(w, localizerService) + errorView := error2.NewView(app) if canCreateFile("data/database") != true { errorView.PanicErrorWriteDirectoryData() - w.ShowAndRun() + app.GetWindow().ShowAndRun() return } db, err := gorm.Open(sqlite.Open("data/database"), &gorm.Config{}) if err != nil { errorView.PanicError(err) - w.ShowAndRun() + app.GetWindow().ShowAndRun() return } @@ -58,7 +70,7 @@ func main() { err = migration.Run(db) if err != nil { errorView.PanicError(err) - w.ShowAndRun() + app.GetWindow().ShowAndRun() return } @@ -67,34 +79,37 @@ func main() { pathFFmpeg, err := convertorRepository.GetPathFfmpeg() if err != nil && errors.Is(err, gorm.ErrRecordNotFound) == false { errorView.PanicError(err) - w.ShowAndRun() + app.GetWindow().ShowAndRun() return } + ffPathUtilities.FFmpeg = pathFFmpeg + pathFFprobe, err := convertorRepository.GetPathFfprobe() if err != nil && errors.Is(err, gorm.ErrRecordNotFound) == false { errorView.PanicError(err) - w.ShowAndRun() + app.GetWindow().ShowAndRun() return } + ffPathUtilities.FFprobe = pathFFprobe - ffPathUtilities := convertor.FFPathUtilities{FFmpeg: pathFFmpeg, FFprobe: pathFFprobe} + app.RunConvertor() + defer app.AfterClosing() - localizerView := localizer.NewView(w, localizerService) - convertorView := convertor.NewView(w, localizerService) - convertorService := convertor.NewService(ffPathUtilities) - defer appCloseWithConvert(convertorService) - convertorHandler := handler.NewConvertorHandler(convertorService, convertorView, convertorRepository, localizerService) + localizerView := localizer.NewView(app) + convertorView := convertor.NewView(app) + convertorHandler := handler.NewConvertorHandler(app, convertorView, convertorRepository) localizerRepository := localizer.NewRepository(settingRepository) - menuView := menu.NewView(w, a, appVersion, localizerService) - mainMenu := handler.NewMenuHandler(convertorHandler, menuView, localizerService, localizerView, localizerRepository) + menuView := menu.NewView(app) + localizerListener := handler.NewLocalizerListener() + app.GetLocalizerService().AddListener(localizerListener) + mainMenu := handler.NewMenuHandler(app, convertorHandler, menuView, localizerView, localizerRepository, localizerListener) - mainHandler := handler.NewMainHandler(convertorHandler, mainMenu, localizerRepository, localizerService) + mainHandler := handler.NewMainHandler(app, convertorHandler, mainMenu, localizerRepository) mainHandler.Start() - w.SetMainMenu(mainMenu.GetMainMenu()) - - w.ShowAndRun() + app.GetWindow().SetMainMenu(mainMenu.GetMainMenu()) + app.GetWindow().ShowAndRun() } func appCloseWithDb(db *gorm.DB) { @@ -104,12 +119,6 @@ func appCloseWithDb(db *gorm.DB) { } } -func appCloseWithConvert(convertorService convertor.ServiceContract) { - for _, cmd := range convertorService.GetRunningProcesses() { - _ = cmd.Process.Kill() - } -} - func canCreateFile(path string) bool { file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666) if err != nil { @@ -118,10 +127,3 @@ func canCreateFile(path string) bool { _ = file.Close() return true } - -func panicErrorLang(w fyne.Window, err error) { - w.SetContent(container.NewVBox( - widget.NewLabel("Произошла ошибка!"), - widget.NewLabel("произошла ошибка при получении языковых переводах. \n\r"+err.Error()), - )) -} diff --git a/menu/view.go b/menu/view.go index 0dc0896..f468498 100644 --- a/menu/view.go +++ b/menu/view.go @@ -5,7 +5,7 @@ import ( "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "github.com/nicksnyder/go-i18n/v2/i18n" "golang.org/x/image/colornames" "net/url" @@ -16,23 +16,17 @@ type ViewContract interface { } type View struct { - w fyne.Window - app fyne.App - appVersion string - localizerService localizer.ServiceContract + app kernel.AppContract } -func NewView(w fyne.Window, app fyne.App, appVersion string, localizerService localizer.ServiceContract) *View { +func NewView(app kernel.AppContract) *View { return &View{ - w: w, - app: app, - appVersion: appVersion, - localizerService: localizerService, + app: app, } } func (v View) About(ffmpegVersion string, ffprobeVersion string) { - view := v.app.NewWindow(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + view := v.app.GetAppFyne().NewWindow(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "about", })) view.Resize(fyne.Size{Width: 793, Height: 550}) @@ -42,7 +36,7 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { programmName.TextStyle = fyne.TextStyle{Bold: true} programmName.TextSize = 20 - programmLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + programmLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "programmLink", }), &url.URL{ Scheme: "https", @@ -50,7 +44,7 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { Path: "kor-elf/gui-for-ffmpeg/releases", }) - licenseLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + licenseLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "licenseLink", }), &url.URL{ Scheme: "https", @@ -58,7 +52,7 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { Path: "kor-elf/gui-for-ffmpeg/src/branch/main/LICENSE", }) - licenseLinkOther := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + licenseLinkOther := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "licenseLinkOther", }), &url.URL{ Scheme: "https", @@ -66,16 +60,16 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { Path: "kor-elf/gui-for-ffmpeg/src/branch/main/LICENSE-3RD-PARTY.txt", }) - programmVersion := widget.NewRichTextFromMarkdown(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + programmVersion := widget.NewRichTextFromMarkdown(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "programmVersion", TemplateData: map[string]string{ - "Version": v.appVersion, + "Version": v.app.GetAppFyne().Metadata().Version, }, })) aboutText := widget.NewRichText( &widget.TextSegment{ - Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{ + Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "aboutText", }), }, @@ -84,10 +78,10 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { image.SetMinSize(fyne.Size{Width: 100, Height: 100}) image.FillMode = canvas.ImageFillContain - ffmpegTrademark := widget.NewRichTextFromMarkdown(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + ffmpegTrademark := widget.NewRichTextFromMarkdown(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "ffmpegTrademark", })) - ffmpegLGPL := widget.NewRichTextFromMarkdown(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + ffmpegLGPL := widget.NewRichTextFromMarkdown(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "ffmpegLGPL", })) @@ -105,7 +99,7 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { )), v.getAboutFfmpeg(ffmpegVersion), v.getAboutFfprobe(ffprobeVersion), - widget.NewCard(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + widget.NewCard(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "AlsoUsedProgram", }), "", v.getOther()), )), @@ -123,7 +117,7 @@ func (v View) getAboutFfmpeg(version string) *fyne.Container { programmName.TextStyle = fyne.TextStyle{Bold: true} programmName.TextSize = 20 - programmLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + programmLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "programmLink", }), &url.URL{ Scheme: "https", @@ -131,7 +125,7 @@ func (v View) getAboutFfmpeg(version string) *fyne.Container { Path: "", }) - licenseLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + licenseLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "licenseLink", }), &url.URL{ Scheme: "https", @@ -153,7 +147,7 @@ func (v View) getAboutFfprobe(version string) *fyne.Container { programmName.TextStyle = fyne.TextStyle{Bold: true} programmName.TextSize = 20 - programmLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + programmLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "programmLink", }), &url.URL{ Scheme: "https", @@ -161,7 +155,7 @@ func (v View) getAboutFfprobe(version string) *fyne.Container { Path: "ffprobe.html", }) - licenseLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + licenseLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "licenseLink", }), &url.URL{ Scheme: "https",