Skip to content

Commit 9035809

Browse files
committed
feat: enhance mobile companion gameplay behavior and UI
1 parent f6e40d4 commit 9035809

1 file changed

Lines changed: 94 additions & 20 deletions

File tree

src/views/MobileCompanion.svelte

Lines changed: 94 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,34 @@
146146
let controlStatusTimer: ReturnType<typeof setInterval> | undefined;
147147
let thumbnailRetryTimer: ReturnType<typeof setInterval> | undefined;
148148
149+
let wakeLock: any = null;
150+
151+
const requestWakeLock = async () => {
152+
if (typeof navigator === "undefined" || !("wakeLock" in navigator)) return;
153+
try {
154+
if (wakeLock) return;
155+
wakeLock = await (navigator as any).wakeLock.request("screen");
156+
wakeLock.addEventListener("release", () => {
157+
wakeLock = null;
158+
});
159+
} catch (err) {
160+
console.warn("Wake Lock request failed", err);
161+
}
162+
};
163+
164+
const releaseWakeLock = async () => {
165+
if (wakeLock) {
166+
await wakeLock.release().catch(() => {});
167+
wakeLock = null;
168+
}
169+
};
170+
171+
const handleVisibilityChange = () => {
172+
if (document.visibilityState === "visible" && canControl) {
173+
void requestWakeLock();
174+
}
175+
};
176+
149177
const THUMBNAIL_BATCH_SIZE = 16;
150178
const THUMBNAIL_RETRY_DELAY_MS = 8000;
151179
const THUMBNAIL_MAX_ATTEMPTS = 3;
@@ -219,6 +247,14 @@
219247
}
220248
}
221249
250+
$: {
251+
if (canControl) {
252+
void requestWakeLock();
253+
} else {
254+
void releaseWakeLock();
255+
}
256+
}
257+
222258
$: selectedGame =
223259
selectedGameId === null
224260
? null
@@ -542,6 +578,7 @@
542578
};
543579
544580
const adoptActiveGame = (nextActiveGameId: number | null) => {
581+
const prevActiveGameId = activeGameId;
545582
activeGameId = nextActiveGameId;
546583
if (nextActiveGameId === null) {
547584
return;
@@ -555,7 +592,7 @@
555592
const shouldLoadMemo = selectedGameId !== target.id;
556593
selectedGameId = target.id;
557594
didSelectGameManually = false;
558-
if (activeView === "detail") {
595+
if (prevActiveGameId !== nextActiveGameId) {
559596
activeView = "controller";
560597
}
561598
@@ -915,6 +952,7 @@
915952
916953
document.addEventListener("focusin", handleViewportReset);
917954
document.addEventListener("focusout", handleViewportReset);
955+
document.addEventListener("visibilitychange", handleVisibilityChange);
918956
919957
void getAllCachedImages().then((cached) => {
920958
cached.forEach(({ path, blob }) => {
@@ -957,6 +995,8 @@
957995
958996
document.removeEventListener("focusin", handleViewportReset);
959997
document.removeEventListener("focusout", handleViewportReset);
998+
document.removeEventListener("visibilitychange", handleVisibilityChange);
999+
void releaseWakeLock();
9601000
9611001
cleanupCallbacks.forEach((callback) => callback());
9621002
cleanupCallbacks = [];
@@ -1062,9 +1102,7 @@
10621102
<span class="i-material-symbols:chevron-right-rounded text-[22px]" />
10631103
</button>
10641104
{/if}
1065-
{#if lastActionText}
1066-
<div class="toast-line">{lastActionText}</div>
1067-
{/if}
1105+
10681106
</section>
10691107

10701108
<section class="content detail-content" class:hidden={activeView !== 'detail'}>
@@ -1124,9 +1162,7 @@
11241162
{:else}
11251163
<section class="empty-state">ゲームを選択してください</section>
11261164
{/if}
1127-
{#if lastActionText}
1128-
<div class="toast-line">{lastActionText}</div>
1129-
{/if}
1165+
11301166
</section>
11311167

11321168
<section class="content connect-content" class:hidden={activeView !== 'connect'}>
@@ -1177,17 +1213,19 @@
11771213
<span class="i-material-symbols:chevron-right-rounded text-[22px]" />
11781214
</button>
11791215
{/if}
1180-
{#if lastActionText}
1181-
<div class="toast-line">{lastActionText}</div>
1182-
{/if}
1216+
11831217
</section>
11841218

11851219
<section class="content controller-content" class:controller-mode={true} class:hidden={activeView !== 'controller'}>
11861220
{#if canControl && selectedGame}
11871221
<section class="controller-panel">
1188-
<button type="button" class="back-button" on:click={() => (activeView = "library")}>
1189-
<span class="i-material-symbols:arrow-back-rounded text-[20px]" />
1190-
<span>一覧</span>
1222+
<button
1223+
type="button"
1224+
class="reconnect-small-button"
1225+
on:click={() => window.location.reload()}
1226+
>
1227+
<span class="i-material-symbols:refresh-rounded text-[15px]" />
1228+
<span>再接続</span>
11911229
</button>
11921230
<div class="controller-kicker">Now Playing</div>
11931231
<div class="controller-game">{selectedGame.title}</div>
@@ -1230,6 +1268,26 @@
12301268
<span>文字消しスクショ</span>
12311269
</button>
12321270

1271+
<section class="memo-preview">
1272+
<div class="section-head">
1273+
<h2>メモ</h2>
1274+
<span class="subtle">編集</span>
1275+
</div>
1276+
<div class="detail-memo-editor">
1277+
<textarea
1278+
bind:value={memoText}
1279+
placeholder="メモを入力"
1280+
/>
1281+
<button
1282+
type="button"
1283+
disabled={connectionState !== "connected" || selectedGameId === null}
1284+
on:click={syncMemo}
1285+
>
1286+
メモを同期
1287+
</button>
1288+
</div>
1289+
</section>
1290+
12331291
</section>
12341292
{:else}
12351293
<section class="empty-state controller-waiting">
@@ -1243,9 +1301,7 @@
12431301
{/if}
12441302
</section>
12451303
{/if}
1246-
{#if lastActionText}
1247-
<div class="toast-line">{lastActionText}</div>
1248-
{/if}
1304+
12491305
</section>
12501306

12511307
<nav class="bottom-nav" aria-label="スマホ連携">
@@ -1281,8 +1337,12 @@
12811337

12821338
<style>
12831339
.mobile-shell {
1284-
height: 100vh;
1285-
height: 100dvh;
1340+
position: fixed;
1341+
top: 0;
1342+
left: 0;
1343+
right: 0;
1344+
bottom: 0;
1345+
height: auto;
12861346
background: #151515;
12871347
color: white;
12881348
display: flex;
@@ -1293,8 +1353,8 @@
12931353
}
12941354
12951355
.topbar {
1296-
min-height: 64px;
1297-
padding: calc(14px + env(safe-area-inset-top, 0px)) 16px 12px;
1356+
min-height: 52px;
1357+
padding: calc(8px + env(safe-area-inset-top, 0px)) 16px 8px;
12981358
display: flex;
12991359
align-items: center;
13001360
justify-content: space-between;
@@ -1624,6 +1684,20 @@
16241684
font-weight: 700;
16251685
}
16261686
1687+
.reconnect-small-button {
1688+
display: inline-flex;
1689+
align-items: center;
1690+
gap: 4px;
1691+
border: 1px solid rgb(255 255 255 / 0.15);
1692+
border-radius: 4px;
1693+
background: rgb(255 255 255 / 0.05);
1694+
color: rgb(255 255 255 / 0.7);
1695+
padding: 3px 8px;
1696+
font-size: 11px;
1697+
font-weight: 800;
1698+
width: fit-content;
1699+
}
1700+
16271701
.detail-kicker,
16281702
.controller-kicker {
16291703
margin-top: 8px;

0 commit comments

Comments
 (0)