Skip to content
This repository has been archived by the owner on Aug 6, 2024. It is now read-only.

Commit

Permalink
Merge pull request #24 from leaphy-robotics/development
Browse files Browse the repository at this point in the history
Add more functionality to saving workspaces and recovering workspaces
  • Loading branch information
koen1711 authored Aug 11, 2023
2 parents ab7a422 + 9401cd7 commit 0aa271b
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 57 deletions.
7 changes: 2 additions & 5 deletions src/app/effects/app.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,8 @@ export class AppEffects {
this.appState.isCodeEditorToggleConfirmed$
.pipe(filter(isToggled => !!isToggled), withLatestFrom(this.appState.codeEditorType$))
.subscribe(([, codeEditorType]) => {
if (codeEditorType == CodeEditorType.Beginner) {
this.appState.setSelectedCodeEditor(CodeEditorType.Advanced);
} else {
this.appState.setSelectedCodeEditor(CodeEditorType.Beginner);
}
this.appState.setSelectedCodeEditor(codeEditorType === CodeEditorType.Beginner ? CodeEditorType.Advanced : CodeEditorType.Beginner);

});

// When the code editor changes, route to the correct screen
Expand Down
88 changes: 66 additions & 22 deletions src/app/effects/backend.wired.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,27 @@ import {MatDialog} from "@angular/material/dialog";
import {VariableDialog} from "../modules/core/dialogs/variable/variable.dialog";
import {UploadDialog} from "../modules/core/dialogs/upload/upload.dialog";
import {Router} from "@angular/router";
import {CodeEditorState} from "../state/code-editor.state";

declare var Blockly: any;

const fileExtensions = [
".l_flitz",
".l_original",
".l_click",
".l_uno",
".l_wifi",
".ino",
]

@Injectable({
providedIn: 'root',
})

// Defines the effects on the Electron environment that different state changes have
export class BackendWiredEffects {

constructor(private blocklyState: BlocklyEditorState, private router: Router, private backEndState: BackEndState, private appState: AppState, private blocklyEditorState: BlocklyEditorState, private robotWiredState: RobotWiredState, private dialogState: DialogState, private zone: NgZone, private dialog: MatDialog) {
constructor(private codeEditorState: CodeEditorState, private blocklyState: BlocklyEditorState, private router: Router, private backEndState: BackEndState, private appState: AppState, private blocklyEditorState: BlocklyEditorState, private robotWiredState: RobotWiredState, private dialogState: DialogState, private zone: NgZone, private dialog: MatDialog) {
// Only set up these effects when we're in Desktop mode
this.appState.isDesktop$
.pipe(filter(isDesktop => !!isDesktop))
Expand Down Expand Up @@ -112,7 +122,7 @@ export class BackendWiredEffects {
.pipe(withLatestFrom(this.appState.codeEditorType$))
.pipe(filter(([status, codeEditorType]) => status === WorkspaceStatus.Finding && codeEditorType === CodeEditorType.Advanced))
.subscribe(() => {
this.send('restore-workspace-code', appState.genericRobotType.id);
this.send('restore-workspace-code', AppState.genericRobotType.id);
});

// When the temp workspace is being loaded, relay the command to Electron
Expand Down Expand Up @@ -161,7 +171,7 @@ export class BackendWiredEffects {
.pipe(filter(([status, codeEditorType]) => status === WorkspaceStatus.SavingAs && codeEditorType === CodeEditorType.Advanced))
.pipe(withLatestFrom(this.blocklyEditorState.projectFilePath$, this.blocklyEditorState.code$))
.subscribe(([, projectFilePath, code]) => {
const payload = {projectFilePath, data: code, extension: appState.genericRobotType.id};
const payload = {projectFilePath, data: code, extension: AppState.genericRobotType.id};
this.send('save-workspace-as', payload);
});

Expand All @@ -170,8 +180,12 @@ export class BackendWiredEffects {
.pipe(filter(status => status === WorkspaceStatus.SavingTemp))
.pipe(withLatestFrom(this.blocklyEditorState.workspaceXml$, this.appState.selectedRobotType$))
.subscribe(([, workspaceXml, robotType]) => {
const payload = {data: workspaceXml, extension: robotType.id};
this.send('save-workspace-temp', payload);
if (CodeEditorType.Advanced == this.appState.getCurrentEditor()) {
this.send('save-workspace-temp', {data: workspaceXml, extension: robotType.id, type: 'advanced'});
} else {
this.send('save-workspace-temp', {data: workspaceXml, extension: robotType.id});
}

});

// When the user clicks help, open the default OS browser with the leaphy Forum
Expand Down Expand Up @@ -203,18 +217,16 @@ export class BackendWiredEffects {
});

fileNamesDialogRef.afterClosed().subscribe((name: string) => {
console.log(this.appState.getCurrentEditor())
if (this.appState.getCurrentEditor() == CodeEditorType.Beginner) {
const data = this.blocklyEditorState.workspaceXml;
const blob = new Blob([data], {type: 'text/plain'});
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = name + '.leaphy';
a.download = name + '.' + args[0].extension;

a.click();
window.URL.revokeObjectURL(url);
// delete a after it is clicked
a.remove();
} else {
const data = this.blocklyEditorState.code;
Expand Down Expand Up @@ -263,21 +275,36 @@ export class BackendWiredEffects {
case 'restore-workspace':
var input = document.createElement('input');
input.type = 'file';
// add a list of extensions to accept
input.accept = fileExtensions.join(',');

input.onchange = e => {

// getting a hold of the file reference
// @ts-ignore
var file = e.target.files[0];

// setting up the reader
var reader = new FileReader();
reader.readAsText(file,'UTF-8');

// here we tell the reader what to do when it's done reading...
reader.onload = readerEvent => {
const data = readerEvent.target.result; // this is the content!
this.backEndState.setBackendMessage({event: 'WORKSPACE_RESTORING', message: 'WORKSPACE_RESTORING', payload: { projectFilePath: file.path, data }, displayTimeout: 2000});
if (!fileExtensions.includes(file.name.substring(file.name.lastIndexOf('.'))))
return;

if (file.name.endsWith('.ino')) {
this.backEndState.setBackendMessage({
event: 'WORKSPACE_RESTORING',
message: 'WORKSPACE_RESTORING',
payload: {projectFilePath: file.path, data, type: 'advanced'},
displayTimeout: 2000
});
} else {
this.backEndState.setBackendMessage({
event: 'WORKSPACE_RESTORING',
message: 'WORKSPACE_RESTORING',
payload: {projectFilePath: file.path, data, type: 'beginner', extension: file.name.substring(file.name.lastIndexOf('.'))},
displayTimeout: 2000
});
}
}

}
Expand All @@ -292,19 +319,36 @@ export class BackendWiredEffects {
case 'save-workspace-temp':
const data = args[0].data;
sessionStorage.setItem('workspace', data);
sessionStorage.setItem('robotType', this.appState.getSelectedRobotType().id);
if (this.appState.getCurrentEditor() == CodeEditorType.Beginner) {
sessionStorage.setItem('type', 'beginner');
} else {
sessionStorage.setItem('type', 'advanced');
}
break;
case 'restore-workspace-temp':
console.log('restoring workspace');
const workspaceTemp = sessionStorage.getItem('workspace');
console.log(workspaceTemp);
try {
this.blocklyState.setWorkspaceXml(workspaceTemp);
this.blocklyState.setProjectFilePath('');
this.blocklyState.setWorkspaceStatus(WorkspaceStatus.Restoring);
} catch (error) {
console.log('Error:', error.message);
const robotType = sessionStorage.getItem('robotType');
const type = sessionStorage.getItem('type');
if (type == 'beginner' && this.appState.getCurrentEditor() == CodeEditorType.Beginner) {
if (robotType != this.appState.getSelectedRobotType().id) {
return;
}
try {
this.blocklyState.setWorkspaceXml(workspaceTemp);
this.blocklyState.setProjectFilePath('');
this.blocklyState.setWorkspaceStatus(WorkspaceStatus.Restoring);
} catch (error) {
console.log('Error:', error.message);
}
} else if (type == 'advanced' && this.appState.getCurrentEditor() == CodeEditorType.Advanced) {
try {
this.codeEditorState.setCode(workspaceTemp);
this.blocklyEditorState.setWorkspaceStatus(WorkspaceStatus.Restoring);
} catch (error) {
console.log('Error:', error.message);
}
}
console.log('restored workspace');
break;
default:
console.log(channel);
Expand Down
21 changes: 11 additions & 10 deletions src/app/effects/blockly-editor.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class BlocklyEditorEffects {
// When all prerequisites are there, Create a new workspace and open the codeview if needed
combineLatest([this.blocklyState.blocklyElement$, this.blocklyState.blocklyConfig$])
.pipe(withLatestFrom(this.appState.selectedRobotType$))
.pipe(filter(([[element, config], robotType]) => !!element && !!config && !!robotType && robotType !== this.appState.genericRobotType))
.pipe(filter(([[element, config], robotType]) => !!element && !!config && !!robotType && robotType !== AppState.genericRobotType))
.pipe(withLatestFrom(
this.getXmlContent('./assets/blockly/base-toolbox.xml'),
this.getXmlContent('./assets/blockly/leaphy-toolbox.xml'),
Expand Down Expand Up @@ -271,20 +271,21 @@ export class BlocklyEditorEffects {
this.blocklyState.setWorkspaceStatus(WorkspaceStatus.Clean);
break;
case 'WORKSPACE_RESTORING':
if (message.payload.type == 'advanced') {
this.blocklyState.setCode(message.payload.data as string);
this.appState.setSelectedCodeEditor(CodeEditorType.Advanced);
this.blocklyState.setProjectFilePath(message.payload.projectFilePath);
this.blocklyState.setWorkspaceStatus(WorkspaceStatus.Restoring);
this.appState.setSelectedRobotType(AppState.genericRobotType);
return;
}
this.appState.setSelectedRobotType(AppState.idToRobotType[message.payload.extension.replace('.', '')]);
this.blocklyState.setWorkspaceXml(message.payload.data as string);
this.blocklyState.setProjectFilePath(message.payload.projectFilePath);
this.blocklyState.setWorkspaceStatus(WorkspaceStatus.Restoring);
break;
case 'WORKSPACE_CODE_RESTORING':
this.blocklyState.setCode(message.payload.data as string);
this.blocklyState.setProjectFilePath(message.payload.projectFilePath);
this.blocklyState.setWorkspaceStatus(WorkspaceStatus.Restoring);
break;
case 'WORKSPACE_RESTORING_TEMP':
this.blocklyState.setWorkspaceXml(message.payload.data as string);
this.blocklyState.setWorkspaceStatus(WorkspaceStatus.Restoring);
break;
default:
console.log('Unknown message received from backend: ' + message.event);
break;
}
});
Expand Down
9 changes: 8 additions & 1 deletion src/app/modules/blockly-editor/blockly-editor.page.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Component} from '@angular/core';
import { BlocklyEditorState } from 'src/app/state/blockly-editor.state';
import { DialogState } from 'src/app/state/dialog.state';
import {BackendWiredEffects} from "../../effects/backend.wired.effects";

@Component({
selector: 'app-blockly-editor',
Expand All @@ -12,5 +13,11 @@ export class BlocklyEditorPage {
constructor(
public blocklyState: BlocklyEditorState,
public dialogState: DialogState,
) {}
private backendWiredEffects: BackendWiredEffects,
private blocklyEditorState: BlocklyEditorState
) {
window.addEventListener("beforeunload", () => {
this.backendWiredEffects.send('save-workspace-temp', {data: this.blocklyEditorState.workspaceXml})
});
}
}
7 changes: 6 additions & 1 deletion src/app/modules/code-editor/code-editor.page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
import { CodeEditorState } from 'src/app/state/code-editor.state';
import {BackendWiredEffects} from "../../effects/backend.wired.effects";

@Component({
selector: 'app-code-editor',
Expand All @@ -10,9 +11,13 @@ export class CodeEditorPage implements AfterViewInit {

@ViewChild("editor") private editor: ElementRef<HTMLElement>;

constructor(private codeEditorState: CodeEditorState) { }
constructor(private codeEditorState: CodeEditorState, private backendWiredEffects: BackendWiredEffects) { }

ngAfterViewInit(): void {
this.codeEditorState.setAceElement(this.editor);

window.addEventListener("beforeunload", () => {
this.backendWiredEffects.send('save-workspace-temp', {data: this.codeEditorState.getCode()})
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ <h3>{{ "SELECT_ROBOT_START_PROJECT" | translate }}</h3>
</div>
<div class="row">
<div class="col align-self-center text-center">
<button mat-stroked-button (click)="onRobotSelected(appState.genericRobotType)">
<button mat-stroked-button (click)="onRobotSelected(AppState.genericRobotType)">
<mat-icon>editor</mat-icon><span>{{ "DIRECT_TO_CODE_EDITOR" | translate }}</span>
</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { AppState } from 'src/app/state/app.state';
import { RobotType } from 'src/app/domain/robot.type';
import {Component} from '@angular/core';
import {AppState} from 'src/app/state/app.state';
import {RobotType} from 'src/app/domain/robot.type';
import {CodeEditorType} from "../../../../domain/code-editor.type";
import {BackEndState} from "../../../../state/backend.state";
import {BackendWiredEffects} from "../../../../effects/backend.wired.effects";

@Component({
selector: 'app-robot-selection',
Expand All @@ -9,8 +12,17 @@ import { RobotType } from 'src/app/domain/robot.type';
})
export class RobotSelectionComponent {

constructor(public appState: AppState) { }
constructor(public appState: AppState, private backEndState: BackendWiredEffects) { }
public onRobotSelected(robot: RobotType) {
this.appState.setSelectedRobotType(robot);
console.log(robot);
if (robot.id === 'l_code') {
this.appState.setSelectedCodeEditor(CodeEditorType.Advanced)
} else {
this.appState.setSelectedCodeEditor(CodeEditorType.Beginner)
}
this.backEndState.send('restore-workspace-temp', {});
}

protected readonly AppState = AppState;
}
33 changes: 23 additions & 10 deletions src/app/state/app.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,33 @@ import packageJson from '../../../package.json';
})
export class AppState {
/* eslint-disable max-len */
private leaphyOriginalRobotType = new RobotType('l_original', 'Leaphy Original', 'orig.svg', 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
private static leaphyOriginalRobotType = new RobotType('l_original', 'Leaphy Original', 'orig.svg', 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
['Leaphy Original Extension', 'Leaphy Extra Extension', 'Servo', 'Adafruit GFX Library', 'Adafruit SSD1306', 'Adafruit LSM9DS1 Library', 'Adafruit Unified Sensor']
);
private leaphyFlitzRobotType = new RobotType('l_flitz', 'Leaphy Flitz', 'flitz.svg', 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
private static leaphyFlitzRobotType = new RobotType('l_flitz', 'Leaphy Flitz', 'flitz.svg', 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
['Leaphy Extra Extension', 'Servo', 'Adafruit GFX Library', 'Adafruit SSD1306', 'Adafruit LSM9DS1 Library', 'Adafruit Unified Sensor'], true, false, false
);
private leaphyClickRobotType = new RobotType('l_click', 'Leaphy Click', 'click.svg', 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
private static leaphyClickRobotType = new RobotType('l_click', 'Leaphy Click', 'click.svg', 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
['Leaphy Extra Extension', 'Servo']
);
private arduinoUnoRobotType = new RobotType('l_uno', 'Arduino Uno', 'uno.svg', 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
private static arduinoUnoRobotType = new RobotType('l_uno', 'Arduino Uno', 'uno.svg', 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
['Leaphy Extra Extension', 'Servo', 'Adafruit GFX Library', 'Adafruit SSD1306', 'Adafruit LSM9DS1 Library', 'Adafruit Unified Sensor']
);
private leaphyWiFiRobotType = new RobotType('l_wifi', 'Leaphy WiFi', 'wifi.svg', 'NodeMCU', 'esp8266:esp8266:nodemcuv2', 'bin', 'esp8266:esp8266',
private static leaphyWiFiRobotType = new RobotType('l_wifi', 'Leaphy WiFi', 'wifi.svg', 'NodeMCU', 'esp8266:esp8266:nodemcuv2', 'bin', 'esp8266:esp8266',
['Leaphy WiFi Extension', 'Leaphy Extra Extension', 'Servo', 'Adafruit GFX Library', 'Adafruit SSD1306', 'Adafruit LSM9DS1 Library', 'Adafruit Unified Sensor'], false
);
public genericRobotType = new RobotType('l_code', 'Generic Robot', null, 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
public static genericRobotType = new RobotType('l_code', 'Generic Robot', null, 'Arduino UNO', 'arduino:avr:uno', 'hex', 'arduino:avr',
['Leaphy Original Extension', 'Leaphy Extra Extension', 'Servo', 'Adafruit GFX Library', 'Adafruit SSD1306', 'Adafruit LSM9DS1 Library', 'Adafruit Unified Sensor']
);

public static idToRobotType = {
'l_original': AppState.leaphyOriginalRobotType,
'l_flitz': AppState.leaphyFlitzRobotType,
'l_click': AppState.leaphyClickRobotType,
'l_uno': AppState.arduinoUnoRobotType,
'l_wifi': AppState.leaphyWiFiRobotType,
'l_code': AppState.genericRobotType
}
/* eslint-enable max-len */

private defaultLanguage = new Language('nl', 'Nederlands')
Expand All @@ -42,9 +51,9 @@ export class AppState {
this.availableRobotTypes$ = this.isDesktop$
.pipe(map(isDesktop => {
if (isDesktop) {
return [this.leaphyFlitzRobotType, this.leaphyOriginalRobotType, this.leaphyClickRobotType, this.arduinoUnoRobotType]
return [AppState.leaphyFlitzRobotType, AppState.leaphyOriginalRobotType, AppState.leaphyClickRobotType, AppState.arduinoUnoRobotType]
} else {
return [this.leaphyWiFiRobotType]
return [AppState.leaphyWiFiRobotType]
}
}));

Expand All @@ -59,15 +68,15 @@ export class AppState {
this.codeEditorType$ = combineLatest([this.selectedRobotType$, this.selectedCodeEditorType$])
.pipe(filter(([robotType,]) => !!robotType))
.pipe(map(([robotType, selectedCodeEditorType]) => {
if (robotType === this.genericRobotType) {
if (robotType === AppState.genericRobotType) {
return CodeEditorType.Advanced
}
return selectedCodeEditorType;
}))

this.canChangeCodeEditor$ = this.selectedRobotType$
.pipe(filter(robotType => !!robotType))
.pipe(map(robotType => robotType !== this.genericRobotType))
.pipe(map(robotType => robotType !== AppState.genericRobotType))

this.packageJsonVersionSubject$ = new BehaviorSubject(packageJson.version);
this.packageJsonVersion$ = this.packageJsonVersionSubject$.asObservable();
Expand Down Expand Up @@ -166,4 +175,8 @@ export class AppState {
public getCurrentEditor(): CodeEditorType {
return this.selectedCodeEditorTypeSubject$.getValue();
}

public getSelectedRobotType(): RobotType {
return this.selectedRobotTypeSubject$.getValue();
}
}
Loading

0 comments on commit 0aa271b

Please sign in to comment.