chore: initialize repository baseline
Import the existing Electron + React + TypeScript app as the version-control baseline before the scanner rework (C# input/capture sidecar, resolution-anchored layout profiles, OCR preprocessing, eval harness, rescan-merge, GOOD interop). Housekeeping in this commit: - Remove orphaned temp_inputhelper_block.ts (duplicate of the input-helper script). - Ignore .claude/scheduled_tasks.lock local session state. - Add .gitattributes to normalize line endings (LF in repo). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
import { useCallback, useMemo, useRef, useState } from "react";
|
||||
import { requiresAdminForAutomation } from "../../../lib/automationPlanner";
|
||||
import {
|
||||
countScannerLearningRules,
|
||||
type ScannerLearningRules,
|
||||
} from "../../../lib/scannerLearning";
|
||||
import { type ParsedArtifactCandidate } from "../../../lib/artifactOcrParser";
|
||||
import { analyzeReviewSamples } from "../../../lib/reviewSampleAnalysis";
|
||||
import {
|
||||
parseLearnedArtifact as parseLearnedArtifactHelper,
|
||||
} from "./scanViewReviewHelpers";
|
||||
import { useScanRuntimeInfo } from "./useScanRuntimeInfo";
|
||||
import { useScanSnapshotPublisher } from "./useScanSnapshotPublisher";
|
||||
import { useScanViewActions } from "./useScanViewActions";
|
||||
import { useScanViewStateSync } from "./useScanViewStateSync";
|
||||
import { emptyAutoScanStats, resolveScanTargetCount, type AutoScanStats, type ScanSummary } from "../../../lib/scannerSession";
|
||||
import type { ScanViewProps, ScanViewControllerResult } from "../types";
|
||||
import type { CaptureResult, ClickResult, ReviewSampleRecord } from "../../../types/global";
|
||||
import { createRendererRepositories } from "../../../infrastructure/repositories/rendererBridgeRepositories";
|
||||
|
||||
export function useScanViewController({
|
||||
snapshot,
|
||||
isScanning,
|
||||
captureSources,
|
||||
selectedSourceId,
|
||||
latestCapture,
|
||||
captureStatus,
|
||||
captureSelectedSource,
|
||||
bridgeReady,
|
||||
onStoredArtifactsChanged,
|
||||
}: ScanViewProps): ScanViewControllerResult {
|
||||
const repositories = useMemo(() => createRendererRepositories(), []);
|
||||
const artifactRepo = repositories?.artifacts;
|
||||
const runtimeRepo = repositories?.runtime;
|
||||
const reviewSamplesRepo = repositories?.reviewSamples;
|
||||
const learningRepo = repositories?.learning;
|
||||
const snapshotRepo = repositories?.snapshot;
|
||||
const automationRepo = repositories?.automation;
|
||||
const captureRepo = repositories?.capture;
|
||||
|
||||
const [detailsOpen, setDetailsOpen] = useState(false);
|
||||
const [diagnosticsOpen, setDiagnosticsOpen] = useState(false);
|
||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||
const [reviewQueueOpen, setReviewQueueOpen] = useState(false);
|
||||
const [reviewSamples, setReviewSamples] = useState<ReviewSampleRecord[]>([]);
|
||||
const [reviewSampleTotal, setReviewSampleTotal] = useState(0);
|
||||
const [reviewStatus, setReviewStatus] = useState("");
|
||||
const [autoScanRunning, setAutoScanRunning] = useState(false);
|
||||
const stopVisibleScanRef = useRef(false);
|
||||
const [autoScanStats, setAutoScanStats] = useState<AutoScanStats>(emptyAutoScanStats);
|
||||
const [scanSummary, setScanSummary] = useState<ScanSummary | null>(null);
|
||||
const [scanLimit, setScanLimit] = useState(16);
|
||||
const [scanLimitTouched, setScanLimitTouched] = useState(false);
|
||||
const [skipRows, setSkipRows] = useState(0);
|
||||
const [automationLog, setAutomationLog] = useState<string[]>([]);
|
||||
const [storedTotal, setStoredTotal] = useState<number | null>(null);
|
||||
const [devMode, setDevMode] = useState(() => localStorage.getItem("gaa-dev-mode") === "1");
|
||||
const [scannerLearningRules, setScannerLearningRules] = useState<ScannerLearningRules>({ textReplacements: {} });
|
||||
const [learningRulesLoaded, setLearningRulesLoaded] = useState(false);
|
||||
const runtimeInfo = useScanRuntimeInfo(runtimeRepo);
|
||||
|
||||
const parsedArtifact = useMemo(
|
||||
() => parseLearnedArtifactHelper(latestCapture, scannerLearningRules),
|
||||
[latestCapture, scannerLearningRules],
|
||||
);
|
||||
|
||||
const selectedSource = captureSources.find((source) => source.id === selectedSourceId);
|
||||
const genshinSource = captureSources.find((source) => source.isGenshinCandidate);
|
||||
const requiresAdminForAutoScan = requiresAdminForAutomation(runtimeInfo);
|
||||
const hasSourceSelected = selectedSourceId.length > 0;
|
||||
const canCaptureSource = bridgeReady && Boolean(captureRepo?.captureSource);
|
||||
const canReadReviewQueue = bridgeReady && Boolean(reviewSamplesRepo?.loadSamples);
|
||||
const canSaveReviewSample = bridgeReady && Boolean(reviewSamplesRepo?.saveSample);
|
||||
const canAutoScan = bridgeReady && Boolean(automationRepo?.clickScreen) && Boolean(automationRepo?.scrollScreen);
|
||||
const reviewAnalysis = useMemo(() => analyzeReviewSamples(reviewSamples), [reviewSamples]);
|
||||
const learningRuleCount = countScannerLearningRules(scannerLearningRules);
|
||||
const detectedInventoryCount = latestCapture?.inventoryCount?.current ?? 0;
|
||||
const activeTargetCount = autoScanRunning
|
||||
? resolveScanTargetCount(scanLimit, detectedInventoryCount)
|
||||
: scanSummary?.targetCount ?? resolveScanTargetCount(scanLimit, detectedInventoryCount);
|
||||
const scanProgressBase = Math.max(autoScanStats.attempted, autoScanStats.parsed, autoScanStats.verified);
|
||||
const scanProgressPercent = Math.min(100, Math.round((scanProgressBase / Math.max(1, activeTargetCount)) * 100));
|
||||
const scannerModeLabel = autoScanRunning ? "Scan laeuft" : runtimeInfo?.isElevated ? "Admin bereit" : "Bereit";
|
||||
const sourceLabel = selectedSource?.name ?? "Keine Quelle";
|
||||
const gridLabel = latestCapture?.inventoryGrid ? `${latestCapture.inventoryGrid.cols} x ${latestCapture.inventoryGrid.rows}` : "warte auf Capture";
|
||||
const inventoryLabel = latestCapture?.inventoryCount?.current ? `${latestCapture.inventoryCount.current}/${latestCapture.inventoryCount.total || "?"}` : "nicht erkannt";
|
||||
|
||||
const appendAutomationLog = useCallback((line: string) => {
|
||||
setAutomationLog((previous) => [...previous.slice(-11), `${new Date().toLocaleTimeString()} ${line}`]);
|
||||
}, []);
|
||||
|
||||
const appendClickDiagnostics = useCallback((result: ClickResult, prefix = "input") => {
|
||||
const cursor = `${result.cursorX ?? "?"},${result.cursorY ?? "?"}`;
|
||||
const focus = result.focused ? `fg:${result.foregroundProcess || "Genshin"}` : `fg-miss:${result.foregroundProcess || "?"}`;
|
||||
const blocked = result.inputBlocked ? " input:blocked" : "";
|
||||
appendAutomationLog(`${prefix}: ${focus}${blocked} cursor ${cursor} moved:${result.moved ? "yes" : "no"} clicked:${result.clicked ? "yes" : "no"}`);
|
||||
}, [appendAutomationLog]);
|
||||
|
||||
const toggleDevMode = useCallback(() => {
|
||||
setDevMode((previous) => {
|
||||
const next = !previous;
|
||||
localStorage.setItem("gaa-dev-mode", next ? "1" : "0");
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const parseArtifact = useCallback(
|
||||
(capture: CaptureResult | null) => parseLearnedArtifactHelper(capture, scannerLearningRules),
|
||||
[scannerLearningRules],
|
||||
);
|
||||
|
||||
const {
|
||||
requestScanStop,
|
||||
saveReviewSample: handleSaveReviewSample,
|
||||
loadReviewQueue: loadReviewQueueAction,
|
||||
openReviewQueue: openReviewQueueModal,
|
||||
runAutoReviewScan,
|
||||
runVisibleGridScan,
|
||||
} = useScanViewActions({
|
||||
autoScanRunning,
|
||||
setAutoScanRunning,
|
||||
isScanning,
|
||||
stopVisibleScanRef,
|
||||
selectedSourceId,
|
||||
bridgeReady,
|
||||
automationRepo,
|
||||
runtimeInfo,
|
||||
runtimeRepo,
|
||||
scanLimit,
|
||||
skipRows,
|
||||
detectedInventoryCount,
|
||||
setScanSummary,
|
||||
setAutoScanStats,
|
||||
setReviewStatus,
|
||||
appendAutomationLog,
|
||||
appendClickDiagnostics,
|
||||
parseArtifact,
|
||||
artifactRepo,
|
||||
reviewSamplesRepo,
|
||||
learningRepo,
|
||||
onStoredArtifactsChanged,
|
||||
setReviewSampleTotal,
|
||||
setReviewSamples,
|
||||
setLearningRulesLoaded,
|
||||
setScannerLearningRules,
|
||||
setStoredTotal,
|
||||
scannerLearningRules,
|
||||
captureSelectedSource,
|
||||
latestCapture,
|
||||
parsedArtifact,
|
||||
canCaptureSource,
|
||||
setReviewQueueOpen,
|
||||
});
|
||||
|
||||
useScanViewStateSync({
|
||||
artifactRepo,
|
||||
latestCapture,
|
||||
scanLimitTouched,
|
||||
setScanLimit,
|
||||
setStoredTotal,
|
||||
});
|
||||
|
||||
useScanSnapshotPublisher({
|
||||
autoScanRunning,
|
||||
reviewStatus,
|
||||
captureStatus,
|
||||
selectedSourceName: selectedSource?.name ?? null,
|
||||
autoScanStats,
|
||||
scanSummary,
|
||||
snapshot,
|
||||
latestInventoryGrid: latestCapture?.inventoryGrid ?? null,
|
||||
automationLog,
|
||||
runtimeInfo,
|
||||
storedTotal,
|
||||
learningRuleCount,
|
||||
snapshotRepo,
|
||||
});
|
||||
|
||||
return {
|
||||
detailsOpen,
|
||||
diagnosticsOpen,
|
||||
settingsOpen,
|
||||
reviewQueueOpen,
|
||||
reviewSamples,
|
||||
reviewSampleTotal,
|
||||
reviewStatus,
|
||||
autoScanRunning,
|
||||
autoScanStats,
|
||||
scanSummary,
|
||||
scanLimit,
|
||||
scanLimitTouched,
|
||||
skipRows,
|
||||
automationLog,
|
||||
storedTotal,
|
||||
devMode,
|
||||
scannerLearningRules,
|
||||
learningRulesLoaded,
|
||||
runtimeInfo,
|
||||
parsedArtifact,
|
||||
reviewAnalysis,
|
||||
learningRuleCount,
|
||||
detectedInventoryCount,
|
||||
scanProgressPercent,
|
||||
activeTargetCount,
|
||||
requiresAdminForAutoScan,
|
||||
hasSourceSelected,
|
||||
canCaptureSource,
|
||||
canReadReviewQueue,
|
||||
canSaveReviewSample,
|
||||
canAutoScan,
|
||||
scannerModeLabel,
|
||||
sourceLabel,
|
||||
gridLabel,
|
||||
inventoryLabel,
|
||||
selectedSource,
|
||||
genshinSource,
|
||||
setDetailsOpen,
|
||||
setDiagnosticsOpen,
|
||||
setSettingsOpen,
|
||||
setReviewQueueOpen,
|
||||
setScanSummary,
|
||||
setScanLimit,
|
||||
setScanLimitTouched,
|
||||
setSkipRows,
|
||||
toggleDevMode,
|
||||
requestScanStop,
|
||||
saveReviewSample: handleSaveReviewSample,
|
||||
loadReviewQueue: loadReviewQueueAction,
|
||||
openReviewQueue: openReviewQueueModal,
|
||||
runAutoReviewScan,
|
||||
runVisibleGridScan,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user