Skip to content

Commit

Permalink
Merge branch 'rc'
Browse files Browse the repository at this point in the history
  • Loading branch information
Vovan-VE committed Oct 15, 2023
2 parents 80f46db + 61a8d27 commit 04dc53b
Show file tree
Hide file tree
Showing 59 changed files with 1,657 additions and 188 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## 0.17.0 (2023-10-15)

- Add: Textual editing for demo keystrokes.
- Fix: SP file format loss demo signature on file read.

### Desktop

- Add: Prevent multiple instances to ran in the same time.
- Add: "Open file with" like whatever editors do.
- Fix: Same file now cannot be opened multiple times in same instance.
- Fix: Debug app didn't write logs.
- Fix: Files, opened in previous run, if missing on startup didn't prune from
internal storage, causing the last to grow and keep trying to open the files
on every program run.
- Fix: Invisible app window on start if app was exited being minimized (Win10).

## 0.16.1 (2023-09-18)

### Desktop
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ INNER_BIN_NAME = $(call INNER_BIN_NAME_2,$(subst /, ,$(1)))

# $(call RESULT_BIN_NAME,<PLATFORM>)
# $(call RESULT_BIN_NAME,<OS>/<ARCH>)
RESULT_BIN_NAME = $(BIN_DIR)/$(APP_BASENAME)-$(subst /,-,$(1))$(if $(DEBUG),-debug)-v$(VERSION)
RESULT_BIN_NAME = $(BIN_DIR)/$(APP_BASENAME)-$(subst /,-,$(1))-v$(VERSION)$(if $(DEBUG),-debug)
RESULT_BIN_NAME_ZIP = $(call RESULT_BIN_NAME,$(1)).zip
# $(call RESULT_BIN_NAME_WINDOWS_PKG,<ARCH>)
RESULT_BIN_NAME_WINDOWS_PKG = $(call RESULT_BIN_NAME,windows/$(1))-installer.exe
Expand Down
7 changes: 2 additions & 5 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@
- Impossible without gameplay simulation. Only if SO will provide a path
actually walked.
- Tooltips with interactive content support.
- Demo handmade
- demo to text
- text to demo

### Desktop

- Prevent multiple instance
- Communication: pass opened file
- Single instance: activate primary instance in better way.
- Windows file types association.

## Wishes from users (unsorted)

Expand Down
135 changes: 117 additions & 18 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,47 @@ import (
"os"
"path/filepath"
"strings"
"time"

"github.com/pkg/errors"
"github.com/vovan-ve/sple-desktop/internal/backend"
"github.com/vovan-ve/sple-desktop/internal/config"
"github.com/vovan-ve/sple-desktop/internal/files"
"github.com/vovan-ve/sple-desktop/internal/helpers"
"github.com/vovan-ve/sple-desktop/internal/singleton"
"github.com/vovan-ve/sple-desktop/internal/storage"
"github.com/wailsapp/wails/v2/pkg/logger"
"github.com/wailsapp/wails/v2/pkg/runtime"
)

type AppOptions struct {
Logger logger.Logger
StartupOpenFiles []string
StartupError error
}

// App struct
type App struct {
ctx context.Context
appConfig storage.Full[string]
frontConfig storage.Full[string]
chosenReg files.ChosenRegistry
files storage.Full[*files.Record]
files files.Storage

isDirty bool

opt *AppOptions
}

// NewApp creates a new App application struct
func NewApp() *App { return &App{} }
func NewApp(opt *AppOptions) *App {
if opt == nil {
opt = &AppOptions{}
}
return &App{
opt: opt,
}
}

// startup is called at application startup
func (a *App) startup(ctx context.Context) {
Expand All @@ -56,7 +74,7 @@ func (a *App) startup(ctx context.Context) {

filesRegPath := filepath.Join(configDir, "files.json")
chosenReg := files.NewChosenRegistry()
fs, err := files.NewStorage(filesRegPath, chosenReg)
fs, err := files.NewStorage(ctx, filesRegPath, chosenReg)
if err != nil {
runtime.LogErrorf(ctx, "files registry: %v", err)
return
Expand All @@ -66,6 +84,8 @@ func (a *App) startup(ctx context.Context) {
a.frontConfig = front
a.chosenReg = chosenReg
a.files = fs

go a.singletonServer()
}

// domReady is called after front-end resources have been loaded
Expand All @@ -84,6 +104,17 @@ func (a *App) domReady(ctx context.Context) {
runtime.WindowSetSize(ctx, p.W, p.H)
}

if len(a.opt.StartupOpenFiles) != 0 {
ref, err := a.openFiles(a.opt.StartupOpenFiles)
a.opt.StartupOpenFiles = nil
a.showError(&err)
if len(ref) != 0 {
a.triggerFront(backend.FEOpenFiles, ref)
}
}
a.showError(&a.opt.StartupError)
a.opt.StartupError = nil

go a.checkUpdate()
}

Expand Down Expand Up @@ -144,7 +175,7 @@ func (a *App) beforeClose(ctx context.Context) (prevent bool) {
prevent = a.isDirty
if prevent {
a.triggerFront(backend.FEExitDirty, nil)
} else {
} else if !runtime.WindowIsMinimised(ctx) {
p := config.WindowPlacement{}
p.X, p.Y = runtime.WindowGetPosition(ctx)
p.W, p.H = runtime.WindowGetSize(ctx)
Expand Down Expand Up @@ -211,7 +242,7 @@ func (a *App) CreateFile(key string, baseFileName string) (actualName string, er
return filepath.Base(fPath), nil
}

func (a *App) OpenFile(multiple bool) []*backend.WebFileRef {
func (a *App) OpenFile(multiple bool) (ret []*backend.WebFileRef) {
defer a.catchPanic()
var err error
defer a.showError(&err)
Expand All @@ -235,19 +266,27 @@ func (a *App) OpenFile(multiple bool) []*backend.WebFileRef {
filenames = append(filenames, fn)
}

var (
ret []*backend.WebFileRef
failed []string
)
ret, err = a.openFiles(filenames)
return
}

func (a *App) openFiles(filenames []string) (ret []*backend.WebFileRef, _ error) {
var failed []string
for _, filename := range filenames {
f, err2 := os.Stat(filename)
if err2 != nil {
failed = append(failed, fmt.Sprintf("- Cannot stat file <%s> - %s", filename, err2.Error()))
if has, err := a.files.HasFile(filename); err != nil {
runtime.LogErrorf(a.ctx, "check if file already opened: %v", err)
} else if has {
continue
}
b, err2 := files.NewFile(filename).Read()
if err2 != nil {
failed = append(failed, fmt.Sprintf("- Cannot read file <%s> - %s", filename, err2.Error()))

f, err := os.Stat(filename)
if err != nil {
failed = append(failed, fmt.Sprintf("- Cannot stat file: %s", err.Error()))
continue
}
b, err := files.NewFile(filename).Read()
if err != nil {
failed = append(failed, fmt.Sprintf("- Cannot read file: %s", err.Error()))
continue
}
ret = append(ret, &backend.WebFileRef{
Expand All @@ -259,10 +298,70 @@ func (a *App) OpenFile(multiple bool) []*backend.WebFileRef {
})
}
if len(failed) > 0 {
err = errors.New("Cannot open following files:\n\n" + strings.Join(failed, "\n\n"))
return nil
return nil, errors.New("Cannot open following files:\n" + strings.Join(failed, "\n"))
}
return
}

func (a *App) singletonServer() {
defer a.catchPanic()
recv := make(chan []byte)
go func() {
defer a.catchPanic()
defer close(recv)
err := singleton.RunReceiver(a.ctx, a.opt.Logger, recv)
if err != nil {
runtime.LogErrorf(a.ctx, "IPC server run: %#v", err)
}
}()
a.readSingletonMessages(recv)
}

func (a *App) activateWindow() {
// TODO: better activate window
runtime.LogDebugf(a.ctx, "%v activating window", time.Now())
runtime.WindowHide(a.ctx)
time.Sleep(10 * time.Millisecond)
runtime.WindowShow(a.ctx)
}

func (a *App) readSingletonMessages(recv <-chan []byte) {
activateDuration := 30 * time.Millisecond
activate := time.AfterFunc(activateDuration, a.activateWindow)
activate.Stop()
defer activate.Stop()
for {
select {
case <-a.ctx.Done():
return
case b := <-recv:
if b == nil {
return
}
msg, err := files.MessageFromIpc(b)
if err != nil {
runtime.LogWarningf(a.ctx, "cannot parse ipc message: %#v", err)
continue
}

runtime.LogDebugf(a.ctx, "IPC message: %s", msg)
switch msg.Type {
case files.IpcMessageOpenFile:
s := string(msg.Data)
runtime.LogDebugf(a.ctx, "IPC open file: %s", s)
ref, err := a.openFiles([]string{s})
a.showError(&err)
if len(ref) != 0 {
a.triggerFront(backend.FEOpenFiles, ref)
}
case files.IpcMessageActivate:
runtime.LogDebugf(a.ctx, "%v will activate window", time.Now())
activate.Reset(activateDuration)
default:
runtime.LogDebugf(a.ctx, "IPC message type unknown: %d", msg.Type)
}
}
}
return ret
}

func (a *App) SaveFileAs(blob64 helpers.Blob64, baseFileName string) {
Expand Down
3 changes: 2 additions & 1 deletion build/linux/deb/usr/share/applications/sple-desktop.desktop
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
Type=Application
Name=SpLE Desktop
Comment=Desktop version of sple.me
Exec=sple-desktop
Exec=sple-desktop %F
Icon=sple-desktop
Terminal=false
Categories=Game;Application;
MimeType=application/octet-stream;
Keywords=sple;supaplex;editor;
4 changes: 2 additions & 2 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "supaplex-levels-editor",
"version": "0.16.1",
"version": "0.17.0",
"private": true,
"description": "Supaplex Levels Editor in browser",
"keywords": [
Expand Down
1 change: 1 addition & 0 deletions frontend/src/backend/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type CreateFile = (
baseName: string,
) => Promise<string>;
export type OpenFile = (options: I.OpenFileOptions) => void;
export type OnOpenFile = Event<I.OpenFiles>;
export type SaveFileAs = (data: Blob, filename: string) => void;

export type SetTitle = (title: string) => void;
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/backend/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as wails from "./wails";
import * as web from "./web";

export type {
OpenFileDoneItem,
OpenFileItem,
FilesStorageKey,
FilesStorageItem,
} from "./internal";
Expand Down Expand Up @@ -34,6 +34,9 @@ export const createFile: B.CreateFile | undefined = WAILS
? wails.createFile
: web.createFile;
export const openFile: B.OpenFile = WAILS ? wails.openFile : web.openFile;
export const onOpenFile: B.OnOpenFile | undefined = WAILS
? wails.onOpenFile
: undefined;
export const saveFileAs: B.SaveFileAs = WAILS
? wails.saveFileAs
: web.saveFileAs;
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/backend/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ export interface FilesStorageItem {
}
export type FilesStorage = StoreDriver<string, FilesStorageItem>;

export interface OpenFileDoneItem {
export interface OpenFileItem {
file: File;
key?: FilesStorageKey;
}
export type OpenFileDoneCallback = (items: readonly OpenFileDoneItem[]) => void;
export type OpenFiles = readonly OpenFileItem[];
export type OpenFileDoneCallback = (items: OpenFiles) => void;
export interface OpenFileOptions {
multiple?: boolean;
done: OpenFileDoneCallback;
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/backend/wails/fileRefToOpenFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { base64Decode } from "utils/encoding/base64";
import { FilesStorageKey, OpenFileItem } from "../internal";
import { files } from "./go/models";

export const fileRefToOpenFile = (f: files.WebFileRef): OpenFileItem => ({
file: new File([base64Decode(f.$$blob64)], f.name),
key: f.$$id as FilesStorageKey,
});
1 change: 1 addition & 0 deletions frontend/src/backend/wails/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { filesStorage } from "./filesStorage";
export const allowManualSave = true;
export { CreateFile as createFile } from "./go/main/App";
export { openFile } from "./openFile";
export { onOpenFile } from "./trigger";
export { saveFileAs } from "./saveFileAs";

export { WindowSetTitle as setTitle } from "./runtime";
Expand Down
11 changes: 3 additions & 8 deletions frontend/src/backend/wails/openFile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { base64Decode } from "utils/encoding/base64";
import { FilesStorageKey, OpenFileOptions } from "../internal";
import { OpenFileOptions } from "../internal";
import { fileRefToOpenFile } from "./fileRefToOpenFile";
import { OpenFile } from "./go/main/App";
import { files } from "./go/models";

Expand All @@ -8,12 +8,7 @@ export const openFile = async ({ multiple = false, done }: OpenFileOptions) => {
try {
files = await OpenFile(multiple);
if (files?.length) {
done(
files.map((f) => ({
file: new File([base64Decode(f.$$blob64)], f.name),
key: f.$$id as FilesStorageKey,
})),
);
done(files.map(fileRefToOpenFile));
}
} catch {}
};
Loading

0 comments on commit 04dc53b

Please sign in to comment.