Skip to content

Commit

Permalink
Merge pull request #77 from Sammy-T/drag
Browse files Browse the repository at this point in the history
Open file on drag and drop
  • Loading branch information
Sammy-T authored Jul 12, 2024
2 parents b7cbd14 + 142a43b commit af8bc3e
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 29 deletions.
82 changes: 58 additions & 24 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"fmt"
"log"
"os"
"path/filepath"
Expand All @@ -14,7 +15,7 @@ import (
type App struct {
ctx context.Context
defaultFilename string
filePath string
filepath string
fileFilters []runtime.FileFilter
status docStatus
}
Expand All @@ -36,13 +37,15 @@ func (a *App) startup(ctx context.Context) {

runtime.EventsOn(a.ctx, "onLanguagesLoaded", a.onLanguagesLoaded)
runtime.EventsOn(a.ctx, "onSaveStatusUpdated", a.onSaveStatusUpdated)

runtime.OnFileDrop(a.ctx, a.onFileDropped)
}

// beforeClose is called when the app is about to quit. It returns a boolean
// to determine whether the app should be prevented from closing.
func (a *App) beforeClose(ctx context.Context) (prevent bool) {
// Close as normal if the document is already saved or empty
if a.status.saved || (a.filePath == "" && a.status.content == "") {
if a.status.saved || (a.filepath == "" && a.status.content == "") {
return false
}

Expand Down Expand Up @@ -113,14 +116,35 @@ func (a *App) onSaveStatusUpdated(optionalData ...interface{}) {
a.status = docStatus{saved, content}
}

func (a *App) onFileDropped(x, y int, paths []string) {
fmt.Printf("Dropped at %v,%v paths: %v\n", x, y, paths)

// Check if the current file has unsaved content
if !a.status.saved && (a.filepath != "" || a.status.content != "") {
// Display a dialog to alert the user the current document is unsaved
dialog, err := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Type: runtime.QuestionDialog,
Title: "Unsaved Changes",
Message: "Open new file without saving?",
DefaultButton: "No",
})

if err != nil || dialog != "Yes" {
return
}
}

a.readFile(paths[0])
}

// UpdateDefaultName sets the default file name to the provided string
func (a *App) UpdateDefaultName(filename string) {
a.defaultFilename = filename
}

// NewFile clears the file path, sets the window title, and emits an 'onNewFile' event
func (a *App) NewFile() {
a.filePath = ""
a.filepath = ""
a.defaultFilename = "*.txt"
a.status = docStatus{}

Expand All @@ -134,34 +158,44 @@ func (a *App) OpenFile() {
Filters: a.fileFilters,
}

response := Response{}

// Open the dialog
filePath, err := runtime.OpenFileDialog(a.ctx, options)
filepathStr, err := runtime.OpenFileDialog(a.ctx, options)
if err != nil {
log.Printf("Error retrieving file path. %v", err)
return
} else if filePath == "" {
} else if filepathStr == "" {
return // Return early if the user cancelled
}
log.Printf("filepath: %v\n", filepathStr)

a.readFile(filepathStr)
}

a.filePath = filePath
a.defaultFilename = "*" + filepath.Ext(filePath)
runtime.WindowSetTitle(a.ctx, "gotepad - "+filepath.Base(filePath))
// readFile is a helper to read the passed in file,
// update the app's file fields
// and emit the "onFileRead" event.
func (a *App) readFile(filepathStr string) {
// Update the app's file fields
a.filepath = filepathStr
a.defaultFilename = "*" + filepath.Ext(filepathStr)

// Read the file at the selected file path
data, err := os.ReadFile(filePath)
runtime.WindowSetTitle(a.ctx, "gotepad - "+filepath.Base(filepathStr))

// Read the file
data, err := os.ReadFile(filepathStr)
if err != nil {
log.Printf("Error reading file. %v", err)
log.Printf("Error reading file. %v\n", err)
return
}

// Update the status
a.status = docStatus{true, string(data)}

response.Status = "success"
response.Message = filePath
response.Data = string(data)
response := Response{
Status: "success",
Message: filepathStr,
Data: string(data),
}

// Emit an event with the read file text attached
runtime.EventsEmit(a.ctx, "onFileRead", response)
Expand All @@ -175,33 +209,33 @@ func (a *App) SaveAs(contents string) {
}

// Open the dialog
filePath, err := runtime.SaveFileDialog(a.ctx, options)
filepathStr, err := runtime.SaveFileDialog(a.ctx, options)
if err != nil {
log.Printf("Error retrieving file path. %v", err)
log.Printf("Error retrieving file path. %v\n", err)
return
} else if filePath == "" {
} else if filepathStr == "" {
return // Return early if the user cancelled
}

a.filePath = filePath
a.filepath = filepathStr
a.Save(contents)
}

// Save writes the contents to the file at the app's filepath
func (a *App) Save(contents string) {
// Check for a valid filepath
if a.filePath == "" {
if a.filepath == "" {
a.SaveAs(contents)
return
}

log.Printf("Save path: %v", a.filePath)
runtime.WindowSetTitle(a.ctx, "gotepad - "+filepath.Base(a.filePath))
log.Printf("Save path: %v", a.filepath)
runtime.WindowSetTitle(a.ctx, "gotepad - "+filepath.Base(a.filepath))

var response Response

// Save the file at the selected file path
err := os.WriteFile(a.filePath, []byte(contents), 0666)
err := os.WriteFile(a.filepath, []byte(contents), 0666)
if err != nil {
response.Status = "error"
response.Message = err.Error()
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/main.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './ext/menu';
import './ext/terminal';
import {editor, supportedLangs, setEditorLang} from './ext/editor';
import {BrowserOpenURL, Environment, EventsEmit, EventsOn} from '../wailsjs/runtime/runtime';
import {BrowserOpenURL, Environment, EventsEmit, EventsOn, OnFileDrop} from '../wailsjs/runtime/runtime';
import {NewFile, OpenFile, SaveAs, Save, UpdateDefaultName} from '../wailsjs/go/main/App';
import {ReadConfig, OpenConfigFile} from '../wailsjs/go/main/AppConfig';

Expand Down Expand Up @@ -380,6 +380,9 @@ EventsOn('onFileSaved', onFileSaved);
EventsOn('onRequestSaveAs', () => SaveAs(editor.getValue()));
EventsOn('onRequestSave', () => Save(editor.getValue()));

//// TODO: Second arg must be `true` to work until the fix already added to master is released.
OnFileDrop((x, y, paths) => console.log(`wails onfiledrop:`, {x, y}, paths), true);

readPrefs();
initLanguages();

Expand All @@ -397,4 +400,4 @@ editor.getContribution('editor.linkDetector').openerService.open = (url) => Brow
menuItems.forEach(initMenuItem);
document.addEventListener('keydown', onKey);

modals.forEach(initModal);
modals.forEach(initModal);
4 changes: 4 additions & 0 deletions frontend/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ html {
--menu-list-border-col: var(--menu-list-border-dark);
}

main {
--wails-drop-target: drop;
}

@media (prefers-color-scheme: light) {
html:not([data-theme=dark]) {
background-color: var(--theme-bg-light);
Expand Down
4 changes: 4 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func main() {
Height: 650,
Assets: assets,
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
DragAndDrop: &options.DragAndDrop{
EnableFileDrop: true,
DisableWebViewDrop: true,
},
OnStartup: func(ctx context.Context) {
app.startup(ctx)
termAction.startup(ctx)
Expand Down
6 changes: 3 additions & 3 deletions termaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (ta *TerminalAction) startup(ctx context.Context) {
runtime.EventsOn(ta.ctx, "onConfigLoaded", ta.onConfigLoaded)
}

func (ta *TerminalAction) onDomReady(ctx context.Context) {
func (ta *TerminalAction) onDomReady(_ context.Context) {
response := Response{"success", "terminals mapped", ta.terminals}
runtime.EventsEmit(ta.ctx, "onTerminalsMapped", response)
}
Expand Down Expand Up @@ -75,8 +75,8 @@ func (ta *TerminalAction) OpenTerminal(name string) {
cmd := exec.Command(terminal.CmdRoot, terminal.OpenCmd...)

// Set the command's working directory
if len(app.filePath) > 0 {
cmd.Dir = filepath.Dir(app.filePath)
if len(app.filepath) > 0 {
cmd.Dir = filepath.Dir(app.filepath)
}

// Run the command
Expand Down

0 comments on commit af8bc3e

Please sign in to comment.