forked from Leak_Technologies/VideoTools
Compare commits
4 Commits
f13f13d05b
...
b7b5788938
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7b5788938 | ||
|
|
ffca39811a | ||
|
|
e749a32926 | ||
|
|
66c79cee91 |
175
main.go
175
main.go
|
|
@ -655,7 +655,6 @@ func (s *appState) showPlayerView() {
|
|||
|
||||
centerStack := container.NewVBox(
|
||||
container.NewCenter(icon),
|
||||
layout.NewSpacer(),
|
||||
container.NewCenter(loadBtn),
|
||||
container.NewCenter(hint),
|
||||
)
|
||||
|
|
@ -820,121 +819,9 @@ func (s *appState) showPlayerView() {
|
|||
s.setContent(mainPanel)
|
||||
}
|
||||
|
||||
func (s *appState) showQueue() {
|
||||
s.stopPreview()
|
||||
s.stopPlayer()
|
||||
s.stopCompareSessions()
|
||||
s.lastModule = s.active
|
||||
s.active = "queue"
|
||||
s.refreshQueueView()
|
||||
}
|
||||
|
||||
// refreshQueueView rebuilds the queue UI while preserving scroll position and inline active conversion.
|
||||
func (s *appState) refreshQueueView() {
|
||||
// Preserve current scroll offset if we already have a view
|
||||
if s.queueScroll != nil {
|
||||
s.queueOffset = s.queueScroll.Offset
|
||||
}
|
||||
|
||||
jobs := s.jobQueue.List()
|
||||
// If a direct conversion is running but not represented in the queue, surface it as a pseudo job.
|
||||
if s.convertBusy {
|
||||
in := filepath.Base(s.convertActiveIn)
|
||||
if in == "" && s.source != nil {
|
||||
in = filepath.Base(s.source.Path)
|
||||
}
|
||||
out := filepath.Base(s.convertActiveOut)
|
||||
jobs = append([]*queue.Job{{
|
||||
ID: "active-convert",
|
||||
Type: queue.JobTypeConvert,
|
||||
Status: queue.JobStatusRunning,
|
||||
Title: fmt.Sprintf("Direct convert: %s", in),
|
||||
Description: fmt.Sprintf("Output: %s", out),
|
||||
Progress: s.convertProgress,
|
||||
}}, jobs...)
|
||||
}
|
||||
|
||||
view, scroll := ui.BuildQueueView(
|
||||
jobs,
|
||||
func() { // onBack
|
||||
if s.lastModule != "" && s.lastModule != "queue" && s.lastModule != "menu" {
|
||||
s.showModule(s.lastModule)
|
||||
} else {
|
||||
s.showMainMenu()
|
||||
}
|
||||
},
|
||||
func(id string) { // onPause
|
||||
if err := s.jobQueue.Pause(id); err != nil {
|
||||
logging.Debug(logging.CatSystem, "failed to pause job: %v", err)
|
||||
}
|
||||
s.refreshQueueView() // Refresh
|
||||
},
|
||||
func(id string) { // onResume
|
||||
if err := s.jobQueue.Resume(id); err != nil {
|
||||
logging.Debug(logging.CatSystem, "failed to resume job: %v", err)
|
||||
}
|
||||
s.refreshQueueView() // Refresh
|
||||
},
|
||||
func(id string) { // onCancel
|
||||
if err := s.jobQueue.Cancel(id); err != nil {
|
||||
logging.Debug(logging.CatSystem, "failed to cancel job: %v", err)
|
||||
}
|
||||
s.refreshQueueView() // Refresh
|
||||
},
|
||||
func(id string) { // onRemove
|
||||
if err := s.jobQueue.Remove(id); err != nil {
|
||||
logging.Debug(logging.CatSystem, "failed to remove job: %v", err)
|
||||
}
|
||||
s.refreshQueueView() // Refresh
|
||||
},
|
||||
func(id string) { // onMoveUp
|
||||
if err := s.jobQueue.MoveUp(id); err != nil {
|
||||
logging.Debug(logging.CatSystem, "failed to move job up: %v", err)
|
||||
}
|
||||
s.refreshQueueView() // Refresh
|
||||
},
|
||||
func(id string) { // onMoveDown
|
||||
if err := s.jobQueue.MoveDown(id); err != nil {
|
||||
logging.Debug(logging.CatSystem, "failed to move job down: %v", err)
|
||||
}
|
||||
s.refreshQueueView() // Refresh
|
||||
},
|
||||
func() { // onPauseAll
|
||||
s.jobQueue.PauseAll()
|
||||
s.refreshQueueView()
|
||||
},
|
||||
func() { // onResumeAll
|
||||
s.jobQueue.ResumeAll()
|
||||
s.refreshQueueView()
|
||||
},
|
||||
func() { // onStart
|
||||
s.jobQueue.ResumeAll()
|
||||
s.refreshQueueView()
|
||||
},
|
||||
func() { // onClear
|
||||
s.jobQueue.Clear()
|
||||
s.clearVideo()
|
||||
s.refreshQueueView() // Refresh
|
||||
},
|
||||
func() { // onClearAll
|
||||
s.jobQueue.ClearAll()
|
||||
s.clearVideo()
|
||||
s.refreshQueueView() // Refresh
|
||||
},
|
||||
utils.MustHex("#4CE870"), // titleColor
|
||||
gridColor, // bgColor
|
||||
textColor, // textColor
|
||||
)
|
||||
|
||||
// Restore scroll offset
|
||||
s.queueScroll = scroll
|
||||
if s.queueScroll != nil {
|
||||
s.queueScroll.Offset = s.queueOffset
|
||||
s.queueScroll.Refresh()
|
||||
}
|
||||
|
||||
s.setContent(container.NewPadded(view))
|
||||
}
|
||||
// Legacy queue view left in place but not used in player-only mode.
|
||||
func (s *appState) showQueue() {}
|
||||
func (s *appState) refreshQueueView() {}
|
||||
|
||||
// addConvertToQueue adds a conversion job to the queue
|
||||
func (s *appState) addConvertToQueue() error {
|
||||
|
|
@ -1209,33 +1096,11 @@ func (s *appState) batchAddToQueue(paths []string) {
|
|||
}
|
||||
}
|
||||
s.loadVideos(combined)
|
||||
s.showModule("convert")
|
||||
s.showPlayerView()
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
|
||||
func (s *appState) showConvertView(file *videoSource) {
|
||||
s.stopPreview()
|
||||
s.lastModule = s.active
|
||||
s.active = "convert"
|
||||
if file != nil {
|
||||
s.source = file
|
||||
}
|
||||
if s.source == nil {
|
||||
s.convert.OutputBase = "converted"
|
||||
s.convert.CoverArtPath = ""
|
||||
s.convert.AspectHandling = "Auto"
|
||||
}
|
||||
s.setContent(buildConvertView(s, s.source))
|
||||
}
|
||||
|
||||
func (s *appState) showCompareView() {
|
||||
s.stopPreview()
|
||||
s.lastModule = s.active
|
||||
s.active = "compare"
|
||||
s.setContent(buildCompareView(s))
|
||||
}
|
||||
|
||||
// jobExecutor executes a job from the queue
|
||||
func (s *appState) jobExecutor(ctx context.Context, job *queue.Job, progressCallback func(float64)) error {
|
||||
logging.Debug(logging.CatSystem, "executing job %s: %s", job.ID, job.Title)
|
||||
|
|
@ -3939,10 +3804,11 @@ func (s *appState) handleDropPlayer(items []fyne.URI) {
|
|||
|
||||
var videoPaths []string
|
||||
for _, uri := range items {
|
||||
if uri.Scheme() != "file" {
|
||||
path := uriPath(uri)
|
||||
if path == "" {
|
||||
logging.Debug(logging.CatModule, "drop received empty path; uri=%v", uri)
|
||||
continue
|
||||
}
|
||||
path := uri.Path()
|
||||
logging.Debug(logging.CatModule, "drop received path=%s", path)
|
||||
|
||||
if info, err := os.Stat(path); err == nil && info.IsDir() {
|
||||
|
|
@ -3955,6 +3821,9 @@ func (s *appState) handleDropPlayer(items []fyne.URI) {
|
|||
|
||||
if len(videoPaths) == 0 {
|
||||
logging.Debug(logging.CatUI, "no valid video files in dropped items")
|
||||
fyne.Do(func() {
|
||||
dialog.ShowInformation("No videos found", "Drop a video file or a folder containing videos.", s.window)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -3965,6 +3834,30 @@ func (s *appState) handleDropPlayer(items []fyne.URI) {
|
|||
}
|
||||
}
|
||||
|
||||
// uriPath extracts a usable local path from a fyne URI.
|
||||
func uriPath(u fyne.URI) string {
|
||||
if u == nil {
|
||||
return ""
|
||||
}
|
||||
// Prefer Path() when present.
|
||||
if p := u.Path(); p != "" {
|
||||
return p
|
||||
}
|
||||
raw := u.String()
|
||||
if raw == "" {
|
||||
return ""
|
||||
}
|
||||
if parsed, err := url.Parse(raw); err == nil {
|
||||
if parsed.Scheme == "file" {
|
||||
return parsed.Path
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(raw, "file://") {
|
||||
raw = strings.TrimPrefix(raw, "file://")
|
||||
}
|
||||
return filepath.FromSlash(raw)
|
||||
}
|
||||
|
||||
// detectModuleTileAtPosition calculates which module tile is at the given position
|
||||
// based on the main menu grid layout (3 columns)
|
||||
func (s *appState) detectModuleTileAtPosition(pos fyne.Position) string {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user