mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-23 19:46:28 -05:00
Only show ungrouped events as fallback
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* One light line summarizing a scan's raw detections as per-type counts,
|
||||
* with a toggle for the full event card feed — the matches are the main
|
||||
* view, the events stay one click away.
|
||||
* One light line summarizing raw detections as per-type counts, with a
|
||||
* toggle for their event card feed. Callers pass only events not covered
|
||||
* by a match card — a fallback for detections not yet grouped, hidden
|
||||
* entirely once everything lives in a match.
|
||||
*/
|
||||
|
||||
import { DEATH_EVENT_TYPE } from "../core/detectors/death/index";
|
||||
|
||||
@@ -207,6 +207,10 @@ export function LivePage({
|
||||
}
|
||||
}, [deviceId, refreshFeed, send]);
|
||||
|
||||
const builtMatches = buildScannerMatches(feed);
|
||||
const groupedEvents = new Set(builtMatches.flatMap((b) => b.sources));
|
||||
const ungroupedFeed = feed.filter((e) => !groupedEvents.has(e));
|
||||
|
||||
const stop = useCallback(() => {
|
||||
stopRef.current?.();
|
||||
stopRef.current = null;
|
||||
@@ -314,55 +318,53 @@ export function LivePage({
|
||||
{feed.length === 0 ? (
|
||||
<p className="score">No detections yet.</p>
|
||||
) : null}
|
||||
{[...buildScannerMatches(feed)]
|
||||
.reverse()
|
||||
.map((built, reverseIndex) => {
|
||||
const id = built.sources[0]!.id!;
|
||||
const ingestable = isIngestableMatch(built.match);
|
||||
return (
|
||||
<MatchCard
|
||||
key={id}
|
||||
match={built.match}
|
||||
live={
|
||||
running && reverseIndex === 0 && built.match.winner === null
|
||||
}
|
||||
inProgress={reverseIndex === 0 && built.match.winner === null}
|
||||
ingestable={ingestable}
|
||||
send={aggregateSendStatus(built.sources)}
|
||||
onSend={
|
||||
SENDOU_UPLOAD_ENABLED && sendouUser && ingestable
|
||||
? () => void send(matchContaining(id), { manual: true })
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{withoutRepeatEvents(built.sources).map((e) => (
|
||||
<EventCard
|
||||
key={e.id}
|
||||
type={e.type}
|
||||
t={e.t}
|
||||
confidence={e.confidence}
|
||||
data={e.data as FixtureData}
|
||||
thumbnail={e.thumbnail}
|
||||
detectedAt={e.detectedAt}
|
||||
getFrame={
|
||||
e.hasFrame && e.id !== undefined
|
||||
? () => loadEventFrame(e.id!)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</MatchCard>
|
||||
);
|
||||
})}
|
||||
{feed.length > 0 ? (
|
||||
{[...builtMatches].reverse().map((built, reverseIndex) => {
|
||||
const id = built.sources[0]!.id!;
|
||||
const ingestable = isIngestableMatch(built.match);
|
||||
return (
|
||||
<MatchCard
|
||||
key={id}
|
||||
match={built.match}
|
||||
live={
|
||||
running && reverseIndex === 0 && built.match.winner === null
|
||||
}
|
||||
inProgress={reverseIndex === 0 && built.match.winner === null}
|
||||
ingestable={ingestable}
|
||||
send={aggregateSendStatus(built.sources)}
|
||||
onSend={
|
||||
SENDOU_UPLOAD_ENABLED && sendouUser && ingestable
|
||||
? () => void send(matchContaining(id), { manual: true })
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{withoutRepeatEvents(built.sources).map((e) => (
|
||||
<EventCard
|
||||
key={e.id}
|
||||
type={e.type}
|
||||
t={e.t}
|
||||
confidence={e.confidence}
|
||||
data={e.data as FixtureData}
|
||||
thumbnail={e.thumbnail}
|
||||
detectedAt={e.detectedAt}
|
||||
getFrame={
|
||||
e.hasFrame && e.id !== undefined
|
||||
? () => loadEventFrame(e.id!)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</MatchCard>
|
||||
);
|
||||
})}
|
||||
{ungroupedFeed.length > 0 ? (
|
||||
<EventsSummary
|
||||
events={feed}
|
||||
events={ungroupedFeed}
|
||||
open={eventsOpen}
|
||||
onToggle={() => setEventsOpen(!eventsOpen)}
|
||||
/>
|
||||
) : null}
|
||||
{eventsOpen
|
||||
? feed.map((e) => (
|
||||
? ungroupedFeed.map((e) => (
|
||||
<EventCard
|
||||
key={e.id}
|
||||
type={e.type}
|
||||
|
||||
@@ -132,6 +132,8 @@ export function VodPage({
|
||||
|
||||
const builtMatches = buildScannerMatches(matches.map((m) => m.event));
|
||||
const vodMatchByEvent = new Map(matches.map((m) => [m.event, m] as const));
|
||||
const groupedEvents = new Set(builtMatches.flatMap((b) => b.sources));
|
||||
const ungroupedMatches = matches.filter((m) => !groupedEvents.has(m.event));
|
||||
|
||||
// "Upload as results" sends the whole scan in one go, so its outcome maps
|
||||
// onto every ingestable card; a partial failure (some chunks sent, some
|
||||
@@ -607,20 +609,20 @@ export function VodPage({
|
||||
</MatchCard>
|
||||
);
|
||||
})}
|
||||
{matches.length > 0 ? (
|
||||
{ungroupedMatches.length > 0 ? (
|
||||
<EventsSummary
|
||||
events={matches.map((m) => m.event)}
|
||||
events={ungroupedMatches.map((m) => m.event)}
|
||||
open={eventsOpen}
|
||||
onToggle={() => setEventsOpen(!eventsOpen)}
|
||||
/>
|
||||
) : null}
|
||||
{/* newest detection on top; storage keeps ascending video-time order */}
|
||||
{eventsOpen
|
||||
? [...matches]
|
||||
? [...ungroupedMatches]
|
||||
.reverse()
|
||||
.map((m, i) => (
|
||||
<EventCard
|
||||
key={matches.length - 1 - i}
|
||||
key={ungroupedMatches.length - 1 - i}
|
||||
type={m.event.type}
|
||||
t={m.event.t}
|
||||
confidence={m.event.confidence}
|
||||
|
||||
@@ -124,22 +124,6 @@ export function updateEventsSend(
|
||||
);
|
||||
}
|
||||
|
||||
export function deleteEvent(id: number): Promise<void> {
|
||||
return db().then(
|
||||
(database) =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
const transaction = database.transaction(
|
||||
[EVENTS_STORE, FRAMES_STORE],
|
||||
"readwrite",
|
||||
);
|
||||
transaction.objectStore(EVENTS_STORE).delete(id);
|
||||
transaction.objectStore(FRAMES_STORE).delete(id);
|
||||
transaction.oncomplete = () => resolve();
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function listEvents(): Promise<StoredEvent[]> {
|
||||
return tx(
|
||||
EVENTS_STORE,
|
||||
|
||||
Reference in New Issue
Block a user