Skip to content

Commit

Permalink
downloads
Browse files Browse the repository at this point in the history
  • Loading branch information
tsaxking committed Jan 27, 2024
1 parent dbed24e commit b085fdb
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 32 deletions.
28 changes: 14 additions & 14 deletions client/models/app/2024-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,6 @@ export const generate2024App = (
};

app.buttonCircle
.addButton(
'Blue Climb',
'Click when the robot has successfully pulled themselves up for the last time in the match',
'clb',
0,
drawButton('blue-stage'),
colors.blue,
'blue',
icons.clb,
)
.addButton(
'Blue Trap',
'When the robot has successfully placed an item in the trap',
Expand All @@ -199,13 +189,13 @@ export const generate2024App = (
icons.trp,
)
.addButton(
'Red Climb',
'Blue Climb',
'Click when the robot has successfully pulled themselves up for the last time in the match',
'clb',
0,
drawButton('red-stage'),
colors.red,
'red',
drawButton('blue-stage'),
colors.blue,
'blue',
icons.clb,
)
.addButton(
Expand All @@ -217,6 +207,16 @@ export const generate2024App = (
colors.red,
'red',
icons.trp,
)
.addButton(
'Red Climb',
'Click when the robot has successfully pulled themselves up for the last time in the match',
'clb',
0,
drawButton('red-stage'),
colors.red,
'red',
icons.clb,
);

const em = app.clickPoints();
Expand Down
104 changes: 93 additions & 11 deletions client/models/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import {
import { Icon } from '../canvas/material-icons';
import { SVG } from '../canvas/svg';
import { Match } from '../../../shared/submodules/tatorscout-calculations/match-submission';
import { downloadText } from '../../utilities/downloads';
import { choose } from '../../utilities/notifications';

/**
* Description placeholder
Expand Down Expand Up @@ -243,14 +245,72 @@ export type EventData = {
* @class App
* @typedef {App}
*/
export class App<a = Action, z extends Zones = Zones, p = TraceParse> {
export class App<a extends Action = Action, z extends Zones = Zones, p extends TraceParse = TraceParse> {
public static build(year: 2024, alliance: 'red' | 'blue' | null = null) {
switch (year) {
case 2024:
return generate2024App(alliance);
}
}

static cache(): {
trace: TraceArray;
tick: number;
location: Point2D;
} | null {
const data = window.localStorage.getItem('app');
if (!data) return null;
return JSON.parse(data);
}

static restore(app: App) {
const d = App.cache();
if (!d) return;
const { trace, location, tick } = d;
const { currentTick } = app;

app.build();
// simulate ticks
for (let i = 0; i < app.ticks.length; i++) {
const tick = app.ticks[i];
const p = trace.find(p => p[0] === i);
if (!p) continue;

app.currentTick = tick;
tick.point = [p[1], p[2]];
app.currentLocation = tick.point;
const obj = app.appObjects[p[3]] as AppObject<unknown, Action>;
obj.change(app.currentLocation);
}

app.currentLocation = location !== undefined ? location : app.currentLocation;
app.currentTick = tick !== undefined ? app.ticks[tick] : currentTick;
}


static save(app: App) {
window.localStorage.setItem('app', JSON.stringify({
trace: app.pull(),
tick: app.currentTick?.index,
location: app.currentLocation
}));
}

static clearCache() {
window.localStorage.removeItem('app');
}

static async upload(...matches: Match[]) {
return attemptAsync(async () => {
return Promise.all(
matches.map(async (m) => {
const d = await ServerRequest.post('/submit', m);
return d.isOk();
})
);
});
}

private static $eventData?: EventData;

public static async getEventData(): Promise<Result<EventData>> {
Expand Down Expand Up @@ -382,6 +442,22 @@ export class App<a = Action, z extends Zones = Zones, p = TraceParse> {
for (const [action, icon] of Object.entries(this.icons)) {
this.icons[action] = icon.clone();
}

if (App.cache()) {
choose('You have a cached match. Would you like to restore it?', 'Yes', 'No').then((res) => {
switch (res) {
case 'Yes':
App.restore(this as App<any, any, any>);
break;
case 'No':
App.clearCache();
break;
case null:
App.clearCache();
break;
}
});
}
}

/**
Expand Down Expand Up @@ -809,7 +885,7 @@ export class App<a = Action, z extends Zones = Zones, p = TraceParse> {

try {
const s = Date.now();
await cb?.(t);
cb?.(t);
if (Date.now() - s > 250) {
console.warn('Callback took too long');
}
Expand All @@ -824,11 +900,11 @@ export class App<a = Action, z extends Zones = Zones, p = TraceParse> {

// there could be a major delay if the callback takes too long, so we need to account for that
setTimeout(() => run(this.currentTick?.next(), i++), Math.max(0, App.tickDuration));
App.save(this as App<any, any, any>);
};

const start = () => {
console.log('start');
run(this.ticks[0], 0);
run(this.currentTick || this.ticks[0], 0);
target.removeEventListener('mousedown', start);
target.removeEventListener('touchstart', start);
};
Expand Down Expand Up @@ -1339,8 +1415,10 @@ export class App<a = Action, z extends Zones = Zones, p = TraceParse> {
[key: string]: string;
};
}) {
// set data to server
const res = await ServerRequest.post('/submit', {
// remove from cache when submitted. It's not needed anymore
App.clearCache();

const d: Match = {
trace: this.pull(),
comments: include.comments,
checks: include.checks,
Expand All @@ -1351,10 +1429,14 @@ export class App<a = Action, z extends Zones = Zones, p = TraceParse> {
teamNumber: 0, // TODO: implement team number
group: 0, // TODO: implement scout group
compLevel: 'qm', // TODO: implement comp level
} as Match);
if (res.isErr()) {
await alert('Error submitting, the server may be disconnected');
}
// download as json file
};

downloadText(
JSON.stringify(d),
`${d.eventKey}-${d.matchNumber}-${d.compLevel}.json`
);

// set data to server
return App.upload(d);
}
}
2 changes: 1 addition & 1 deletion client/utilities/downloads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const loadFiles = (): Promise<Result<FileList>> => {
} else {
rej(new Error('No files selected'));
}
};
}
});
});
};
Expand Down
129 changes: 129 additions & 0 deletions client/utilities/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,132 @@ export const prompt = async (question: string): Promise<string | null> => {
$(modal).modal('show');
});
};

export const select = async (question: string, options: string[]): Promise<number> => {
return new Promise<number>((res) => {
const id = 'alert-' + Math.random().toString(36).substring(2, 9);
const m = new Modal({
target: document.body,
props: {
title: 'Choose',
message: question,
id,
},
});

const modal = m.$$.root.querySelector('#' + id) as HTMLElement;

const select = document.createElement('select');
select.classList.add('form-control', 'mt-3');
const defaultOption = document.createElement('option');
defaultOption.value = '-1';
defaultOption.innerText = 'Select an option...';
select.appendChild(defaultOption);
modal.querySelector('.modal-body')?.appendChild(select);

options.forEach((option, i) => {
const o = document.createElement('option');
o.value = i.toString();
o.innerText = option;
select.appendChild(o);
});

const submitButton = new Button({
target: modal.querySelector('.modal-footer') as HTMLElement,
props: {
text: 'Confirm',
color: 'primary',
},
});

const cancelButton = new Button({
target: modal.querySelector('.modal-footer') as HTMLElement,
props: {
text: 'Cancel',
color: 'secondary',
},
});

const submit = () => {
$(modal).modal('hide');
res(parseInt(select.value));
};

select.addEventListener('keydown', (e) => {
switch (e.key) {
case 'Enter':
return submit();
case 'Escape':
return res(-1);
}
});

submitButton.$$.root
.querySelector('button.btn-primary')
?.addEventListener('click', submit);

cancelButton.$$.root
.querySelector('button.btn-secondary')
?.addEventListener('click', () => {
$(modal).modal('hide');
res(-1);
});

m.$on('close', () => {
$(modal).modal('hide');
res(-1);
});

$(modal).modal('show');
});
};

export const choose = async <A extends string, B extends string>(question: string, option1: A, option2: B): Promise<null | A | B> => {
return new Promise<null | A | B>((res) => {
const id = 'alert-' + Math.random().toString(36).substring(2, 9);
const m = new Modal({
target: document.body,
props: {
title: 'Choose',
message: question,
id,
},
});

const modal = m.$$.root.querySelector('#' + id) as HTMLElement;

const b1 = new Button({
target: modal.querySelector('.modal-footer') as HTMLElement,
props: {
text: option1,
color: 'primary',
},
});

const b2 = new Button({
target: modal.querySelector('.modal-footer') as HTMLElement,
props: {
text: option2,
color: 'secondary',
},
});

const submit = (i: null | A | B) => {
$(modal).modal('hide');
res(i);
};

b1.$$.root
.querySelector('button.btn-primary')
?.addEventListener('click', () => submit(option1));

b2.$$.root
.querySelector('button.btn-secondary')
?.addEventListener('click', () => submit(option2));

m.$on('close', () => submit(null));


$(modal).modal('show');
});
}
3 changes: 2 additions & 1 deletion client/views/Main.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Pre from './pages/Pre.svelte';
import { App } from '../models/app/app';
import type { EventData } from '../models/app/app';
import type { TBAMatch } from '../../shared/submodules/tatorscout-calculations/tba';
import Upload from './pages/Upload.svelte';
let event: EventData;
let currentMatch: TBAMatch | undefined = undefined;
Expand Down Expand Up @@ -37,5 +38,5 @@ const domain = 'http://localhost:3000';
<Page {active} {domain} title="Pre"><Pre {event} {currentMatch}></Pre></Page>
<Page {active} {domain} title="App"><AppView {app}></AppView></Page>
<Page {active} {domain} title="Post"><Post {app} {active}></Post></Page>
<Page {active} {domain} title="Upload"></Page>
<Page {active} {domain} title="Upload"><Upload /></Page>
</main>
Loading

0 comments on commit b085fdb

Please sign in to comment.