feat: CI creates Gitea releases with changelog, app polls for updates on startup
Some checks failed
Android Build & Publish / android (push) Failing after 2m0s
Some checks failed
Android Build & Publish / android (push) Failing after 2m0s
- android-build.yml: fetch full history+tags, embed VITE_APP_BUILD, add step to create a tagged Gitea release (build-N) with markdown changelog and APK release assets after every push; bump permissions to contents:write - src/game/update-check.ts: polls Gitea releases/latest, compares build-N tag against CURRENT_BUILD (0 in dev), returns UpdateInfo or null; dismissal persisted to localStorage - src/vite-env.d.ts: TypeScript env declarations for VITE_APP_BUILD - src/scenes/MenuScene.ts: fire-and-forget update check on menu load; renders dismissible bottom-bar banner with optional APK download link - src/game/ai.ts: early-game empty-table dump heuristic (safest card first)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import Phaser from 'phaser';
|
||||
import { Difficulty } from '../game/types';
|
||||
import { GameSceneData, loadAudioPreferences } from '../game/preferences';
|
||||
import { checkForUpdate, isDismissed, dismissUpdate, CURRENT_BUILD, UpdateInfo } from '../game/update-check';
|
||||
|
||||
type MenuButtonPalette = {
|
||||
base: number;
|
||||
@@ -133,6 +134,14 @@ export class MenuScene extends Phaser.Scene {
|
||||
|
||||
this.createRulesPanel(layout);
|
||||
this.createControlPanel(layout, audioPreferences);
|
||||
|
||||
// Fire-and-forget update check — shows a dismissible banner if a newer
|
||||
// CI build is available on Gitea.
|
||||
checkForUpdate(CURRENT_BUILD).then(info => {
|
||||
if (info && !isDismissed(info.buildNumber) && this.scene.isActive()) {
|
||||
this.showUpdateBanner(layout, info);
|
||||
}
|
||||
}).catch(() => { /* network unavailable — silent */ });
|
||||
}
|
||||
|
||||
private createLayout(width: number, height: number): MenuLayout {
|
||||
@@ -576,4 +585,64 @@ export class MenuScene extends Phaser.Scene {
|
||||
this.scene.start('SettingsScene', { returnSceneKey: 'MenuScene' });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a slim dismissible notification bar at the bottom of the visible
|
||||
* area when a newer CI build is available on Gitea.
|
||||
*
|
||||
* Layout: [ "Aggiornamento disponibile — build N" | Scarica → | ✕ ]
|
||||
*/
|
||||
private showUpdateBanner(layout: MenuLayout, info: UpdateInfo): void {
|
||||
const bannerH = layout.isCompactViewport ? 40 : 48;
|
||||
const bannerW = layout.visibleBounds.width - layout.frameInset * 2;
|
||||
const cx = layout.visibleBounds.centerX;
|
||||
// Float the banner along the very bottom edge of the visible area.
|
||||
const cy = layout.visibleBounds.bottom - bannerH / 2 - 4;
|
||||
const fs = layout.isCompactViewport ? 13 : 15;
|
||||
const depth = 200;
|
||||
|
||||
// Collect all objects so the dismiss handler can destroy them together.
|
||||
const objs: Phaser.GameObjects.GameObject[] = [];
|
||||
const track = <T extends Phaser.GameObjects.GameObject>(o: T): T => {
|
||||
objs.push(o); return o;
|
||||
};
|
||||
|
||||
track(
|
||||
this.add.rectangle(cx, cy, bannerW, bannerH, 0x0a1e3a, 0.96)
|
||||
.setStrokeStyle(1, 0x4a90d9, 0.85)
|
||||
.setDepth(depth),
|
||||
);
|
||||
|
||||
track(
|
||||
this.add.text(cx - bannerW / 2 + 12, cy,
|
||||
`Aggiornamento disponibile — build ${info.buildNumber}`,
|
||||
{ fontFamily: 'Georgia, serif', fontSize: `${fs}px`, color: '#b8d8f8', resolution: 2 },
|
||||
).setOrigin(0, 0.5).setDepth(depth + 1),
|
||||
);
|
||||
|
||||
// Dismiss (✕) — always present, rightmost.
|
||||
const dismissBtn = track(
|
||||
this.add.text(cx + bannerW / 2 - 12, cy, '✕', {
|
||||
fontFamily: 'Georgia, serif', fontSize: `${fs + 4}px`, color: '#7a8a9a', resolution: 2,
|
||||
}).setOrigin(1, 0.5).setDepth(depth + 1).setInteractive({ useHandCursor: true }),
|
||||
) as Phaser.GameObjects.Text;
|
||||
dismissBtn.on('pointerover', () => dismissBtn.setColor('#c0d0e0'));
|
||||
dismissBtn.on('pointerout', () => dismissBtn.setColor('#7a8a9a'));
|
||||
dismissBtn.on('pointerdown', () => {
|
||||
dismissUpdate(info.buildNumber);
|
||||
objs.forEach(o => o.destroy());
|
||||
});
|
||||
|
||||
// "Scarica →" link — present when a direct APK URL is available.
|
||||
if (info.apkUrl) {
|
||||
const dlBtn = track(
|
||||
this.add.text(cx + bannerW / 2 - 38, cy, 'Scarica →', {
|
||||
fontFamily: 'Georgia, serif', fontSize: `${fs}px`, color: '#5ba3e8', resolution: 2,
|
||||
}).setOrigin(1, 0.5).setDepth(depth + 1).setInteractive({ useHandCursor: true }),
|
||||
) as Phaser.GameObjects.Text;
|
||||
dlBtn.on('pointerover', () => dlBtn.setColor('#90c8ff'));
|
||||
dlBtn.on('pointerout', () => dlBtn.setColor('#5ba3e8'));
|
||||
dlBtn.on('pointerdown', () => window.open(info.apkUrl!, '_blank'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user