2024-12-23 17:22:37 +01:00
package main
import (
"changeme/hardware"
"fmt"
2024-12-29 13:09:46 +01:00
"github.com/rs/zerolog/log"
2024-12-23 17:22:37 +01:00
"os"
"path/filepath"
"time"
"github.com/wailsapp/wails/v2/pkg/runtime"
"gopkg.in/yaml.v2"
)
const (
projectsDirectory = "projects" // The directory were are stored all the projects
avatarsDirectory = "frontend/public" // The directory were are stored all the avatars
projectExtension = ".dmxproj" // The extension of a DMX Connect project
)
// GetProjects gets all the projects in the projects directory
func ( a * App ) GetProjects ( ) ( [ ] ProjectMetaData , error ) {
projects := [ ] ProjectMetaData { }
f , err := os . Open ( projectsDirectory )
if err != nil {
2024-12-29 13:09:46 +01:00
log . Err ( err ) . Str ( "file" , "project" ) . Msg ( "unable to open the projects directory" )
return nil , fmt . Errorf ( "unable to open the projects directory: %v" , err )
2024-12-23 17:22:37 +01:00
}
2024-12-29 13:09:46 +01:00
log . Trace ( ) . Str ( "file" , "project" ) . Str ( "projectsDirectory" , projectsDirectory ) . Msg ( "projects directory opened" )
2024-12-23 17:22:37 +01:00
files , err := f . Readdir ( 0 )
if err != nil {
2024-12-29 13:09:46 +01:00
log . Err ( err ) . Str ( "file" , "project" ) . Msg ( "unable to read the projects directory" )
return nil , fmt . Errorf ( "unable to read the projects directory: %v" , err )
2024-12-23 17:22:37 +01:00
}
2024-12-29 13:09:46 +01:00
log . Trace ( ) . Str ( "file" , "project" ) . Any ( "projectsFiles" , files ) . Msg ( "project files got" )
2024-12-23 17:22:37 +01:00
for _ , fileInfo := range files {
// Open the file and get the show name
fileData , err := os . ReadFile ( filepath . Join ( projectsDirectory , fileInfo . Name ( ) ) )
2024-12-29 13:09:46 +01:00
if err != nil {
log . Warn ( ) . Str ( "file" , "project" ) . Str ( "projectFile" , fileInfo . Name ( ) ) . Msg ( "unable to open the project file" )
continue
}
log . Trace ( ) . Str ( "file" , "project" ) . Str ( "projectFile" , fileInfo . Name ( ) ) . Any ( "fileData" , fileData ) . Msg ( "project file read" )
projectObject := ProjectInfo { }
err = yaml . Unmarshal ( fileData , & projectObject )
if err != nil {
log . Warn ( ) . Str ( "file" , "project" ) . Str ( "projectFile" , fileInfo . Name ( ) ) . Msg ( "project has invalid format" )
continue
2024-12-23 17:22:37 +01:00
}
2024-12-29 13:09:46 +01:00
log . Trace ( ) . Str ( "file" , "project" ) . Str ( "projectFile" , fileInfo . Name ( ) ) . Msg ( "project file unmarshalled" )
// Add the SaveFile property
projects = append ( projects , ProjectMetaData {
Name : projectObject . ShowInfo . Name ,
Save : fileInfo . Name ( ) ,
} )
2024-12-23 17:22:37 +01:00
}
2024-12-29 13:09:46 +01:00
log . Info ( ) . Str ( "file" , "project" ) . Any ( "projectsList" , projects ) . Msg ( "got the projects list" )
2024-12-23 17:22:37 +01:00
return projects , nil
}
// CreateProject creates a new blank project
func ( a * App ) CreateProject ( ) ShowInfo {
date := time . Now ( )
a . projectSave = ""
a . projectInfo . ShowInfo = ShowInfo {
Name : "My new show" ,
Date : fmt . Sprintf ( "%04d-%02d-%02dT%02d:%02d" , date . Year ( ) , date . Month ( ) , date . Day ( ) , date . Hour ( ) , date . Minute ( ) ) ,
Avatar : "appicon.png" ,
Comments : "Write your comments here" ,
}
2024-12-29 13:09:46 +01:00
log . Info ( ) . Str ( "file" , "project" ) . Any ( "showInfo" , a . projectInfo . ShowInfo ) . Msg ( "project has been created" )
2024-12-23 17:22:37 +01:00
return a . projectInfo . ShowInfo
}
// GetProjectInfo returns the information of the saved project
func ( a * App ) GetProjectInfo ( projectFile string ) ( ProjectInfo , error ) {
// Open the project file
projectPath := filepath . Join ( projectsDirectory , projectFile )
2024-12-29 13:09:46 +01:00
log . Trace ( ) . Str ( "file" , "project" ) . Str ( "projectPath" , projectPath ) . Msg ( "project path is created" )
2024-12-23 17:22:37 +01:00
content , err := os . ReadFile ( projectPath )
if err != nil {
2024-12-29 13:09:46 +01:00
log . Err ( err ) . Str ( "file" , "project" ) . Str ( "projectFile" , projectFile ) . Msg ( "Unable to read the project file" )
return ProjectInfo { } , fmt . Errorf ( "unable to read the project file: %v" , err )
2024-12-23 17:22:37 +01:00
}
2024-12-29 13:09:46 +01:00
log . Trace ( ) . Str ( "file" , "project" ) . Str ( "projectPath" , projectPath ) . Msg ( "project file read" )
2024-12-23 17:22:37 +01:00
a . projectInfo = ProjectInfo { }
err = yaml . Unmarshal ( content , & a . projectInfo )
if err != nil {
2024-12-29 13:09:46 +01:00
log . Err ( err ) . Str ( "file" , "project" ) . Str ( "projectFile" , projectFile ) . Msg ( "Unable to get the project information" )
return ProjectInfo { } , fmt . Errorf ( "unable to get the project information: %v" , err )
2024-12-23 17:22:37 +01:00
}
2024-12-29 13:09:46 +01:00
log . Trace ( ) . Str ( "file" , "project" ) . Str ( "projectPath" , projectPath ) . Msg ( "project information got" )
2024-12-23 17:22:37 +01:00
// Load it into the app
a . projectSave = projectFile
// Return the show information
2024-12-29 13:09:46 +01:00
log . Info ( ) . Str ( "file" , "project" ) . Any ( "projectInfo" , a . projectInfo ) . Msg ( "got the project information" )
2024-12-23 17:22:37 +01:00
return a . projectInfo , nil
}
// ChooseAvatarPath opens a filedialog to choose the show avatar
func ( a * App ) ChooseAvatarPath ( ) ( string , error ) {
// Open the file dialog box
filePath , err := runtime . OpenFileDialog ( a . ctx , runtime . OpenDialogOptions {
Title : "Choose your show avatar" ,
Filters : [ ] runtime . FileFilter {
{
DisplayName : "Images" ,
Pattern : "*.png;*.jpg;*.jpeg" ,
} ,
} ,
} )
if err != nil {
2024-12-29 13:09:46 +01:00
log . Err ( err ) . Str ( "file" , "project" ) . Msg ( "unable to open the avatar dialog" )
2024-12-23 17:22:37 +01:00
return "" , err
}
2024-12-29 13:09:46 +01:00
log . Debug ( ) . Str ( "file" , "project" ) . Msg ( "avatar dialog is opened" )
2024-12-23 17:22:37 +01:00
// Copy the avatar to the application avatars path
avatarPath := filepath . Join ( avatarsDirectory , filepath . Base ( filePath ) )
2024-12-29 13:09:46 +01:00
log . Trace ( ) . Str ( "file" , "project" ) . Str ( "avatarPath" , avatarPath ) . Msg ( "avatar path is created" )
2024-12-23 17:22:37 +01:00
_ , err = copy ( filePath , avatarPath )
if err != nil {
2024-12-29 13:09:46 +01:00
log . Err ( err ) . Str ( "file" , "project" ) . Str ( "avatarsDirectory" , avatarsDirectory ) . Str ( "fileBase" , filepath . Base ( filePath ) ) . Msg ( "unable to copy the avatar file" )
2024-12-23 17:22:37 +01:00
return "" , err
}
2024-12-29 13:09:46 +01:00
log . Info ( ) . Str ( "file" , "project" ) . Str ( "avatarFileName" , filepath . Base ( filePath ) ) . Msg ( "got the new avatar file" )
2024-12-23 17:22:37 +01:00
return filepath . Base ( filePath ) , nil
}
// UpdateShowInfo updates the show information
func ( a * App ) UpdateShowInfo ( showInfo ShowInfo ) {
a . projectInfo . ShowInfo = showInfo
2024-12-29 13:09:46 +01:00
log . Info ( ) . Str ( "file" , "project" ) . Any ( "showInfo" , showInfo ) . Msg ( "show information was updated" )
2024-12-23 17:22:37 +01:00
}
// SaveProject saves the project
func ( a * App ) SaveProject ( ) ( string , error ) {
// If there is no save file, create a new one with the show name
if a . projectSave == "" {
date := time . Now ( )
a . projectSave = fmt . Sprintf ( "%04d%02d%02d%02d%02d%02d%s" , date . Year ( ) , date . Month ( ) , date . Day ( ) , date . Hour ( ) , date . Minute ( ) , date . Second ( ) , projectExtension )
2024-12-29 13:09:46 +01:00
log . Debug ( ) . Str ( "file" , "project" ) . Str ( "newProjectSave" , a . projectSave ) . Msg ( "projectSave is null, getting a new one" )
2024-12-23 17:22:37 +01:00
}
data , err := yaml . Marshal ( a . projectInfo )
if err != nil {
2024-12-29 13:09:46 +01:00
log . Err ( err ) . Str ( "file" , "project" ) . Any ( "projectInfo" , a . projectInfo ) . Msg ( "unable to format the project information" )
2024-12-23 17:22:37 +01:00
return "" , err
}
2024-12-29 13:09:46 +01:00
log . Trace ( ) . Str ( "file" , "project" ) . Any ( "projectInfo" , a . projectInfo ) . Msg ( "projectInfo has been marshalled" )
2024-12-23 17:22:37 +01:00
// Create the project directory if not exists
err = os . MkdirAll ( projectsDirectory , os . ModePerm )
if err != nil {
2024-12-29 13:09:46 +01:00
log . Err ( err ) . Str ( "file" , "project" ) . Str ( "projectsDirectory" , projectsDirectory ) . Msg ( "unable to create the projects directory" )
2024-12-23 17:22:37 +01:00
return "" , err
}
2024-12-29 13:09:46 +01:00
log . Trace ( ) . Str ( "file" , "project" ) . Str ( "projectsDirectory" , projectsDirectory ) . Msg ( "projects directory has been created" )
2024-12-23 17:22:37 +01:00
err = os . WriteFile ( filepath . Join ( projectsDirectory , a . projectSave ) , data , os . ModePerm )
if err != nil {
2024-12-29 13:09:46 +01:00
log . Err ( err ) . Str ( "file" , "project" ) . Str ( "projectsDirectory" , projectsDirectory ) . Str ( "projectSave" , a . projectSave ) . Msg ( "unable to save the project" )
2024-12-23 17:22:37 +01:00
return "" , err
}
2024-12-29 13:09:46 +01:00
log . Info ( ) . Str ( "file" , "project" ) . Str ( "projectFileName" , a . projectSave ) . Msg ( "project has been saved" )
2024-12-23 17:22:37 +01:00
return a . projectSave , nil
}
// ShowInfo defines the information of the show
type ShowInfo struct {
Name string ` yaml:"name" `
Date string ` yaml:"date" `
Avatar string ` yaml:"avatar" `
Comments string ` yaml:"comments" `
}
// ProjectMetaData defines all the minimum information for a lighting project
type ProjectMetaData struct {
Name string // Show name
Save string // The save file of the project
}
// ProjectInfo defines all the information for a lighting project
type ProjectInfo struct {
ShowInfo ShowInfo ` yaml:"show" ` // Show information
PeripheralsInfo map [ string ] hardware . PeripheralInfo ` yaml:"peripherals" ` // Peripherals information
}