Redone design
Fixed keyboar on web
This commit is contained in:
parent
c008e89412
commit
2707d80723
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,5 +1,5 @@
|
||||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
addons/
|
||||
build/
|
||||
*.tmp
|
||||
*.tmp
|
||||
Talkpal.apk*
|
@ -1,36 +0,0 @@
|
||||
# Attribution
|
||||
## Collaborators
|
||||
|
||||
### Role
|
||||
Person 1
|
||||
Person 2
|
||||
[Person w/ Link]()
|
||||
|
||||
|
||||
## Sourced / Unaffiliated
|
||||
### Asset Type
|
||||
#### Use Case
|
||||
Author: [Name]()
|
||||
Source: [Domain : webpage.html]()
|
||||
License: [License]()
|
||||
|
||||
#### Godot Engine Logo
|
||||
Author: Andrea Calabró
|
||||
Source: [godotengine.org : press](https://godotengine.org/press/)
|
||||
License: [CC BY 4.0 International](https://github.com/godotengine/godot/blob/master/LOGO_LICENSE.txt)
|
||||
|
||||
## Tools
|
||||
#### Godot
|
||||
Author: [Juan Linietsky, Ariel Manzur, and contributors](https://godotengine.org/contact)
|
||||
Source: [godotengine.org](https://godotengine.org/)
|
||||
License: [MIT License](https://github.com/godotengine/godot/blob/master/LICENSE.txt)
|
||||
|
||||
#### Git
|
||||
Author: [Linus Torvalds](https://github.com/torvalds)
|
||||
Source: [git-scm.com](https://git-scm.com/downloads)
|
||||
License: [GNU General Public License version 2](https://opensource.org/licenses/GPL-2.0)
|
||||
|
||||
#### Godot Menus Template
|
||||
Author: [Marek Belski](https://github.com/Maaack/Godot-Menus-Template/graphs/contributors)
|
||||
Source: [github: Godot-Menus-Template](https://github.com/Maaack/Godot-Menus-Template)
|
||||
License: [MIT License](LICENSE.txt)
|
4
assets/themes/edit_label_font.tres
Normal file
4
assets/themes/edit_label_font.tres
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_resource type="Theme" format=3 uid="uid://bbboqrxd230bp"]
|
||||
|
||||
[resource]
|
||||
default_font_size = 42
|
4
assets/themes/errror.tres
Normal file
4
assets/themes/errror.tres
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_resource type="Theme" format=3 uid="uid://c66wo0qg82ssk"]
|
||||
|
||||
[resource]
|
||||
default_font_size = 60
|
BIN
build/Talkpal.144x144.png
Normal file
BIN
build/Talkpal.144x144.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
34
build/Talkpal.144x144.png.import
Normal file
34
build/Talkpal.144x144.png.import
Normal file
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dq3g3dgxcmfqm"
|
||||
path="res://.godot/imported/Talkpal.144x144.png-9746dc3f6ae3502391455f6dcf0427f2.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://build/Talkpal.144x144.png"
|
||||
dest_files=["res://.godot/imported/Talkpal.144x144.png-9746dc3f6ae3502391455f6dcf0427f2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
BIN
build/Talkpal.180x180.png
Normal file
BIN
build/Talkpal.180x180.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
34
build/Talkpal.180x180.png.import
Normal file
34
build/Talkpal.180x180.png.import
Normal file
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c7rrqhmvltgo7"
|
||||
path="res://.godot/imported/Talkpal.180x180.png-543499b9301010cae1b5a8aa15a43453.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://build/Talkpal.180x180.png"
|
||||
dest_files=["res://.godot/imported/Talkpal.180x180.png-543499b9301010cae1b5a8aa15a43453.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
BIN
build/Talkpal.512x512.png
Normal file
BIN
build/Talkpal.512x512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
34
build/Talkpal.512x512.png.import
Normal file
34
build/Talkpal.512x512.png.import
Normal file
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cpi8avt0lny03"
|
||||
path="res://.godot/imported/Talkpal.512x512.png-5f61f4bc15dc82ee2bceb9e0c65e6d42.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://build/Talkpal.512x512.png"
|
||||
dest_files=["res://.godot/imported/Talkpal.512x512.png-5f61f4bc15dc82ee2bceb9e0c65e6d42.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
BIN
build/Talkpal.apple-touch-icon.png
Normal file
BIN
build/Talkpal.apple-touch-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
34
build/Talkpal.apple-touch-icon.png.import
Normal file
34
build/Talkpal.apple-touch-icon.png.import
Normal file
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://clefkbuu8dy15"
|
||||
path="res://.godot/imported/Talkpal.apple-touch-icon.png-16693661a1927dfe41ba57e49aadb965.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://build/Talkpal.apple-touch-icon.png"
|
||||
dest_files=["res://.godot/imported/Talkpal.apple-touch-icon.png-16693661a1927dfe41ba57e49aadb965.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
213
build/Talkpal.audio.worklet.js
Normal file
213
build/Talkpal.audio.worklet.js
Normal file
@ -0,0 +1,213 @@
|
||||
/**************************************************************************/
|
||||
/* audio.worklet.js */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
class RingBuffer {
|
||||
constructor(p_buffer, p_state, p_threads) {
|
||||
this.buffer = p_buffer;
|
||||
this.avail = p_state;
|
||||
this.threads = p_threads;
|
||||
this.rpos = 0;
|
||||
this.wpos = 0;
|
||||
}
|
||||
|
||||
data_left() {
|
||||
return this.threads ? Atomics.load(this.avail, 0) : this.avail;
|
||||
}
|
||||
|
||||
space_left() {
|
||||
return this.buffer.length - this.data_left();
|
||||
}
|
||||
|
||||
read(output) {
|
||||
const size = this.buffer.length;
|
||||
let from = 0;
|
||||
let to_write = output.length;
|
||||
if (this.rpos + to_write > size) {
|
||||
const high = size - this.rpos;
|
||||
output.set(this.buffer.subarray(this.rpos, size));
|
||||
from = high;
|
||||
to_write -= high;
|
||||
this.rpos = 0;
|
||||
}
|
||||
if (to_write) {
|
||||
output.set(this.buffer.subarray(this.rpos, this.rpos + to_write), from);
|
||||
}
|
||||
this.rpos += to_write;
|
||||
if (this.threads) {
|
||||
Atomics.add(this.avail, 0, -output.length);
|
||||
Atomics.notify(this.avail, 0);
|
||||
} else {
|
||||
this.avail -= output.length;
|
||||
}
|
||||
}
|
||||
|
||||
write(p_buffer) {
|
||||
const to_write = p_buffer.length;
|
||||
const mw = this.buffer.length - this.wpos;
|
||||
if (mw >= to_write) {
|
||||
this.buffer.set(p_buffer, this.wpos);
|
||||
this.wpos += to_write;
|
||||
if (mw === to_write) {
|
||||
this.wpos = 0;
|
||||
}
|
||||
} else {
|
||||
const high = p_buffer.subarray(0, mw);
|
||||
const low = p_buffer.subarray(mw);
|
||||
this.buffer.set(high, this.wpos);
|
||||
this.buffer.set(low);
|
||||
this.wpos = low.length;
|
||||
}
|
||||
if (this.threads) {
|
||||
Atomics.add(this.avail, 0, to_write);
|
||||
Atomics.notify(this.avail, 0);
|
||||
} else {
|
||||
this.avail += to_write;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GodotProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
this.threads = false;
|
||||
this.running = true;
|
||||
this.lock = null;
|
||||
this.notifier = null;
|
||||
this.output = null;
|
||||
this.output_buffer = new Float32Array();
|
||||
this.input = null;
|
||||
this.input_buffer = new Float32Array();
|
||||
this.port.onmessage = (event) => {
|
||||
const cmd = event.data['cmd'];
|
||||
const data = event.data['data'];
|
||||
this.parse_message(cmd, data);
|
||||
};
|
||||
}
|
||||
|
||||
process_notify() {
|
||||
if (this.notifier) {
|
||||
Atomics.add(this.notifier, 0, 1);
|
||||
Atomics.notify(this.notifier, 0);
|
||||
}
|
||||
}
|
||||
|
||||
parse_message(p_cmd, p_data) {
|
||||
if (p_cmd === 'start' && p_data) {
|
||||
const state = p_data[0];
|
||||
let idx = 0;
|
||||
this.threads = true;
|
||||
this.lock = state.subarray(idx, ++idx);
|
||||
this.notifier = state.subarray(idx, ++idx);
|
||||
const avail_in = state.subarray(idx, ++idx);
|
||||
const avail_out = state.subarray(idx, ++idx);
|
||||
this.input = new RingBuffer(p_data[1], avail_in, true);
|
||||
this.output = new RingBuffer(p_data[2], avail_out, true);
|
||||
} else if (p_cmd === 'stop') {
|
||||
this.running = false;
|
||||
this.output = null;
|
||||
this.input = null;
|
||||
this.lock = null;
|
||||
this.notifier = null;
|
||||
} else if (p_cmd === 'start_nothreads') {
|
||||
this.output = new RingBuffer(p_data[0], p_data[0].length, false);
|
||||
} else if (p_cmd === 'chunk') {
|
||||
this.output.write(p_data);
|
||||
}
|
||||
}
|
||||
|
||||
static array_has_data(arr) {
|
||||
return arr.length && arr[0].length && arr[0][0].length;
|
||||
}
|
||||
|
||||
process(inputs, outputs, parameters) {
|
||||
if (!this.running) {
|
||||
return false; // Stop processing.
|
||||
}
|
||||
if (this.output === null) {
|
||||
return true; // Not ready yet, keep processing.
|
||||
}
|
||||
const process_input = GodotProcessor.array_has_data(inputs);
|
||||
if (process_input) {
|
||||
const input = inputs[0];
|
||||
const chunk = input[0].length * input.length;
|
||||
if (this.input_buffer.length !== chunk) {
|
||||
this.input_buffer = new Float32Array(chunk);
|
||||
}
|
||||
if (!this.threads) {
|
||||
GodotProcessor.write_input(this.input_buffer, input);
|
||||
this.port.postMessage({ 'cmd': 'input', 'data': this.input_buffer });
|
||||
} else if (this.input.space_left() >= chunk) {
|
||||
GodotProcessor.write_input(this.input_buffer, input);
|
||||
this.input.write(this.input_buffer);
|
||||
} else {
|
||||
// this.port.postMessage('Input buffer is full! Skipping input frame.'); // Uncomment this line to debug input buffer.
|
||||
}
|
||||
}
|
||||
const process_output = GodotProcessor.array_has_data(outputs);
|
||||
if (process_output) {
|
||||
const output = outputs[0];
|
||||
const chunk = output[0].length * output.length;
|
||||
if (this.output_buffer.length !== chunk) {
|
||||
this.output_buffer = new Float32Array(chunk);
|
||||
}
|
||||
if (this.output.data_left() >= chunk) {
|
||||
this.output.read(this.output_buffer);
|
||||
GodotProcessor.write_output(output, this.output_buffer);
|
||||
if (!this.threads) {
|
||||
this.port.postMessage({ 'cmd': 'read', 'data': chunk });
|
||||
}
|
||||
} else {
|
||||
// this.port.postMessage('Output buffer has not enough frames! Skipping output frame.'); // Uncomment this line to debug output buffer.
|
||||
}
|
||||
}
|
||||
this.process_notify();
|
||||
return true;
|
||||
}
|
||||
|
||||
static write_output(dest, source) {
|
||||
const channels = dest.length;
|
||||
for (let ch = 0; ch < channels; ch++) {
|
||||
for (let sample = 0; sample < dest[ch].length; sample++) {
|
||||
dest[ch][sample] = source[sample * channels + ch];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static write_input(dest, source) {
|
||||
const channels = source.length;
|
||||
for (let ch = 0; ch < channels; ch++) {
|
||||
for (let sample = 0; sample < source[ch].length; sample++) {
|
||||
dest[sample * channels + ch] = source[ch][sample];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('godot-processor', GodotProcessor);
|
200
build/Talkpal.html
Normal file
200
build/Talkpal.html
Normal file
@ -0,0 +1,200 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
|
||||
<title>Talkpal</title>
|
||||
<style>
|
||||
html, body, #canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
color: white;
|
||||
background-color: black;
|
||||
overflow: hidden;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#canvas:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#status, #status-splash, #status-progress {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#status, #status-splash {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#status {
|
||||
background-color: #242424;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#status-splash {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#status-progress, #status-notice {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#status-progress {
|
||||
bottom: 10%;
|
||||
width: 50%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#status-notice {
|
||||
background-color: #5b3943;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid #9b3943;
|
||||
color: #e0e0e0;
|
||||
font-family: 'Noto Sans', 'Droid Sans', Arial, sans-serif;
|
||||
line-height: 1.3;
|
||||
margin: 0 2rem;
|
||||
overflow: hidden;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
<link id="-gd-engine-icon" rel="icon" type="image/png" href="Talkpal.icon.png" />
|
||||
<link rel="apple-touch-icon" href="Talkpal.apple-touch-icon.png"/>
|
||||
<link rel="manifest" href="Talkpal.manifest.json">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas">
|
||||
Your browser does not support the canvas tag.
|
||||
</canvas>
|
||||
|
||||
<noscript>
|
||||
Your browser does not support JavaScript.
|
||||
</noscript>
|
||||
|
||||
<div id="status">
|
||||
<img id="status-splash" src="Talkpal.png" alt="">
|
||||
<progress id="status-progress"></progress>
|
||||
<div id="status-notice"></div>
|
||||
</div>
|
||||
|
||||
<script src="Talkpal.js"></script>
|
||||
<script>
|
||||
const GODOT_CONFIG = {"args":[],"canvasResizePolicy":2,"ensureCrossOriginIsolationHeaders":true,"executable":"Talkpal","experimentalVK":true,"fileSizes":{"Talkpal.pck":6372256,"Talkpal.wasm":43016933},"focusCanvas":true,"gdextensionLibs":[],"serviceWorker":"Talkpal.service.worker.js"};
|
||||
const GODOT_THREADS_ENABLED = false;
|
||||
const engine = new Engine(GODOT_CONFIG);
|
||||
|
||||
(function () {
|
||||
const statusOverlay = document.getElementById('status');
|
||||
const statusProgress = document.getElementById('status-progress');
|
||||
const statusNotice = document.getElementById('status-notice');
|
||||
|
||||
let initializing = true;
|
||||
let statusMode = '';
|
||||
|
||||
function setStatusMode(mode) {
|
||||
if (statusMode === mode || !initializing) {
|
||||
return;
|
||||
}
|
||||
if (mode === 'hidden') {
|
||||
statusOverlay.remove();
|
||||
initializing = false;
|
||||
return;
|
||||
}
|
||||
statusOverlay.style.visibility = 'visible';
|
||||
statusProgress.style.display = mode === 'progress' ? 'block' : 'none';
|
||||
statusNotice.style.display = mode === 'notice' ? 'block' : 'none';
|
||||
statusMode = mode;
|
||||
}
|
||||
|
||||
function setStatusNotice(text) {
|
||||
while (statusNotice.lastChild) {
|
||||
statusNotice.removeChild(statusNotice.lastChild);
|
||||
}
|
||||
const lines = text.split('\n');
|
||||
lines.forEach((line) => {
|
||||
statusNotice.appendChild(document.createTextNode(line));
|
||||
statusNotice.appendChild(document.createElement('br'));
|
||||
});
|
||||
}
|
||||
|
||||
function displayFailureNotice(err) {
|
||||
console.error(err);
|
||||
if (err instanceof Error) {
|
||||
setStatusNotice(err.message);
|
||||
} else if (typeof err === 'string') {
|
||||
setStatusNotice(err);
|
||||
} else {
|
||||
setStatusNotice('An unknown error occured');
|
||||
}
|
||||
setStatusMode('notice');
|
||||
initializing = false;
|
||||
}
|
||||
|
||||
const missing = Engine.getMissingFeatures({
|
||||
threads: GODOT_THREADS_ENABLED,
|
||||
});
|
||||
|
||||
if (missing.length !== 0) {
|
||||
if (GODOT_CONFIG['serviceWorker'] && GODOT_CONFIG['ensureCrossOriginIsolationHeaders'] && 'serviceWorker' in navigator) {
|
||||
// There's a chance that installing the service worker would fix the issue
|
||||
Promise.race([
|
||||
navigator.serviceWorker.getRegistration().then((registration) => {
|
||||
if (registration != null) {
|
||||
return Promise.reject(new Error('Service worker already exists.'));
|
||||
}
|
||||
return registration;
|
||||
}).then(() => engine.installServiceWorker()),
|
||||
// For some reason, `getRegistration()` can stall
|
||||
new Promise((resolve) => {
|
||||
setTimeout(() => resolve(), 2000);
|
||||
}),
|
||||
]).catch((err) => {
|
||||
console.error('Error while registering service worker:', err);
|
||||
}).then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
} else {
|
||||
// Display the message as usual
|
||||
const missingMsg = 'Error\nThe following features required to run Godot projects on the Web are missing:\n';
|
||||
displayFailureNotice(missingMsg + missing.join('\n'));
|
||||
}
|
||||
} else {
|
||||
setStatusMode('progress');
|
||||
engine.startGame({
|
||||
'onProgress': function (current, total) {
|
||||
if (current > 0 && total > 0) {
|
||||
statusProgress.value = current;
|
||||
statusProgress.max = total;
|
||||
} else {
|
||||
statusProgress.removeAttribute('value');
|
||||
statusProgress.removeAttribute('max');
|
||||
}
|
||||
},
|
||||
}).then(() => {
|
||||
setStatusMode('hidden');
|
||||
}, displayFailureNotice);
|
||||
}
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
BIN
build/Talkpal.icon.png
Normal file
BIN
build/Talkpal.icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
34
build/Talkpal.icon.png.import
Normal file
34
build/Talkpal.icon.png.import
Normal file
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cv3qgijbr0ixb"
|
||||
path="res://.godot/imported/Talkpal.icon.png-2e39fac812df96c3f4fa6298212d67c1.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://build/Talkpal.icon.png"
|
||||
dest_files=["res://.godot/imported/Talkpal.icon.png-2e39fac812df96c3f4fa6298212d67c1.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
905
build/Talkpal.js
Normal file
905
build/Talkpal.js
Normal file
File diff suppressed because one or more lines are too long
1
build/Talkpal.manifest.json
Normal file
1
build/Talkpal.manifest.json
Normal file
@ -0,0 +1 @@
|
||||
{"background_color":"#000000","display":"standalone","icons":[{"sizes":"144x144","src":"Talkpal.144x144.png","type":"image/png"},{"sizes":"180x180","src":"Talkpal.180x180.png","type":"image/png"},{"sizes":"512x512","src":"Talkpal.512x512.png","type":"image/png"}],"name":"Talkpal","orientation":"any","start_url":"./Talkpal.html"}
|
41
build/Talkpal.offline.html
Normal file
41
build/Talkpal.offline.html
Normal file
@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>You are offline</title>
|
||||
<style>
|
||||
html {
|
||||
background-color: #000000;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
margin: 2rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-block: 1rem;
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
padding: 1rem 2rem;
|
||||
margin: 3rem auto 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>You are offline</h1>
|
||||
<p>This application requires an Internet connection to run for the first time.</p>
|
||||
<p>Press the button below to try reloading:</p>
|
||||
<button type="button">Reload</button>
|
||||
<script>
|
||||
document.querySelector('button').addEventListener('click', () => {
|
||||
window.location.reload();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
BIN
build/Talkpal.pck
Normal file
BIN
build/Talkpal.pck
Normal file
Binary file not shown.
BIN
build/Talkpal.png
Normal file
BIN
build/Talkpal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
34
build/Talkpal.png.import
Normal file
34
build/Talkpal.png.import
Normal file
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cbp1jcxnlheub"
|
||||
path="res://.godot/imported/Talkpal.png-93a93329b7f18a5c427549562ff04a5f.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://build/Talkpal.png"
|
||||
dest_files=["res://.godot/imported/Talkpal.png-93a93329b7f18a5c427549562ff04a5f.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
166
build/Talkpal.service.worker.js
Normal file
166
build/Talkpal.service.worker.js
Normal file
@ -0,0 +1,166 @@
|
||||
// This service worker is required to expose an exported Godot project as a
|
||||
// Progressive Web App. It provides an offline fallback page telling the user
|
||||
// that they need an Internet connection to run the project if desired.
|
||||
// Incrementing CACHE_VERSION will kick off the install event and force
|
||||
// previously cached resources to be updated from the network.
|
||||
/** @type {string} */
|
||||
const CACHE_VERSION = '1741733523|6678384895';
|
||||
/** @type {string} */
|
||||
const CACHE_PREFIX = 'Talkpal-sw-cache-';
|
||||
const CACHE_NAME = CACHE_PREFIX + CACHE_VERSION;
|
||||
/** @type {string} */
|
||||
const OFFLINE_URL = 'Talkpal.offline.html';
|
||||
/** @type {boolean} */
|
||||
const ENSURE_CROSSORIGIN_ISOLATION_HEADERS = true;
|
||||
// Files that will be cached on load.
|
||||
/** @type {string[]} */
|
||||
const CACHED_FILES = ["Talkpal.html","Talkpal.js","Talkpal.offline.html","Talkpal.icon.png","Talkpal.apple-touch-icon.png","Talkpal.worker.js","Talkpal.audio.worklet.js"];
|
||||
// Files that we might not want the user to preload, and will only be cached on first load.
|
||||
/** @type {string[]} */
|
||||
const CACHABLE_FILES = ["Talkpal.wasm","Talkpal.pck"];
|
||||
const FULL_CACHE = CACHED_FILES.concat(CACHABLE_FILES);
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(caches.open(CACHE_NAME).then((cache) => cache.addAll(CACHED_FILES)));
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(caches.keys().then(
|
||||
function (keys) {
|
||||
// Remove old caches.
|
||||
return Promise.all(keys.filter((key) => key.startsWith(CACHE_PREFIX) && key !== CACHE_NAME).map((key) => caches.delete(key)));
|
||||
}
|
||||
).then(function () {
|
||||
// Enable navigation preload if available.
|
||||
return ('navigationPreload' in self.registration) ? self.registration.navigationPreload.enable() : Promise.resolve();
|
||||
}));
|
||||
});
|
||||
|
||||
/**
|
||||
* Ensures that the response has the correct COEP/COOP headers
|
||||
* @param {Response} response
|
||||
* @returns {Response}
|
||||
*/
|
||||
function ensureCrossOriginIsolationHeaders(response) {
|
||||
if (response.headers.get('Cross-Origin-Embedder-Policy') === 'require-corp'
|
||||
&& response.headers.get('Cross-Origin-Opener-Policy') === 'same-origin') {
|
||||
return response;
|
||||
}
|
||||
|
||||
const crossOriginIsolatedHeaders = new Headers(response.headers);
|
||||
crossOriginIsolatedHeaders.set('Cross-Origin-Embedder-Policy', 'require-corp');
|
||||
crossOriginIsolatedHeaders.set('Cross-Origin-Opener-Policy', 'same-origin');
|
||||
const newResponse = new Response(response.body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: crossOriginIsolatedHeaders,
|
||||
});
|
||||
|
||||
return newResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls fetch and cache the result if it is cacheable
|
||||
* @param {FetchEvent} event
|
||||
* @param {Cache} cache
|
||||
* @param {boolean} isCacheable
|
||||
* @returns {Response}
|
||||
*/
|
||||
async function fetchAndCache(event, cache, isCacheable) {
|
||||
// Use the preloaded response, if it's there
|
||||
/** @type { Response } */
|
||||
let response = await event.preloadResponse;
|
||||
if (response == null) {
|
||||
// Or, go over network.
|
||||
response = await self.fetch(event.request);
|
||||
}
|
||||
|
||||
if (ENSURE_CROSSORIGIN_ISOLATION_HEADERS) {
|
||||
response = ensureCrossOriginIsolationHeaders(response);
|
||||
}
|
||||
|
||||
if (isCacheable) {
|
||||
// And update the cache
|
||||
cache.put(event.request, response.clone());
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
self.addEventListener(
|
||||
'fetch',
|
||||
/**
|
||||
* Triggered on fetch
|
||||
* @param {FetchEvent} event
|
||||
*/
|
||||
(event) => {
|
||||
const isNavigate = event.request.mode === 'navigate';
|
||||
const url = event.request.url || '';
|
||||
const referrer = event.request.referrer || '';
|
||||
const base = referrer.slice(0, referrer.lastIndexOf('/') + 1);
|
||||
const local = url.startsWith(base) ? url.replace(base, '') : '';
|
||||
const isCachable = FULL_CACHE.some((v) => v === local) || (base === referrer && base.endsWith(CACHED_FILES[0]));
|
||||
if (isNavigate || isCachable) {
|
||||
event.respondWith((async () => {
|
||||
// Try to use cache first
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
if (isNavigate) {
|
||||
// Check if we have full cache during HTML page request.
|
||||
/** @type {Response[]} */
|
||||
const fullCache = await Promise.all(FULL_CACHE.map((name) => cache.match(name)));
|
||||
const missing = fullCache.some((v) => v === undefined);
|
||||
if (missing) {
|
||||
try {
|
||||
// Try network if some cached file is missing (so we can display offline page in case).
|
||||
const response = await fetchAndCache(event, cache, isCachable);
|
||||
return response;
|
||||
} catch (e) {
|
||||
// And return the hopefully always cached offline page in case of network failure.
|
||||
console.error('Network error: ', e); // eslint-disable-line no-console
|
||||
return caches.match(OFFLINE_URL);
|
||||
}
|
||||
}
|
||||
}
|
||||
let cached = await cache.match(event.request);
|
||||
if (cached != null) {
|
||||
if (ENSURE_CROSSORIGIN_ISOLATION_HEADERS) {
|
||||
cached = ensureCrossOriginIsolationHeaders(cached);
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
// Try network if don't have it in cache.
|
||||
const response = await fetchAndCache(event, cache, isCachable);
|
||||
return response;
|
||||
})());
|
||||
} else if (ENSURE_CROSSORIGIN_ISOLATION_HEADERS) {
|
||||
event.respondWith((async () => {
|
||||
let response = await fetch(event.request);
|
||||
response = ensureCrossOriginIsolationHeaders(response);
|
||||
return response;
|
||||
})());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
// No cross origin
|
||||
if (event.origin !== self.origin) {
|
||||
return;
|
||||
}
|
||||
const id = event.source.id || '';
|
||||
const msg = event.data || '';
|
||||
// Ensure it's one of our clients.
|
||||
self.clients.get(id).then(function (client) {
|
||||
if (!client) {
|
||||
return; // Not a valid client.
|
||||
}
|
||||
if (msg === 'claim') {
|
||||
self.skipWaiting().then(() => self.clients.claim());
|
||||
} else if (msg === 'clear') {
|
||||
caches.delete(CACHE_NAME);
|
||||
} else if (msg === 'update') {
|
||||
self.skipWaiting().then(() => self.clients.claim()).then(() => self.clients.matchAll()).then((all) => all.forEach((c) => c.navigate(c.url)));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
BIN
build/Talkpal.wasm
Normal file
BIN
build/Talkpal.wasm
Normal file
Binary file not shown.
161
build/Talkpal.worker.js
Normal file
161
build/Talkpal.worker.js
Normal file
@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2015 The Emscripten Authors
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
// Pthread Web Worker startup routine:
|
||||
// This is the entry point file that is loaded first by each Web Worker
|
||||
// that executes pthreads on the Emscripten application.
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {};
|
||||
|
||||
// Thread-local guard variable for one-time init of the JS state
|
||||
var initializedJS = false;
|
||||
|
||||
function assert(condition, text) {
|
||||
if (!condition) abort('Assertion failed: ' + text);
|
||||
}
|
||||
|
||||
function threadPrintErr() {
|
||||
var text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.error(text);
|
||||
}
|
||||
function threadAlert() {
|
||||
var text = Array.prototype.slice.call(arguments).join(' ');
|
||||
postMessage({cmd: 'alert', text: text, threadId: Module['_pthread_self']()});
|
||||
}
|
||||
// We don't need out() for now, but may need to add it if we want to use it
|
||||
// here. Or, if this code all moves into the main JS, that problem will go
|
||||
// away. (For now, adding it here increases code size for no benefit.)
|
||||
var out = () => { throw 'out() is not defined in worker.js.'; }
|
||||
var err = threadPrintErr;
|
||||
self.alert = threadAlert;
|
||||
|
||||
Module['instantiateWasm'] = (info, receiveInstance) => {
|
||||
// Instantiate from the module posted from the main thread.
|
||||
// We can just use sync instantiation in the worker.
|
||||
var module = Module['wasmModule'];
|
||||
// We don't need the module anymore; new threads will be spawned from the main thread.
|
||||
Module['wasmModule'] = null;
|
||||
var instance = new WebAssembly.Instance(module, info);
|
||||
// TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193,
|
||||
// the above line no longer optimizes out down to the following line.
|
||||
// When the regression is fixed, we can remove this if/else.
|
||||
return receiveInstance(instance);
|
||||
}
|
||||
|
||||
// Turn unhandled rejected promises into errors so that the main thread will be
|
||||
// notified about them.
|
||||
self.onunhandledrejection = (e) => {
|
||||
throw e.reason ?? e;
|
||||
};
|
||||
|
||||
function handleMessage(e) {
|
||||
try {
|
||||
if (e.data.cmd === 'load') { // Preload command that is called once per worker to parse and load the Emscripten code.
|
||||
|
||||
// Until we initialize the runtime, queue up any further incoming messages.
|
||||
let messageQueue = [];
|
||||
self.onmessage = (e) => messageQueue.push(e);
|
||||
|
||||
// And add a callback for when the runtime is initialized.
|
||||
self.startWorker = (instance) => {
|
||||
Module = instance;
|
||||
// Notify the main thread that this thread has loaded.
|
||||
postMessage({ 'cmd': 'loaded' });
|
||||
// Process any messages that were queued before the thread was ready.
|
||||
for (let msg of messageQueue) {
|
||||
handleMessage(msg);
|
||||
}
|
||||
// Restore the real message handler.
|
||||
self.onmessage = handleMessage;
|
||||
};
|
||||
|
||||
// Module and memory were sent from main thread
|
||||
Module['wasmModule'] = e.data.wasmModule;
|
||||
|
||||
// Use `const` here to ensure that the variable is scoped only to
|
||||
// that iteration, allowing safe reference from a closure.
|
||||
for (const handler of e.data.handlers) {
|
||||
Module[handler] = function() {
|
||||
postMessage({ cmd: 'callHandler', handler, args: [...arguments] });
|
||||
}
|
||||
}
|
||||
|
||||
Module['wasmMemory'] = e.data.wasmMemory;
|
||||
|
||||
Module['buffer'] = Module['wasmMemory'].buffer;
|
||||
|
||||
Module['workerID'] = e.data.workerID;
|
||||
|
||||
Module['ENVIRONMENT_IS_PTHREAD'] = true;
|
||||
|
||||
if (typeof e.data.urlOrBlob == 'string') {
|
||||
importScripts(e.data.urlOrBlob);
|
||||
} else {
|
||||
var objectUrl = URL.createObjectURL(e.data.urlOrBlob);
|
||||
importScripts(objectUrl);
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
}
|
||||
Godot(Module);
|
||||
} else if (e.data.cmd === 'run') {
|
||||
// Pass the thread address to wasm to store it for fast access.
|
||||
Module['__emscripten_thread_init'](e.data.pthread_ptr, /*isMainBrowserThread=*/0, /*isMainRuntimeThread=*/0, /*canBlock=*/1);
|
||||
|
||||
// Await mailbox notifications with `Atomics.waitAsync` so we can start
|
||||
// using the fast `Atomics.notify` notification path.
|
||||
Module['__emscripten_thread_mailbox_await'](e.data.pthread_ptr);
|
||||
|
||||
assert(e.data.pthread_ptr);
|
||||
// Also call inside JS module to set up the stack frame for this pthread in JS module scope
|
||||
Module['establishStackSpace']();
|
||||
Module['PThread'].receiveObjectTransfer(e.data);
|
||||
Module['PThread'].threadInitTLS();
|
||||
|
||||
if (!initializedJS) {
|
||||
initializedJS = true;
|
||||
}
|
||||
|
||||
try {
|
||||
Module['invokeEntryPoint'](e.data.start_routine, e.data.arg);
|
||||
} catch(ex) {
|
||||
if (ex != 'unwind') {
|
||||
// The pthread "crashed". Do not call `_emscripten_thread_exit` (which
|
||||
// would make this thread joinable). Instead, re-throw the exception
|
||||
// and let the top level handler propagate it back to the main thread.
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
} else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread.
|
||||
if (Module['_pthread_self']()) {
|
||||
Module['__emscripten_thread_exit'](-1);
|
||||
}
|
||||
} else if (e.data.target === 'setimmediate') {
|
||||
// no-op
|
||||
} else if (e.data.cmd === 'checkMailbox') {
|
||||
if (initializedJS) {
|
||||
Module['checkMailbox']();
|
||||
}
|
||||
} else if (e.data.cmd) {
|
||||
// The received message looks like something that should be handled by this message
|
||||
// handler, (since there is a e.data.cmd field present), but is not one of the
|
||||
// recognized commands:
|
||||
err('worker.js received unknown command ' + e.data.cmd);
|
||||
err(e.data);
|
||||
}
|
||||
} catch(ex) {
|
||||
err('worker.js onmessage() captured an uncaught exception: ' + ex);
|
||||
if (ex && ex.stack) err(ex.stack);
|
||||
if (Module['__emscripten_thread_crashed']) {
|
||||
Module['__emscripten_thread_crashed']();
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
};
|
||||
|
||||
self.onmessage = handleMessage;
|
||||
|
||||
|
905
build/web/Talkpal.js
Normal file
905
build/web/Talkpal.js
Normal file
File diff suppressed because one or more lines are too long
908
build/web/Talkpal.js.old
Normal file
908
build/web/Talkpal.js.old
Normal file
File diff suppressed because one or more lines are too long
@ -63,7 +63,7 @@ permissions/access_coarse_location=false
|
||||
permissions/access_fine_location=false
|
||||
permissions/access_location_extra_commands=false
|
||||
permissions/access_mock_location=false
|
||||
permissions/access_network_state=false
|
||||
permissions/access_network_state=true
|
||||
permissions/access_surface_flinger=false
|
||||
permissions/access_wifi_state=false
|
||||
permissions/account_manager=false
|
||||
@ -124,7 +124,7 @@ permissions/install_location_provider=false
|
||||
permissions/install_packages=false
|
||||
permissions/install_shortcut=false
|
||||
permissions/internal_system_window=false
|
||||
permissions/internet=false
|
||||
permissions/internet=true
|
||||
permissions/kill_background_processes=false
|
||||
permissions/location_hardware=false
|
||||
permissions/manage_accounts=false
|
||||
@ -240,7 +240,7 @@ html/custom_html_shell=""
|
||||
html/head_include=""
|
||||
html/canvas_resize_policy=2
|
||||
html/focus_canvas_on_start=true
|
||||
html/experimental_virtual_keyboard=false
|
||||
html/experimental_virtual_keyboard=true
|
||||
progressive_web_app/enabled=true
|
||||
progressive_web_app/ensure_cross_origin_isolation_headers=true
|
||||
progressive_web_app/offline_page=""
|
||||
|
@ -40,7 +40,7 @@ project/assembly_name="Talkpal Frontend"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/maaacks_menus_template/plugin.cfg", "res://addons/uuid/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/maaacks_menus_template/plugin.cfg", "res://addons/onscreenkeyboard/plugin.cfg", "res://addons/uuid/plugin.cfg")
|
||||
|
||||
[internationalization]
|
||||
|
||||
|
@ -15,12 +15,14 @@ const DateUpdateInterval := 1.0
|
||||
@onready var _timeline = $Panel/Timeline
|
||||
@onready var _reservations = $Panel/Reservations
|
||||
@onready var _date = $TopBar/DateButton
|
||||
@onready var _room = $TopBar/RoomButton
|
||||
|
||||
var _date_update_timer = 0.0
|
||||
|
||||
func _process(delta):
|
||||
_process_hour_size()
|
||||
_process_date(delta)
|
||||
_process_fonts()
|
||||
|
||||
func _process_hour_size():
|
||||
var hour_size = get_viewport_rect().size.y/15
|
||||
@ -37,6 +39,16 @@ func _process_date(delta):
|
||||
var date = Time.get_date_dict_from_system()
|
||||
_date.text = "%02d.%02d.%04d" % [date.day, date.month, date.year]
|
||||
|
||||
func _process_fonts():
|
||||
_process_font_size(_date, 35)
|
||||
_process_font_size(_room, 35)
|
||||
|
||||
func _process_font_size(obj, k):
|
||||
var font_size = obj.get_theme_default_font_size()
|
||||
var new_font_size = get_viewport_rect().size.y/k
|
||||
if font_size != new_font_size:
|
||||
obj.add_theme_font_size_override("font_size", new_font_size)
|
||||
|
||||
func _ready():
|
||||
_connect_signals()
|
||||
|
||||
@ -44,7 +56,6 @@ func _ready():
|
||||
_remove_reservations()
|
||||
|
||||
_fill_with_slots()
|
||||
_update_schedule()
|
||||
|
||||
func _connect_signals():
|
||||
await _main.ready
|
||||
@ -94,6 +105,7 @@ func _compose_reservation(start_time, duration_time, title, color, id):
|
||||
|
||||
var reservation = ReservationScene.instantiate()
|
||||
_reservations.add_child(reservation)
|
||||
|
||||
reservation.set_start_time(start_time)
|
||||
reservation.set_duration_time(duration_time)
|
||||
reservation.set_title(title)
|
||||
@ -143,7 +155,9 @@ func _on_date_button_pressed():
|
||||
print("emit change date signal")
|
||||
|
||||
func _on_reservations_updated(reservations):
|
||||
await get_tree().create_timer(0.1, false).timeout
|
||||
update()
|
||||
|
||||
func update():
|
||||
_ready()
|
||||
_update_schedule()
|
||||
|
@ -14,18 +14,29 @@ grow_horizontal = 2
|
||||
theme_override_constants/separation = 25
|
||||
script = ExtResource("1_2wgc4")
|
||||
|
||||
[node name="TopBar" type="HBoxContainer" parent="."]
|
||||
[node name="TopBar" type="Control" parent="."]
|
||||
custom_minimum_size = Vector2(1150, 50)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
|
||||
[node name="RoomButton" type="Button" parent="TopBar"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
layout_mode = 1
|
||||
offset_right = 348.0
|
||||
offset_bottom = 72.0
|
||||
size_flags_horizontal = 0
|
||||
theme = ExtResource("1_na0ey")
|
||||
text = "Переговорка 1"
|
||||
|
||||
[node name="DateButton" type="Button" parent="TopBar"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 10
|
||||
layout_mode = 1
|
||||
anchors_preset = 1
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -380.0
|
||||
offset_bottom = 72.0
|
||||
grow_horizontal = 0
|
||||
size_flags_horizontal = 8
|
||||
theme = ExtResource("1_na0ey")
|
||||
text = "Вт, 14 июн. 2022"
|
||||
|
||||
@ -69,11 +80,11 @@ theme_override_colors/font_color = Color(0, 0, 0, 0)
|
||||
text = "11:00 "
|
||||
|
||||
[node name="Handler" type="ColorRect" parent="Panel/CurrentTime/HBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 5)
|
||||
custom_minimum_size = Vector2(0, 10)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 0
|
||||
color = Color(1, 1, 1, 0.556863)
|
||||
color = Color(1, 1, 0, 0.556863)
|
||||
|
||||
[node name="Reservations" type="Control" parent="Panel"]
|
||||
layout_mode = 2
|
||||
@ -86,3 +97,6 @@ grow_horizontal = 2
|
||||
[node name="Reservation" parent="Panel/Reservations" instance=ExtResource("4_o5rhy")]
|
||||
layout_mode = 2
|
||||
offset_right = 1036.0
|
||||
|
||||
[node name="Control" type="Control" parent="."]
|
||||
layout_mode = 2
|
||||
|
@ -64,6 +64,6 @@ func _on_section_panel_gui_input(event):
|
||||
print("emit open reservation info signal")
|
||||
|
||||
var repo = _main.get_reservation_repo()
|
||||
repo.set_current_reservation_id(_id)
|
||||
repo.set_selected_reservation_id(_id)
|
||||
|
||||
_main.load_page(Main.Pages.ReservationEdit, true)
|
||||
|
304
scenes/common/custom_line_edit.gd
Normal file
304
scenes/common/custom_line_edit.gd
Normal file
@ -0,0 +1,304 @@
|
||||
class_name CustomLineEdit
|
||||
extends Control
|
||||
|
||||
# Internal state
|
||||
var cursor_pos: int = 0
|
||||
var selection: Vector2i = Vector2i(-1, -1)
|
||||
var cursor_visible: bool = false
|
||||
var has_focus: bool = false
|
||||
|
||||
# Visual settings
|
||||
var cursor_color: Color = Color.BLACK
|
||||
|
||||
@export var text: String = "":
|
||||
set(v):
|
||||
text = v.left(max_length)
|
||||
cursor_pos = clamp(cursor_pos, 0, text.length())
|
||||
queue_redraw()
|
||||
|
||||
@export_multiline var placeholder: String = "":
|
||||
set(v):
|
||||
placeholder = v
|
||||
queue_redraw()
|
||||
|
||||
@export_enum("Left", "Center", "Right") var align: int = 0:
|
||||
set(v):
|
||||
align = v
|
||||
queue_redraw()
|
||||
|
||||
@export_range(0, 1024) var max_length: int = 256
|
||||
|
||||
@export var secret: bool = false:
|
||||
set(v):
|
||||
secret = v
|
||||
queue_redraw()
|
||||
|
||||
@export var secret_char: String = "*" :
|
||||
set(v):
|
||||
secret_char = v[0] if v.length() > 0 else "*"
|
||||
queue_redraw()
|
||||
|
||||
@export var editable: bool = true
|
||||
@export var context_menu_enabled: bool = true
|
||||
@export var clear_button_enabled: bool = false
|
||||
@export var shortcut_keys_enabled: bool = true
|
||||
@export var virtual_keyboard_enabled: bool = true
|
||||
@export var caret_blink: bool = true
|
||||
@export_range(0.1, 2.0) var caret_blink_interval: float = 0.5
|
||||
|
||||
@export var expand_to_text_length: bool = false
|
||||
@export var select_all_on_focus: bool = false
|
||||
|
||||
@export_group("Colors")
|
||||
@export var text_color: Color = Color.BLACK:
|
||||
set(v):
|
||||
text_color = v
|
||||
queue_redraw()
|
||||
|
||||
@export var placeholder_color: Color = Color.DIM_GRAY:
|
||||
set(v):
|
||||
placeholder_color = v
|
||||
queue_redraw()
|
||||
|
||||
@export var caret_color: Color = Color.BLACK:
|
||||
set(v):
|
||||
caret_color = v
|
||||
queue_redraw()
|
||||
|
||||
@export var selection_color: Color = Color(0.7, 0.8, 1.0, 0.5):
|
||||
set(v):
|
||||
selection_color = v
|
||||
queue_redraw()
|
||||
|
||||
@export_group("Font")
|
||||
@export var font: Font = ThemeDB.fallback_font:
|
||||
set(v):
|
||||
font = v
|
||||
queue_redraw()
|
||||
|
||||
@export_range(8, 64) var font_size: int = 16:
|
||||
set(v):
|
||||
font_size = v
|
||||
queue_redraw()
|
||||
|
||||
func _ready():
|
||||
focus_entered.connect(_on_focus_entered)
|
||||
focus_exited.connect(_on_focus_exited)
|
||||
set_process_input(true)
|
||||
start_blink_timer()
|
||||
|
||||
func _on_focus_entered():
|
||||
has_focus = true
|
||||
cursor_visible = true
|
||||
queue_redraw()
|
||||
|
||||
func _on_focus_exited():
|
||||
has_focus = false
|
||||
cursor_visible = false
|
||||
queue_redraw()
|
||||
|
||||
func start_blink_timer():
|
||||
var timer = Timer.new()
|
||||
add_child(timer)
|
||||
timer.wait_time = 0.5
|
||||
timer.timeout.connect(_toggle_cursor_visibility)
|
||||
timer.start()
|
||||
|
||||
func _toggle_cursor_visibility():
|
||||
if has_focus:
|
||||
cursor_visible = !cursor_visible
|
||||
queue_redraw()
|
||||
|
||||
func _gui_input(event):
|
||||
if event is InputEventKey and has_focus:
|
||||
handle_key_input(event)
|
||||
|
||||
if event is InputEventMouseButton and event.pressed:
|
||||
if get_rect().has_point(event.position) or true:
|
||||
grab_focus()
|
||||
handle_mouse_click(event)
|
||||
else:
|
||||
release_focus()
|
||||
|
||||
func handle_mouse_click(event: InputEventMouseButton):
|
||||
var click_pos = get_local_mouse_position().x
|
||||
var text_to_use = get_display_text()
|
||||
var offset = get_text_offset(text_to_use)
|
||||
|
||||
var pos = 0
|
||||
var accumulated_width = 0.0
|
||||
var found = false
|
||||
|
||||
for i in range(text_to_use.length()):
|
||||
var char_width = font.get_string_size(text_to_use.substr(i, 1), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x
|
||||
if accumulated_width + char_width/2 > click_pos - offset:
|
||||
pos = i
|
||||
found = true
|
||||
break
|
||||
accumulated_width += char_width
|
||||
|
||||
if not found:
|
||||
pos = text_to_use.length()
|
||||
|
||||
cursor_pos = pos
|
||||
selection = Vector2i(-1, -1)
|
||||
cursor_visible = true
|
||||
queue_redraw()
|
||||
|
||||
func handle_key_input(event: InputEventKey):
|
||||
var shift_pressed = event.shift_pressed
|
||||
var ctrl_pressed = event.ctrl_pressed
|
||||
|
||||
# Handle selection
|
||||
if shift_pressed and selection.x == -1:
|
||||
selection = Vector2i(cursor_pos, cursor_pos)
|
||||
|
||||
# Handle text input
|
||||
if event.unicode != 0 and !event.echo:
|
||||
insert_text_at_cursor(char(event.unicode))
|
||||
|
||||
# Handle special keys
|
||||
match event.keycode:
|
||||
KEY_BACKSPACE:
|
||||
delete_prev_char()
|
||||
KEY_DELETE:
|
||||
delete_next_char()
|
||||
KEY_LEFT:
|
||||
move_cursor(-1, ctrl_pressed, shift_pressed)
|
||||
KEY_RIGHT:
|
||||
move_cursor(1, ctrl_pressed, shift_pressed)
|
||||
KEY_HOME:
|
||||
cursor_pos = 0
|
||||
adjust_selection(shift_pressed)
|
||||
KEY_END:
|
||||
cursor_pos = text.length()
|
||||
adjust_selection(shift_pressed)
|
||||
KEY_C:
|
||||
if ctrl_pressed:
|
||||
copy_to_clipboard()
|
||||
KEY_V:
|
||||
if ctrl_pressed:
|
||||
paste_from_clipboard()
|
||||
|
||||
queue_redraw()
|
||||
|
||||
func insert_text_at_cursor(new_text: String):
|
||||
var new_text_filtered = new_text.replace("\n", "").replace("\t", "")
|
||||
if text.length() + new_text_filtered.length() > max_length:
|
||||
return
|
||||
|
||||
if selection.x != -1:
|
||||
delete_selection()
|
||||
|
||||
text = text.insert(cursor_pos, new_text_filtered)
|
||||
cursor_pos += new_text_filtered.length()
|
||||
selection = Vector2i(-1, -1)
|
||||
|
||||
func delete_prev_char():
|
||||
if cursor_pos > 0:
|
||||
if selection.x != -1:
|
||||
delete_selection()
|
||||
else:
|
||||
text = text.erase(cursor_pos - 1, 1)
|
||||
cursor_pos -= 1
|
||||
|
||||
func delete_next_char():
|
||||
if cursor_pos < text.length():
|
||||
if selection.x != -1:
|
||||
delete_selection()
|
||||
else:
|
||||
text = text.erase(cursor_pos, 1)
|
||||
|
||||
func delete_selection():
|
||||
var start = min(selection.x, selection.y)
|
||||
var end = max(selection.x, selection.y)
|
||||
text = text.erase(start, end - start)
|
||||
cursor_pos = start
|
||||
selection = Vector2i(-1, -1)
|
||||
|
||||
func move_cursor(direction: int, ctrl: bool, shift: bool):
|
||||
var new_pos = cursor_pos
|
||||
if ctrl:
|
||||
new_pos = find_word_boundary(direction)
|
||||
else:
|
||||
new_pos += direction
|
||||
|
||||
cursor_pos = clamp(new_pos, 0, text.length())
|
||||
adjust_selection(shift)
|
||||
|
||||
func adjust_selection(shift: bool):
|
||||
if shift:
|
||||
selection.y = cursor_pos
|
||||
else:
|
||||
selection = Vector2i(-1, -1)
|
||||
|
||||
func find_word_boundary(direction: int) -> int:
|
||||
# Simplified word navigation
|
||||
var pos = cursor_pos
|
||||
if direction == -1:
|
||||
while pos > 0 and text[pos-1] == " ":
|
||||
pos -= 1
|
||||
while pos > 0 and text[pos-1] != " ":
|
||||
pos -= 1
|
||||
else:
|
||||
while pos < text.length() and text[pos] == " ":
|
||||
pos += 1
|
||||
while pos < text.length() and text[pos] != " ":
|
||||
pos += 1
|
||||
return pos
|
||||
|
||||
func copy_to_clipboard():
|
||||
if selection.x != -1:
|
||||
var start = min(selection.x, selection.y)
|
||||
var end = max(selection.x, selection.y)
|
||||
DisplayServer.clipboard_set(text.substr(start, end - start))
|
||||
|
||||
func paste_from_clipboard():
|
||||
var clipboard = DisplayServer.clipboard_get()
|
||||
insert_text_at_cursor(clipboard)
|
||||
|
||||
func get_display_text() -> String:
|
||||
if secret and text.length() > 0:
|
||||
return secret_char.repeat(text.length())
|
||||
return text if text.length() > 0 else placeholder
|
||||
|
||||
func get_text_offset(display_text: String) -> float:
|
||||
var text_width = font.get_string_size(display_text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x
|
||||
match align:
|
||||
HorizontalAlignment.HORIZONTAL_ALIGNMENT_CENTER:
|
||||
return max(0, (size.x - text_width) / 2)
|
||||
HorizontalAlignment.HORIZONTAL_ALIGNMENT_RIGHT:
|
||||
return max(0, size.x - text_width)
|
||||
_: # Left align
|
||||
return 0.0
|
||||
|
||||
func _draw():
|
||||
var display_text = get_display_text()
|
||||
var text_offset = get_text_offset(display_text)
|
||||
|
||||
# Draw selection
|
||||
print(selection)
|
||||
if selection.x != -1:
|
||||
draw_selection(text_offset, display_text)
|
||||
|
||||
# Draw text
|
||||
var text_color = Color.DIM_GRAY if text == "" else Color.BLACK
|
||||
draw_string(font, Vector2(text_offset, size.y / 2 + font_size / 2), display_text,
|
||||
HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color)
|
||||
|
||||
# Draw cursor
|
||||
if cursor_visible and has_focus:
|
||||
draw_cursor(text_offset, display_text)
|
||||
|
||||
func draw_selection(offset: float, display_text: String):
|
||||
var start = min(selection.x, selection.y)
|
||||
var end = max(selection.x, selection.y)
|
||||
|
||||
var start_pos = offset + font.get_string_size(display_text.left(start), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x
|
||||
var end_pos = offset + font.get_string_size(display_text.left(end), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x
|
||||
|
||||
draw_rect(Rect2(start_pos, 2, end_pos - start_pos, size.y - 4), selection_color, true)
|
||||
|
||||
func draw_cursor(offset: float, display_text: String):
|
||||
var cursor_x = offset + font.get_string_size(display_text.left(cursor_pos), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x
|
||||
draw_line(Vector2(cursor_x, 2), Vector2(cursor_x, size.y - 2), cursor_color, 2.0)
|
44
scenes/common/dialog_box.tscn
Normal file
44
scenes/common/dialog_box.tscn
Normal file
@ -0,0 +1,44 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dt03kci5qbkg3"]
|
||||
|
||||
[ext_resource type="Theme" uid="uid://c66wo0qg82ssk" path="res://assets/themes/errror.tres" id="1_lxolw"]
|
||||
|
||||
[node name="DialogBox" type="VBoxContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Background" type="ColorRect" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
color = Color(0.172549, 0.172549, 0.172549, 0.658824)
|
||||
|
||||
[node name="Control" type="Control" parent="Background"]
|
||||
anchors_preset = 0
|
||||
offset_right = 40.0
|
||||
offset_bottom = 40.0
|
||||
|
||||
[node name="Box" type="ColorRect" parent="Background/Control"]
|
||||
layout_mode = 1
|
||||
offset_left = 133.0
|
||||
offset_top = 411.0
|
||||
offset_right = 133.0
|
||||
offset_bottom = 411.0
|
||||
color = Color(0, 0, 0, 0.572549)
|
||||
|
||||
[node name="Container" type="VBoxContainer" parent="Background/Control/Box"]
|
||||
layout_mode = 2
|
||||
offset_right = 934.0
|
||||
offset_bottom = 178.0
|
||||
theme_override_constants/separation = 50
|
||||
|
||||
[node name="Label" type="Label" parent="Background/Control/Box/Container"]
|
||||
layout_mode = 2
|
||||
theme = ExtResource("1_lxolw")
|
||||
text = "Это время уже забронировано"
|
||||
|
||||
[node name="Button" type="Button" parent="Background/Control/Box/Container"]
|
||||
layout_mode = 2
|
||||
theme = ExtResource("1_lxolw")
|
||||
text = "OK"
|
@ -23,14 +23,28 @@ enum Type {
|
||||
editable = value
|
||||
set_editable(value)
|
||||
|
||||
@onready var _label = $FieldLabelControl/FieldLabel
|
||||
@onready var _line = $Line
|
||||
@onready var _calendar = $Calendar
|
||||
@onready var _time = $Time
|
||||
@onready var _text = $Text
|
||||
@onready var _label = $Container/FieldLabelControl/FieldLabel
|
||||
@onready var _line = $Container/Value/Line
|
||||
@onready var _calendar = $Container/Value/Calendar
|
||||
@onready var _time = $Container/Value/Time
|
||||
@onready var _text = $Container/Value/Text
|
||||
|
||||
var _type
|
||||
|
||||
func _process(delta):
|
||||
_process_fonts()
|
||||
|
||||
func _process_fonts():
|
||||
_process_font_size(_label, 35)
|
||||
_process_font_size(_line, 35)
|
||||
_process_font_size(_text, 35)
|
||||
|
||||
func _process_font_size(obj, k):
|
||||
var font_size = obj.get_theme_default_font_size()
|
||||
var new_font_size = get_viewport_rect().size.y/k
|
||||
if font_size != new_font_size:
|
||||
obj.add_theme_font_size_override("font_size", new_font_size)
|
||||
|
||||
func _ready():
|
||||
set_title(title)
|
||||
set_type(type)
|
||||
|
@ -1,8 +1,8 @@
|
||||
[gd_scene load_steps=6 format=3 uid="uid://d0fdiesiaajlq"]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/common/edit_field.gd" id="1_sdy7t"]
|
||||
[ext_resource type="Theme" uid="uid://7lcget51crj1" path="res://assets/themes/medium.tres" id="2_haj3x"]
|
||||
[ext_resource type="Theme" uid="uid://cmhwbyqu6nh38" path="res://assets/themes/big.tres" id="2_iq8f3"]
|
||||
[ext_resource type="Theme" uid="uid://bbboqrxd230bp" path="res://assets/themes/edit_label_font.tres" id="3_4sp4y"]
|
||||
[ext_resource type="PackedScene" uid="uid://drdv8adk1wi8f" path="res://scenes/common/calendar/calendar_edit.tscn" id="4_hlx5p"]
|
||||
[ext_resource type="PackedScene" uid="uid://bhd0xvnvoqslr" path="res://scenes/common/time/time_edit.tscn" id="5_d0drs"]
|
||||
|
||||
@ -14,41 +14,55 @@ grow_horizontal = 2
|
||||
theme_override_constants/separation = 25
|
||||
script = ExtResource("1_sdy7t")
|
||||
|
||||
[node name="FieldLabelControl" type="Control" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="FieldLabel" type="Label" parent="FieldLabelControl"]
|
||||
layout_mode = 2
|
||||
offset_left = 25.0
|
||||
offset_top = 4.0
|
||||
offset_right = 231.0
|
||||
offset_bottom = 62.0
|
||||
theme = ExtResource("2_haj3x")
|
||||
|
||||
[node name="Indent" type="Label" parent="."]
|
||||
layout_mode = 2
|
||||
theme = ExtResource("2_iq8f3")
|
||||
text = " "
|
||||
text = " "
|
||||
|
||||
[node name="Line" type="LineEdit" parent="."]
|
||||
[node name="Container" type="VBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme = ExtResource("2_iq8f3")
|
||||
max_length = 32
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="Text" type="TextEdit" parent="."]
|
||||
[node name="FieldLabelControl" type="HBoxContainer" parent="Container"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Indent" type="Label" parent="Container/FieldLabelControl"]
|
||||
layout_mode = 2
|
||||
theme = ExtResource("2_iq8f3")
|
||||
text = " "
|
||||
|
||||
[node name="FieldLabel" type="Label" parent="Container/FieldLabelControl"]
|
||||
layout_mode = 2
|
||||
theme = ExtResource("3_4sp4y")
|
||||
theme_override_font_sizes/font_size = 16
|
||||
|
||||
[node name="Value" type="VBoxContainer" parent="Container"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Line" type="LineEdit" parent="Container/Value"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme = ExtResource("2_iq8f3")
|
||||
theme_override_font_sizes/font_size = 16
|
||||
max_length = 32
|
||||
selecting_enabled = false
|
||||
|
||||
[node name="Text" type="TextEdit" parent="Container/Value"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme = ExtResource("2_iq8f3")
|
||||
theme_override_font_sizes/font_size = 16
|
||||
wrap_mode = 1
|
||||
scroll_fit_content_height = true
|
||||
|
||||
[node name="Calendar" parent="." instance=ExtResource("4_hlx5p")]
|
||||
[node name="Calendar" parent="Container/Value" instance=ExtResource("4_hlx5p")]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Time" parent="." instance=ExtResource("5_d0drs")]
|
||||
[node name="Time" parent="Container/Value" instance=ExtResource("5_d0drs")]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
@ -12,6 +12,15 @@ var _hours := 0
|
||||
var _minutes := 0
|
||||
var _time_setting_page
|
||||
|
||||
func _process(delta):
|
||||
_process_font_size()
|
||||
|
||||
func _process_font_size():
|
||||
var font_size = _edit.get_theme_default_font_size()
|
||||
var new_font_size = get_viewport_rect().size.y/35
|
||||
if font_size != new_font_size:
|
||||
_edit.add_theme_font_size_override("font_size", new_font_size)
|
||||
|
||||
func _ready():
|
||||
initialize_signals()
|
||||
|
||||
|
@ -14,7 +14,7 @@ script = ExtResource("1_2wxyg")
|
||||
[node name="TimeEdit" type="LineEdit" parent="."]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "11:10 "
|
||||
text = "14:35 "
|
||||
placeholder_text = "hh:mm (a/p)m"
|
||||
script = ExtResource("2_7d4ae")
|
||||
current_time = true
|
||||
|
@ -9,6 +9,7 @@ const BgColors = {
|
||||
"temporarily_free": Color("3a2c00")
|
||||
}
|
||||
const MinutesForTemporarilyFree := 15
|
||||
const StatusCheckPeriod := 5.0
|
||||
|
||||
enum Status {
|
||||
FREE,
|
||||
@ -18,6 +19,7 @@ enum Status {
|
||||
@onready var _reservation_repo : AbstractReservationRepo = $Repos/Reservation
|
||||
@onready var _event_handler : EventHandler = $Repos/EventHandler
|
||||
@onready var _reservation_service : ReservationService = $Services/ReservationService
|
||||
@onready var _keyboard = $Keyboard/OnscreenKeyboard
|
||||
|
||||
@export var current_page : Pages:
|
||||
set(value):
|
||||
@ -33,6 +35,7 @@ enum Status {
|
||||
@onready var _time_status_indent := $Left/TimeStatusContainer/Indent
|
||||
@onready var _time_label := $Left/TimeStatusContainer/TimeLabel
|
||||
@onready var _status_label := $Left/TimeStatusContainer/StatusLabel
|
||||
@onready var _will_be_available_label := $Left/TimeStatusContainer/WillBeAvailableLabel
|
||||
@onready var _background := $Background
|
||||
|
||||
@onready var _create_reservation_button := $RightBottom/CreateReservationButton
|
||||
@ -44,6 +47,7 @@ enum Status {
|
||||
var _current_page := Pages.Board
|
||||
var _previous_page : Pages
|
||||
var _status : Status
|
||||
var _time_after_status_check := 0.0
|
||||
|
||||
func _ready():
|
||||
initialize_signals()
|
||||
@ -58,9 +62,13 @@ func initialize_signals():
|
||||
|
||||
func _process(delta):
|
||||
_process_time_status_indent()
|
||||
_process_status(delta)
|
||||
|
||||
var time = Time.get_time_dict_from_system()
|
||||
_process_time(time)
|
||||
_process_available_time(time)
|
||||
|
||||
_process_fonts()
|
||||
|
||||
func _process_time_status_indent():
|
||||
var indent = get_viewport_rect().size.y/3
|
||||
@ -70,6 +78,24 @@ func _process_time_status_indent():
|
||||
func _process_time(time):
|
||||
_time_label.text = "%02d:%02d" % [time.hour, time.minute]
|
||||
|
||||
func _process_available_time(time):
|
||||
var reservation = _reservation_repo.get_current_reservation()
|
||||
|
||||
if _status == Status.BUSY and reservation:
|
||||
var current_time_in_minutes = time.hour*60 + time.minute
|
||||
var reservation_minutes = reservation.finish_time.hours*60 + reservation.finish_time.minutes
|
||||
var result_minutes = reservation_minutes - current_time_in_minutes
|
||||
_will_be_available_label.text = "(осталось %s мин)" % str(result_minutes)
|
||||
else:
|
||||
_will_be_available_label.text = ""
|
||||
|
||||
func _process_status(delta):
|
||||
if _time_after_status_check >= StatusCheckPeriod:
|
||||
_time_after_status_check = 0.0
|
||||
_update_status()
|
||||
|
||||
_time_after_status_check += delta
|
||||
|
||||
func _update_status(reservations=null):
|
||||
var time = Time.get_time_dict_from_system()
|
||||
var current_time_in_minutes = time.hour*60 + time.minute
|
||||
@ -101,11 +127,20 @@ func _update_ui_status(status: Status, text: String, color: Color):
|
||||
_status_label.text = text
|
||||
_background.color = color
|
||||
|
||||
func _process_fonts():
|
||||
_process_font_size(_create_reservation_button, 35)
|
||||
|
||||
func _process_font_size(obj, k):
|
||||
var font_size = obj.get_theme_default_font_size()
|
||||
var new_font_size = get_viewport_rect().size.y/k
|
||||
if font_size != new_font_size:
|
||||
obj.add_theme_font_size_override("font_size", new_font_size)
|
||||
|
||||
func get_current_page():
|
||||
return _current_page
|
||||
|
||||
func load_page(value, with_update=true):
|
||||
_pages[_current_page].visible = false
|
||||
var previous_page = _current_page
|
||||
|
||||
if _previous_page != _current_page:
|
||||
if not _current_page == Pages.TimeSetting:
|
||||
@ -114,10 +149,24 @@ func load_page(value, with_update=true):
|
||||
_current_page = value
|
||||
if with_update:
|
||||
_pages[_current_page].update()
|
||||
_pages[_current_page].visible = true
|
||||
|
||||
hide_keyboard()
|
||||
_change_page_with_delay(previous_page)
|
||||
_change_create_reservation_buttion_visibility(_current_page)
|
||||
|
||||
return _pages[_current_page]
|
||||
|
||||
func _change_page_with_delay(previous_page):
|
||||
await get_tree().create_timer(0.1, false).timeout
|
||||
_pages[previous_page].visible = false
|
||||
_pages[_current_page].visible = true
|
||||
|
||||
func _change_create_reservation_buttion_visibility(page: Pages):
|
||||
if page == Pages.Board:
|
||||
_create_reservation_button.show()
|
||||
else:
|
||||
_create_reservation_button.hide()
|
||||
|
||||
func go_to_previous_page(with_update=true):
|
||||
if _previous_page != null:
|
||||
load_page(_previous_page, with_update)
|
||||
@ -188,3 +237,6 @@ func _on_1_hour_button_pressed():
|
||||
func get_date() -> String:
|
||||
var date = Time.get_date_dict_from_system()
|
||||
return "%02d.%02d.%04d" % [date.day, date.month, date.year]
|
||||
|
||||
func hide_keyboard():
|
||||
_keyboard.hide()
|
||||
|
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=14 format=3 uid="uid://bkrvh8vjpgqot"]
|
||||
[gd_scene load_steps=16 format=3 uid="uid://bkrvh8vjpgqot"]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/main/main_tablet.gd" id="1_fr6s5"]
|
||||
[ext_resource type="PackedScene" uid="uid://c431r28ef5edp" path="res://scenes/board/board.tscn" id="2_n47h4"]
|
||||
@ -12,6 +12,8 @@
|
||||
[ext_resource type="Script" path="res://src/infra/repos/backend/reservation_http.gd" id="10_v7sup"]
|
||||
[ext_resource type="Script" path="res://src/domain/services/reservation.gd" id="11_5xy2x"]
|
||||
[ext_resource type="Script" path="res://src/infra/repos/backend/event_handler_ws.gd" id="11_de30t"]
|
||||
[ext_resource type="Script" path="res://addons/onscreenkeyboard/onscreen_keyboard.gd" id="12_mc4hf"]
|
||||
[ext_resource type="PackedScene" uid="uid://dt03kci5qbkg3" path="res://scenes/common/dialog_box.tscn" id="14_cvh6c"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_uus54"]
|
||||
bg_color = Color(0.6, 0.6, 0.6, 0)
|
||||
@ -78,7 +80,7 @@ size_flags_vertical = 3
|
||||
[node name="TimeLabel" type="Label" parent="Left/TimeStatusContainer"]
|
||||
layout_mode = 2
|
||||
theme = ExtResource("5_atujq")
|
||||
text = "20:38"
|
||||
text = "15:09"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="Left/TimeStatusContainer"]
|
||||
@ -87,6 +89,11 @@ theme = ExtResource("5_atujq")
|
||||
text = "Свободно"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="WillBeAvailableLabel" type="Label" parent="Left/TimeStatusContainer"]
|
||||
layout_mode = 2
|
||||
theme = ExtResource("9_wpf8g")
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ReserveNowBox" type="VBoxContainer" parent="Left/TimeStatusContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 20
|
||||
@ -138,7 +145,8 @@ grow_vertical = 0
|
||||
[node name="CreateReservationButton" type="Button" parent="RightBottom"]
|
||||
layout_mode = 2
|
||||
theme = ExtResource("9_wpf8g")
|
||||
text = "Забронировать"
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = " Забронировать "
|
||||
|
||||
[node name="Repos" type="Node" parent="."]
|
||||
|
||||
@ -148,21 +156,34 @@ script = ExtResource("10_v7sup")
|
||||
[node name="EventHandler" type="Node" parent="Repos"]
|
||||
script = ExtResource("11_de30t")
|
||||
|
||||
[node name="Keyboard" type="Control" parent="."]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
anchors_preset = 0
|
||||
offset_left = -24.0
|
||||
offset_top = -10.0
|
||||
offset_right = 16.0
|
||||
offset_bottom = 30.0
|
||||
|
||||
[node name="OnscreenKeyboard" type="PanelContainer" parent="Keyboard"]
|
||||
visible = false
|
||||
layout_mode = 0
|
||||
offset_top = 595.0
|
||||
offset_right = 1182.0
|
||||
offset_bottom = 1252.0
|
||||
script = ExtResource("12_mc4hf")
|
||||
font_size = 72
|
||||
|
||||
[node name="Services" type="Node" parent="."]
|
||||
|
||||
[node name="ReservationService" type="Node" parent="Services"]
|
||||
script = ExtResource("11_5xy2x")
|
||||
|
||||
[node name="DialogBox" type="VBoxContainer" parent="."]
|
||||
[node name="Control" type="Control" parent="."]
|
||||
layout_mode = 2
|
||||
anchors_preset = 0
|
||||
offset_right = 1152.0
|
||||
|
||||
[node name="DialogBox" parent="." instance=ExtResource("14_cvh6c")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
@ -28,11 +28,15 @@ grow_horizontal = 2
|
||||
theme_override_constants/separation = 35
|
||||
script = ExtResource("1_prqr3")
|
||||
|
||||
[node name="Indent" type="BoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TopBar" type="HBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 50
|
||||
|
||||
[node name="BackButton" type="Button" parent="TopBar"]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("1_j1bkw")
|
||||
@ -49,6 +53,7 @@ text = "Бронирование комнаты"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ApplyButton" type="Button" parent="TopBar"]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("1_j1bkw")
|
||||
@ -86,7 +91,6 @@ title = "Конец"
|
||||
type = 3
|
||||
|
||||
[node name="Splitter3" type="Panel" parent="."]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(0, 5)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_yafv8")
|
||||
@ -98,7 +102,6 @@ title = "Создатель"
|
||||
editable = false
|
||||
|
||||
[node name="RoomField" parent="." instance=ExtResource("2_qfs8j")]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
title = "Комната"
|
||||
editable = false
|
||||
@ -114,7 +117,6 @@ visible = false
|
||||
layout_mode = 2
|
||||
title = "Описание"
|
||||
type = 1
|
||||
editable = false
|
||||
|
||||
[node name="Splitter5" type="Panel" parent="."]
|
||||
visible = false
|
||||
@ -126,12 +128,60 @@ theme_override_styles/panel = SubResource("StyleBoxFlat_r7q2r")
|
||||
layout_mode = 2
|
||||
script = ExtResource("5_bbsyh")
|
||||
|
||||
[node name="BottomBar" type="BoxContainer" parent="."]
|
||||
[node name="BottomBar" type="Control" parent="."]
|
||||
custom_minimum_size = Vector2(1150, 0)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 10
|
||||
|
||||
[node name="Left" type="HBoxContainer" parent="BottomBar"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -100.0
|
||||
offset_right = 401.0
|
||||
grow_vertical = 0
|
||||
theme_override_constants/separation = 50
|
||||
|
||||
[node name="BackButton" type="Button" parent="BottomBar/Left"]
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("1_j1bkw")
|
||||
text = " Назад "
|
||||
|
||||
[node name="DeleteButton" type="Button" parent="BottomBar/Left"]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("1_j1bkw")
|
||||
text = " Удалить "
|
||||
alignment = 2
|
||||
|
||||
[node name="Right" type="HBoxContainer" parent="BottomBar"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -371.0
|
||||
offset_top = -100.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
alignment = 2
|
||||
|
||||
[node name="ApplyButton" type="Button" parent="BottomBar/Right"]
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("1_j1bkw")
|
||||
text = " Забронировать "
|
||||
|
||||
[node name="BottomBarOld" type="BoxContainer" parent="."]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
alignment = 2
|
||||
|
||||
[node name="DeleteButton" type="Button" parent="BottomBar"]
|
||||
[node name="DeleteButton" type="Button" parent="BottomBarOld"]
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("1_j1bkw")
|
||||
|
@ -30,6 +30,7 @@ layout_mode = 2
|
||||
theme_override_constants/separation = 50
|
||||
|
||||
[node name="BackButton" type="Button" parent="TopBar"]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("2_57fpn")
|
||||
@ -42,9 +43,11 @@ theme = ExtResource("2_57fpn")
|
||||
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/shadow_offset_x = 3
|
||||
theme_override_constants/shadow_offset_y = 3
|
||||
text = "Изменение бронирования"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ApplyButton" type="Button" parent="TopBar"]
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("2_57fpn")
|
||||
@ -121,11 +124,59 @@ theme_override_styles/panel = SubResource("StyleBoxFlat_yafv8")
|
||||
layout_mode = 2
|
||||
script = ExtResource("5_xmu5c")
|
||||
|
||||
[node name="BottomBar" type="BoxContainer" parent="."]
|
||||
[node name="BottomBar" type="Control" parent="."]
|
||||
custom_minimum_size = Vector2(1150, 0)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 10
|
||||
|
||||
[node name="Left" type="HBoxContainer" parent="BottomBar"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -100.0
|
||||
offset_right = 401.0
|
||||
grow_vertical = 0
|
||||
theme_override_constants/separation = 50
|
||||
|
||||
[node name="BackButton" type="Button" parent="BottomBar/Left"]
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("2_57fpn")
|
||||
text = " Назад "
|
||||
|
||||
[node name="DeleteButton" type="Button" parent="BottomBar/Left"]
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("2_57fpn")
|
||||
text = " Удалить "
|
||||
alignment = 2
|
||||
|
||||
[node name="Right" type="HBoxContainer" parent="BottomBar"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -371.0
|
||||
offset_top = -100.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
alignment = 2
|
||||
|
||||
[node name="ApplyButton" type="Button" parent="BottomBar/Right"]
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("2_57fpn")
|
||||
text = " Изменить "
|
||||
|
||||
[node name="BottomBarOld" type="BoxContainer" parent="."]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
alignment = 2
|
||||
|
||||
[node name="DeleteButton" type="Button" parent="BottomBar"]
|
||||
[node name="DeleteButton" type="Button" parent="BottomBarOld"]
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("2_57fpn")
|
||||
|
@ -11,9 +11,10 @@ enum Types {
|
||||
type = new_type
|
||||
|
||||
@onready var _main: Main = get_tree().get_current_scene()
|
||||
@onready var _back_button := $TopBar/BackButton
|
||||
@onready var _apply_button := $TopBar/ApplyButton
|
||||
@onready var _delete_button := $BottomBar/DeleteButton
|
||||
@onready var _title := $TopBar/Label
|
||||
@onready var _back_button := $BottomBar/Left/BackButton
|
||||
@onready var _apply_button := $BottomBar/Right/ApplyButton
|
||||
@onready var _delete_button := $BottomBar/Left/DeleteButton
|
||||
@onready var _error_box := $ErrorBox
|
||||
|
||||
@onready var _title_field := $TitleField
|
||||
@ -24,6 +25,29 @@ enum Types {
|
||||
@onready var _room_field := $RoomField
|
||||
@onready var _description_field := $DescriptionField
|
||||
|
||||
func _process(delta):
|
||||
_process_fonts()
|
||||
_process_separation()
|
||||
|
||||
func _process_fonts():
|
||||
_process_font_size(_title, 35)
|
||||
_process_font_size(_back_button, 35)
|
||||
_process_font_size(_apply_button, 35)
|
||||
_process_font_size(_delete_button, 35)
|
||||
_process_font_size(_error_box, 35)
|
||||
|
||||
func _process_font_size(obj, k):
|
||||
var font_size = obj.get_theme_default_font_size()
|
||||
var new_font_size = get_viewport_rect().size.y/k
|
||||
if font_size != new_font_size:
|
||||
obj.add_theme_font_size_override("font_size", new_font_size)
|
||||
|
||||
func _process_separation():
|
||||
var separation = get_theme_constant("separation")
|
||||
var new_separation = get_viewport_rect().size.y/28
|
||||
if separation != new_separation:
|
||||
add_theme_constant_override("separation", new_separation)
|
||||
|
||||
func _ready():
|
||||
initialize_signals()
|
||||
_error_box.set_message(String())
|
||||
@ -50,7 +74,7 @@ func _on_delete_button_pressed():
|
||||
|
||||
func _load_info():
|
||||
var repo = _main.get_reservation_repo()
|
||||
var reservation_id = repo.get_current_reservation_id()
|
||||
var reservation_id = repo.get_selected_reservation_id()
|
||||
var reservation = await repo.get_reservation(reservation_id)
|
||||
|
||||
_title_field.set_value(reservation.title)
|
||||
@ -94,9 +118,9 @@ func _update_reservation():
|
||||
dto.color = randi_range(1, 3)
|
||||
|
||||
var repo = _main.get_reservation_repo()
|
||||
var reservation_id = repo.get_current_reservation_id()
|
||||
var reservation_id = repo.get_selected_reservation_id()
|
||||
repo.change_reservation(reservation_id, dto)
|
||||
repo.set_current_reservation_id(null)
|
||||
repo.set_selected_reservation_id(null)
|
||||
|
||||
dto.queue_free()
|
||||
|
||||
@ -105,7 +129,7 @@ func _update_reservation():
|
||||
|
||||
func _delete_reservation():
|
||||
var repo = _main.get_reservation_repo()
|
||||
var reservation_id = repo.get_current_reservation_id()
|
||||
var reservation_id = repo.get_selected_reservation_id()
|
||||
repo.cancel_reservation(reservation_id)
|
||||
|
||||
_main.load_page(Main.Pages.Board)
|
||||
|
@ -6,10 +6,10 @@ class_name ReservationService
|
||||
func is_time_busy(new_start_time_minutes, new_finish_time_minutes):
|
||||
var repo = _main.get_reservation_repo()
|
||||
var reservations = await repo.list_reservations({"date": _main.get_date()})
|
||||
var current_reservation_id = repo.get_current_reservation_id()
|
||||
var selected_reservation_id = repo.get_selected_reservation_id()
|
||||
|
||||
for reservation in reservations:
|
||||
if reservation.id == current_reservation_id:
|
||||
if reservation.id == selected_reservation_id:
|
||||
continue
|
||||
|
||||
var other_start_time = reservation.start_time
|
||||
|
@ -5,7 +5,8 @@ class_name AbstractReservationRepo
|
||||
signal connected
|
||||
signal not_connected
|
||||
|
||||
var _current_reservation_id = null
|
||||
var _selected_reservation_id = null
|
||||
var _current_reservation = null
|
||||
|
||||
func create_reservation(dto: CreateReservationDTO):
|
||||
pass
|
||||
@ -22,8 +23,11 @@ func get_reservation(reservation_id):
|
||||
func list_reservations(filters: Dictionary = {}):
|
||||
pass
|
||||
|
||||
func set_current_reservation_id(value):
|
||||
_current_reservation_id = value
|
||||
func set_selected_reservation_id(value):
|
||||
_selected_reservation_id = value
|
||||
|
||||
func get_current_reservation_id():
|
||||
return _current_reservation_id
|
||||
func get_selected_reservation_id():
|
||||
return _selected_reservation_id
|
||||
|
||||
func get_current_reservation():
|
||||
return _current_reservation
|
||||
|
@ -1,7 +1,7 @@
|
||||
class_name EventHandlerWS
|
||||
extends EventHandler
|
||||
|
||||
const BACKEND_URL = "http://127.0.0.1:5000/socket.io"
|
||||
const BACKEND_URL = "http://192.168.1.178:5000/socket.io"
|
||||
var _room_id: String = ""
|
||||
var _jwt_token: String = ""
|
||||
var _client: SocketIOClient
|
||||
@ -40,10 +40,13 @@ func _on_socket_connect(_payload, _namespace, error: bool):
|
||||
print("Socket.IO connected")
|
||||
subscribe_to_room(_room_id)
|
||||
|
||||
func _on_socket_disconnect():
|
||||
func _on_socket_disconnect(name_space: String):
|
||||
print("Disconnected from server")
|
||||
disconnected.emit()
|
||||
|
||||
print("Reconnecting...")
|
||||
_ready()
|
||||
|
||||
func _on_socket_event(event: String, payload: Variant, _namespace):
|
||||
print(event, payload)
|
||||
match event:
|
||||
@ -60,6 +63,7 @@ func subscribe_to_room(room_id: String):
|
||||
)
|
||||
|
||||
func disconnect_from_server():
|
||||
print("Disconnected from server")
|
||||
_client.socketio_disconnect()
|
||||
|
||||
func _exit_tree():
|
||||
|
@ -2,14 +2,13 @@
|
||||
extends AbstractReservationRepo
|
||||
class_name ReservationRepoHTTP
|
||||
|
||||
const BASE_URL = "http://127.0.0.1:5000"
|
||||
const BASE_URL = "http://192.168.1.178:5000"
|
||||
const RESERVATION_ENDPOINT = "/reservation/"
|
||||
const HEALTH_ENDPOINT = "/health/"
|
||||
|
||||
signal request_failed(error_message: String)
|
||||
|
||||
var _jwt_token: String = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MDA0MDQzNywianRpIjoiOTM4NTUyMjMtMjhiNC00OWVhLWI3ZjUtZmYxMTg4YzI1Mjg2IiwidHlwZSI6ImFjY2VzcyIsInN1YiI6InRlc3RfdXNlciIsIm5iZiI6MTc0MDA0MDQzNywiY3NyZiI6ImMwYzI2MTU0LTdkNjItNGYyZi04ZjBhLWI0MjA0ODJlMmEzZCIsImV4cCI6MTc0MDA0MTMzN30.esPRTXNxrtziuOc2dUsc9XqbedErjcyvPlL3aUZIaaA"
|
||||
|
||||
var _timed_out := false
|
||||
|
||||
func _ready():
|
||||
@ -52,13 +51,31 @@ func list_reservations(filters: Dictionary = {}) -> Array:
|
||||
|
||||
var endpoint = RESERVATION_ENDPOINT + query
|
||||
var result = await _make_request(endpoint, HTTPClient.METHOD_GET)
|
||||
return _parse_reservation_list(result) if result is Array else []
|
||||
var reservations = _parse_reservation_list(result) if result is Array else []
|
||||
|
||||
func set_current_reservation_id(value):
|
||||
_current_reservation_id = value
|
||||
_set_current_reservation_id_from_reservations(reservations)
|
||||
return reservations
|
||||
|
||||
func get_current_reservation_id():
|
||||
return _current_reservation_id
|
||||
func _set_current_reservation_id_from_reservations(reservations):
|
||||
var time = Time.get_time_dict_from_system()
|
||||
var current_time_in_minutes = time.hour*60 + time.minute
|
||||
|
||||
for reservation in reservations:
|
||||
var start_time_in_minutes = reservation.start_time.hours*60 + reservation.start_time.minutes
|
||||
var finish_time_in_minutes = reservation.finish_time.hours*60 + reservation.finish_time.minutes
|
||||
|
||||
if current_time_in_minutes >= start_time_in_minutes \
|
||||
and current_time_in_minutes < finish_time_in_minutes:
|
||||
_current_reservation = reservation
|
||||
return
|
||||
|
||||
_current_reservation = null
|
||||
|
||||
func set_selected_reservation_id(value):
|
||||
_selected_reservation_id = value
|
||||
|
||||
func get_selected_reservation_id():
|
||||
return _selected_reservation_id
|
||||
|
||||
func set_jwt_token(token: String):
|
||||
_jwt_token = token
|
||||
|
@ -230,6 +230,7 @@ func socketio_connect(name_space: String="/"):
|
||||
|
||||
# disconnect from socket.io server by namespace
|
||||
func socketio_disconnect(name_space: String="/"):
|
||||
print("FUCK")
|
||||
if _connection_state == ConnectionState.CONNECTED:
|
||||
# We should ONLY send disconnect packet when we're connected
|
||||
_socketio_send_packet(SocketIOPacketType.DISCONNECT, name_space)
|
||||
|
Loading…
x
Reference in New Issue
Block a user