mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-28 06:22:45 -08:00
chore: archive refactor milestones and remove structural quality-gates task
- Remove structural quality gates task and references from task-27 roadmap. - Remove structural-gates-adjacent work from scripts/positioning cleanup context, including check-main-lines adjustments. - Archive completed backlog tasks 11 and 27.7 by moving them to completed directory. - Finish task-27.5 module split by moving/anonymizing anki-integration and renderer positioning files into their dedicated directories and updating paths.
This commit is contained in:
136
src/renderer/positioning/position-state.ts
Normal file
136
src/renderer/positioning/position-state.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import type { SubtitlePosition } from "../../types";
|
||||
import type { RendererContext } from "../context";
|
||||
|
||||
const PREFERRED_Y_PERCENT_MIN = 2;
|
||||
const PREFERRED_Y_PERCENT_MAX = 80;
|
||||
|
||||
export type SubtitlePositionController = {
|
||||
applyStoredSubtitlePosition: (position: SubtitlePosition | null, source: string) => void;
|
||||
getCurrentYPercent: () => number;
|
||||
applyYPercent: (yPercent: number) => void;
|
||||
persistSubtitlePositionPatch: (patch: Partial<SubtitlePosition>) => void;
|
||||
};
|
||||
|
||||
function clampYPercent(yPercent: number): number {
|
||||
return Math.max(PREFERRED_Y_PERCENT_MIN, Math.min(PREFERRED_Y_PERCENT_MAX, yPercent));
|
||||
}
|
||||
|
||||
function getPersistedYPercent(
|
||||
ctx: RendererContext,
|
||||
position: SubtitlePosition | null,
|
||||
): number {
|
||||
if (!position || typeof position.yPercent !== "number" || !Number.isFinite(position.yPercent)) {
|
||||
return ctx.state.persistedSubtitlePosition.yPercent;
|
||||
}
|
||||
|
||||
return position.yPercent;
|
||||
}
|
||||
|
||||
function getPersistedOffset(
|
||||
ctx: RendererContext,
|
||||
position: SubtitlePosition | null,
|
||||
key: "invisibleOffsetXPx" | "invisibleOffsetYPx",
|
||||
): number {
|
||||
if (
|
||||
position &&
|
||||
typeof position[key] === "number" &&
|
||||
Number.isFinite(position[key])
|
||||
) {
|
||||
return position[key];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function updatePersistedSubtitlePosition(
|
||||
ctx: RendererContext,
|
||||
position: SubtitlePosition | null,
|
||||
): void {
|
||||
ctx.state.persistedSubtitlePosition = {
|
||||
yPercent: getPersistedYPercent(ctx, position),
|
||||
invisibleOffsetXPx: getPersistedOffset(ctx, position, "invisibleOffsetXPx"),
|
||||
invisibleOffsetYPx: getPersistedOffset(ctx, position, "invisibleOffsetYPx"),
|
||||
};
|
||||
}
|
||||
|
||||
function getNextPersistedPosition(
|
||||
ctx: RendererContext,
|
||||
patch: Partial<SubtitlePosition>,
|
||||
): SubtitlePosition {
|
||||
return {
|
||||
yPercent:
|
||||
typeof patch.yPercent === "number" && Number.isFinite(patch.yPercent)
|
||||
? patch.yPercent
|
||||
: ctx.state.persistedSubtitlePosition.yPercent,
|
||||
invisibleOffsetXPx:
|
||||
typeof patch.invisibleOffsetXPx === "number" &&
|
||||
Number.isFinite(patch.invisibleOffsetXPx)
|
||||
? patch.invisibleOffsetXPx
|
||||
: ctx.state.persistedSubtitlePosition.invisibleOffsetXPx ?? 0,
|
||||
invisibleOffsetYPx:
|
||||
typeof patch.invisibleOffsetYPx === "number" &&
|
||||
Number.isFinite(patch.invisibleOffsetYPx)
|
||||
? patch.invisibleOffsetYPx
|
||||
: ctx.state.persistedSubtitlePosition.invisibleOffsetYPx ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
export function createInMemorySubtitlePositionController(
|
||||
ctx: RendererContext,
|
||||
): SubtitlePositionController {
|
||||
function getCurrentYPercent(): number {
|
||||
if (ctx.state.currentYPercent !== null) {
|
||||
return ctx.state.currentYPercent;
|
||||
}
|
||||
|
||||
const marginBottom = parseFloat(ctx.dom.subtitleContainer.style.marginBottom) || 60;
|
||||
ctx.state.currentYPercent = clampYPercent((marginBottom / window.innerHeight) * 100);
|
||||
return ctx.state.currentYPercent;
|
||||
}
|
||||
|
||||
function applyYPercent(yPercent: number): void {
|
||||
const clampedPercent = clampYPercent(yPercent);
|
||||
ctx.state.currentYPercent = clampedPercent;
|
||||
const marginBottom = (clampedPercent / 100) * window.innerHeight;
|
||||
|
||||
ctx.dom.subtitleContainer.style.position = "";
|
||||
ctx.dom.subtitleContainer.style.left = "";
|
||||
ctx.dom.subtitleContainer.style.top = "";
|
||||
ctx.dom.subtitleContainer.style.right = "";
|
||||
ctx.dom.subtitleContainer.style.transform = "";
|
||||
ctx.dom.subtitleContainer.style.marginBottom = `${marginBottom}px`;
|
||||
}
|
||||
|
||||
function persistSubtitlePositionPatch(patch: Partial<SubtitlePosition>): void {
|
||||
const nextPosition = getNextPersistedPosition(ctx, patch);
|
||||
ctx.state.persistedSubtitlePosition = nextPosition;
|
||||
window.electronAPI.saveSubtitlePosition(nextPosition);
|
||||
}
|
||||
|
||||
function applyStoredSubtitlePosition(position: SubtitlePosition | null, source: string): void {
|
||||
updatePersistedSubtitlePosition(ctx, position);
|
||||
if (position && position.yPercent !== undefined) {
|
||||
applyYPercent(position.yPercent);
|
||||
console.log(
|
||||
"Applied subtitle position from",
|
||||
source,
|
||||
":",
|
||||
position.yPercent,
|
||||
"%",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const defaultMarginBottom = 60;
|
||||
const defaultYPercent = (defaultMarginBottom / window.innerHeight) * 100;
|
||||
applyYPercent(defaultYPercent);
|
||||
console.log("Applied default subtitle position from", source);
|
||||
}
|
||||
|
||||
return {
|
||||
applyStoredSubtitlePosition,
|
||||
getCurrentYPercent,
|
||||
applyYPercent,
|
||||
persistSubtitlePositionPatch,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user