Proof of concept of building emojis.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4464 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
e921b4a86a
commit
3c4959433a
@ -8,6 +8,7 @@ tfrpc.register(async function createIdentity() {
|
|||||||
return ssb.createIdentity();
|
return ssb.createIdentity();
|
||||||
});
|
});
|
||||||
tfrpc.register(async function appendMessage(id, message) {
|
tfrpc.register(async function appendMessage(id, message) {
|
||||||
|
print('APPEND', JSON.stringify(message));
|
||||||
return ssb.appendMessageWithIdentity(id, message);
|
return ssb.appendMessageWithIdentity(id, message);
|
||||||
});
|
});
|
||||||
tfrpc.register(function url() {
|
tfrpc.register(function url() {
|
||||||
|
@ -9,6 +9,6 @@
|
|||||||
<script src="leaflet.js"></script>
|
<script src="leaflet.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body style="color: #fff; display: flex; flex-flow: column; height: 100%; width: 100%; margin: 0; padding: 0">
|
<body style="color: #fff; display: flex; flex-flow: column; height: 100%; width: 100%; margin: 0; padding: 0">
|
||||||
<gg-app style="width: 100%; height: 100%"></gg-app>
|
<gg-app style="width: 100%; height: 100%" id="ggapp"></gg-app>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -14,6 +14,12 @@ const k_color_pavement = [32, 32, 32, 255];
|
|||||||
const k_color_grass = [0, 255, 0, 255];
|
const k_color_grass = [0, 255, 0, 255];
|
||||||
const k_color_default = [128, 128, 128, 255];
|
const k_color_default = [128, 128, 128, 255];
|
||||||
|
|
||||||
|
const k_store = {
|
||||||
|
'🦞': 15,
|
||||||
|
'🛶': 10,
|
||||||
|
'🏠': 10,
|
||||||
|
};
|
||||||
|
|
||||||
class GgAppElement extends LitElement {
|
class GgAppElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
@ -22,11 +28,12 @@ class GgAppElement extends LitElement {
|
|||||||
activities: {type: Array},
|
activities: {type: Array},
|
||||||
activity: {type: Object},
|
activity: {type: Object},
|
||||||
world: {type: Object},
|
world: {type: Object},
|
||||||
id: {type: String},
|
whoami: {type: String},
|
||||||
status: {type: Object},
|
status: {type: Object},
|
||||||
tab: {type: String},
|
tab: {type: String},
|
||||||
url: {type: String},
|
url: {type: String},
|
||||||
currency: {type: Number},
|
currency: {type: Number},
|
||||||
|
to_build: {type: String},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +42,7 @@ class GgAppElement extends LitElement {
|
|||||||
this.activities = [];
|
this.activities = [];
|
||||||
this.activity = {};
|
this.activity = {};
|
||||||
this.loaded_activities = [];
|
this.loaded_activities = [];
|
||||||
|
this.placed_emojis = [];
|
||||||
this.strava = {};
|
this.strava = {};
|
||||||
this.min_lat = Number.MAX_VALUE;
|
this.min_lat = Number.MAX_VALUE;
|
||||||
this.min_lon = Number.MAX_VALUE;
|
this.min_lon = Number.MAX_VALUE;
|
||||||
@ -63,7 +71,7 @@ class GgAppElement extends LitElement {
|
|||||||
console.log('update_activities failed', e);
|
console.log('update_activities failed', e);
|
||||||
}
|
}
|
||||||
await this.acquire_ssb_identity();
|
await this.acquire_ssb_identity();
|
||||||
if (this.id && this.activities?.length) {
|
if (this.whoami && this.activities?.length) {
|
||||||
await this.sync_activities();
|
await this.sync_activities();
|
||||||
}
|
}
|
||||||
await this.get_activities_from_ssb();
|
await this.get_activities_from_ssb();
|
||||||
@ -118,8 +126,30 @@ class GgAppElement extends LitElement {
|
|||||||
this.status = {text: 'calculating balance'};
|
this.status = {text: 'calculating balance'};
|
||||||
rows = await tfrpc.rpc.query(`
|
rows = await tfrpc.rpc.query(`
|
||||||
SELECT count(*) AS currency FROM messages WHERE author = ? AND json_extract(content, '$.type') = 'gg-activity'
|
SELECT count(*) AS currency FROM messages WHERE author = ? AND json_extract(content, '$.type') = 'gg-activity'
|
||||||
`, [this.id]);
|
`, [this.whoami]);
|
||||||
this.currency = rows[0].currency;
|
let currency = rows[0].currency;
|
||||||
|
rows = await tfrpc.rpc.query(`
|
||||||
|
SELECT SUM(json_extract(content, '$.cost')) AS cost FROM messages WHERE author = ? AND json_extract(content, '$.type') = 'gg-place'
|
||||||
|
`, [this.whoami]);
|
||||||
|
let spent = rows[0].cost;
|
||||||
|
this.currency = currency - spent;
|
||||||
|
this.status = {text: 'getting placed emojis'};
|
||||||
|
rows = await tfrpc.rpc.query(`
|
||||||
|
SELECT messages.content
|
||||||
|
FROM messages_fts('"gg-place"')
|
||||||
|
JOIN messages ON messages.rowid = messages_fts.rowid
|
||||||
|
WHERE json_extract(messages.content, '$.type') = 'gg-place'
|
||||||
|
ORDER BY messages.timestamp
|
||||||
|
`);
|
||||||
|
for (let row of rows) {
|
||||||
|
console.log(row.content);
|
||||||
|
let content = JSON.parse(row.content);
|
||||||
|
this.placed_emojis.push({
|
||||||
|
position: content.position,
|
||||||
|
emoji: content.emoji,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log(this.placed_emojis);
|
||||||
this.status = undefined;
|
this.status = undefined;
|
||||||
this.update_map();
|
this.update_map();
|
||||||
}
|
}
|
||||||
@ -137,7 +167,7 @@ class GgAppElement extends LitElement {
|
|||||||
SELECT from_strava.value FROM json_each(?) AS from_strava
|
SELECT from_strava.value FROM json_each(?) AS from_strava
|
||||||
LEFT OUTER JOIN my_activities ON from_strava.value = my_activities.url
|
LEFT OUTER JOIN my_activities ON from_strava.value = my_activities.url
|
||||||
WHERE my_activities.url IS NULL
|
WHERE my_activities.url IS NULL
|
||||||
`, [this.id, JSON.stringify(ids)]);
|
`, [this.whoami, JSON.stringify(ids)]);
|
||||||
console.log('missing = ', missing);
|
console.log('missing = ', missing);
|
||||||
for (let [index, row] of missing.entries()) {
|
for (let [index, row] of missing.entries()) {
|
||||||
this.status = {text: 'syncing from strava', value: index, max: missing.length};
|
this.status = {text: 'syncing from strava', value: index, max: missing.length};
|
||||||
@ -163,7 +193,7 @@ class GgAppElement extends LitElement {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
await tfrpc.rpc.appendMessage(this.id, message);
|
await tfrpc.rpc.appendMessage(this.whoami, message);
|
||||||
}
|
}
|
||||||
this.status = undefined;
|
this.status = undefined;
|
||||||
}
|
}
|
||||||
@ -182,16 +212,16 @@ class GgAppElement extends LitElement {
|
|||||||
ORDER BY timestamp DESC limit 1
|
ORDER BY timestamp DESC limit 1
|
||||||
`, [JSON.stringify(ids)])).map(row => row.author) : [];
|
`, [JSON.stringify(ids)])).map(row => row.author) : [];
|
||||||
if (!players.length) {
|
if (!players.length) {
|
||||||
this.id = await tfrpc.rpc.createIdentity();
|
this.whoami = await tfrpc.rpc.createIdentity();
|
||||||
if (this.id) {
|
if (this.whoami) {
|
||||||
await tfrpc.rpc.appendMessage(this.id, {
|
await tfrpc.rpc.appendMessage(this.whoami, {
|
||||||
type: 'gg-player',
|
type: 'gg-player',
|
||||||
active: true,
|
active: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
players.sort();
|
players.sort();
|
||||||
this.id = players[0];
|
this.whoami = players[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,6 +324,57 @@ class GgAppElement extends LitElement {
|
|||||||
.openOn(this.leaflet);
|
.openOn(this.leaflet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async build() {
|
||||||
|
if (this.popup) {
|
||||||
|
this.popup.remove();
|
||||||
|
}
|
||||||
|
if (!this.marker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let latlng = this.marker.getLatLng();
|
||||||
|
|
||||||
|
let cost = k_store[this.to_build];
|
||||||
|
if (cost > this.currency) {
|
||||||
|
alert('Insufficient funds.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let message = {
|
||||||
|
type: 'gg-place',
|
||||||
|
position: {lat: latlng.lat, lng: latlng.lng},
|
||||||
|
emoji: this.to_build,
|
||||||
|
cost: cost,
|
||||||
|
};
|
||||||
|
let id = await tfrpc.rpc.appendMessage(this.whoami, message);
|
||||||
|
this.marker.remove();
|
||||||
|
this.placed_emojis.push({
|
||||||
|
position: {lat: latlng.lat, lng: latlng.lng},
|
||||||
|
emoji: this.to_build,
|
||||||
|
});
|
||||||
|
this.currency -= cost;
|
||||||
|
return this.update_map();
|
||||||
|
}
|
||||||
|
|
||||||
|
on_marker_click(event) {
|
||||||
|
this.popup = L.popup()
|
||||||
|
.setLatLng(event.latlng)
|
||||||
|
.setContent(`
|
||||||
|
${this.to_build} (-${k_store[this.to_build]}) <input type="button" value="Build" onclick="document.getElementById('ggapp').build()"></input>
|
||||||
|
`)
|
||||||
|
.openOn(this.leaflet);
|
||||||
|
}
|
||||||
|
|
||||||
|
on_mouse_down(event) {
|
||||||
|
if (this.marker) {
|
||||||
|
this.marker.remove();
|
||||||
|
this.marker = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.to_build) {
|
||||||
|
this.marker = L.marker(event.latlng, {icon: L.divIcon({className: 'build-icon'}), draggable: true}).addTo(this.leaflet);
|
||||||
|
this.marker.on({click: this.on_marker_click.bind(this)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async update_map() {
|
async update_map() {
|
||||||
let map = this.shadowRoot.getElementById('map');
|
let map = this.shadowRoot.getElementById('map');
|
||||||
if (!map || !this.loaded_activities.length) {
|
if (!map || !this.loaded_activities.length) {
|
||||||
@ -304,6 +385,7 @@ class GgAppElement extends LitElement {
|
|||||||
if (!this.leaflet) {
|
if (!this.leaflet) {
|
||||||
this.leaflet = L.map(map, {attributionControl: false, maxZoom: 16, bounceAtZoomLimits: false});
|
this.leaflet = L.map(map, {attributionControl: false, maxZoom: 16, bounceAtZoomLimits: false});
|
||||||
this.leaflet.on({contextmenu: this.on_click.bind(this)});
|
this.leaflet.on({contextmenu: this.on_click.bind(this)});
|
||||||
|
this.leaflet.on({click: this.on_mouse_down.bind(this)});
|
||||||
}
|
}
|
||||||
let self = this;
|
let self = this;
|
||||||
let grid_layer = L.GridLayer.extend({
|
let grid_layer = L.GridLayer.extend({
|
||||||
@ -336,6 +418,16 @@ class GgAppElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (let placed of self.placed_emojis) {
|
||||||
|
let position = self.leaflet.options.crs.latLngToPoint(placed.position, coords.z);
|
||||||
|
let tile_x = Math.floor(position.x / size.x);
|
||||||
|
let tile_y = Math.floor(position.y / size.y);
|
||||||
|
position.x = position.x - tile_x * size.x;
|
||||||
|
position.y = position.y - tile_y * size.y;
|
||||||
|
if (tile_x == coords.x && tile_y == coords.y) {
|
||||||
|
context.fillText(placed.emoji, position.x, position.y + 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -539,8 +631,8 @@ class GgAppElement extends LitElement {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
console.log('id =', this.id, 'message = ', message);
|
console.log('id =', this.whoami, 'message = ', message);
|
||||||
let id = await tfrpc.rpc.appendMessage(this.id, message);
|
let id = await tfrpc.rpc.appendMessage(this.whoami, message);
|
||||||
console.log('appended message', id);
|
console.log('appended message', id);
|
||||||
alert('Activity uploaded.');
|
alert('Activity uploaded.');
|
||||||
await this.get_activities_from_ssb();
|
await this.get_activities_from_ssb();
|
||||||
@ -579,10 +671,20 @@ class GgAppElement extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render_store_item(item) {
|
||||||
|
let [emoji, cost] = item;
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<input type="button" value="${emoji}" @click=${() => this.to_build = emoji}></input> ${cost} ${emoji == this.to_build ? '<-- Will be built next' : undefined}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
render_store() {
|
render_store() {
|
||||||
return html`
|
return html`
|
||||||
<h2>Store</h2>
|
<h2>Store</h2>
|
||||||
<div><b>Your balance:</b> ${this.currency}</div>
|
<div><b>Your balance:</b> ${this.currency}</div>
|
||||||
|
${Object.entries(k_store).map(this.render_store_item.bind(this))}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,7 +697,7 @@ class GgAppElement extends LitElement {
|
|||||||
header = html`
|
header = html`
|
||||||
<div style="flex: 1 0; display: flex; flex-direction: row; align-items: center; gap: 1em; width: 100%">
|
<div style="flex: 1 0; display: flex; flex-direction: row; align-items: center; gap: 1em; width: 100%">
|
||||||
<div style="flex: 1 1">Please <a target="_top" href=${strava_url}>login</a> to Strava.</div>
|
<div style="flex: 1 1">Please <a target="_top" href=${strava_url}>login</a> to Strava.</div>
|
||||||
<span style="font-size: xx-small; flex: 1 1; word-break: break-all">${this.id}</span>
|
<span style="font-size: xx-small; flex: 1 1; word-break: break-all">${this.whoami}</span>
|
||||||
<input type="button" value="📁" @click=${this.upload}></input>
|
<input type="button" value="📁" @click=${this.upload}></input>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -604,7 +706,7 @@ class GgAppElement extends LitElement {
|
|||||||
<div>
|
<div>
|
||||||
<div style="flex: 1 0; display: flex; flex-direction: row; align-items: center; gap: 1em; width: 100%">
|
<div style="flex: 1 0; display: flex; flex-direction: row; align-items: center; gap: 1em; width: 100%">
|
||||||
<h1>Welcome, ${this.user.credentials.session.name}</h1>
|
<h1>Welcome, ${this.user.credentials.session.name}</h1>
|
||||||
<span style="font-size: xx-small; flex: 1 1; word-break: break-all">${this.id}</span>
|
<span style="font-size: xx-small; flex: 1 1; word-break: break-all">${this.whoami}</span>
|
||||||
<input type="button" value="📁" @click=${this.upload}></input>
|
<input type="button" value="📁" @click=${this.upload}></input>
|
||||||
</div>
|
</div>
|
||||||
<h3 ?hidden=${!this.status?.text}>${this.status?.text} <progress ?hidden=${!this.status?.max} value=${this.status?.value} max=${this.status?.max}>${this.status?.value}</progress></h3>
|
<h3 ?hidden=${!this.status?.text}>${this.status?.text} <progress ?hidden=${!this.status?.max} value=${this.status?.value} max=${this.status?.max}>${this.status?.value}</progress></h3>
|
||||||
@ -646,6 +748,12 @@ class GgAppElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
<style>
|
||||||
|
.build-icon::before {
|
||||||
|
content: '📍';
|
||||||
|
border: 2px solid red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<link rel="stylesheet" href="leaflet.css"/>
|
<link rel="stylesheet" href="leaflet.css"/>
|
||||||
<div style="width: 100%; height: 100%; display: flex; flex-direction: column">
|
<div style="width: 100%; height: 100%; display: flex; flex-direction: column">
|
||||||
${header}
|
${header}
|
||||||
|
Loading…
Reference in New Issue
Block a user