mirror of
https://github.com/stashapp/stash.git
synced 2025-12-10 02:15:30 +01:00
Marker time input (#242)
* Use duration input for marker time * Allow reset to current time * Validate input
This commit is contained in:
parent
85935f022a
commit
fe7bf59906
2 changed files with 135 additions and 11 deletions
127
ui/v2/src/components/Shared/DurationInput.tsx
Normal file
127
ui/v2/src/components/Shared/DurationInput.tsx
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
import React, { FunctionComponent, useState, useEffect } from "react";
|
||||
import { InputGroup, ButtonGroup, Button, IInputGroupProps, HTMLInputProps, ControlGroup } from "@blueprintjs/core";
|
||||
import { TextUtils } from "../../utils/text";
|
||||
import { FIXED, NUMERIC_INPUT } from "@blueprintjs/core/lib/esm/common/classes";
|
||||
|
||||
interface IProps {
|
||||
disabled?: boolean
|
||||
numericValue: number
|
||||
onValueChange(valueAsNumber: number): void
|
||||
onReset?(): void
|
||||
}
|
||||
|
||||
export const DurationInput: FunctionComponent<HTMLInputProps & IProps> = (props: IProps) => {
|
||||
const [value, setValue] = useState<string>(secondsToString(props.numericValue));
|
||||
|
||||
useEffect(() => {
|
||||
setValue(secondsToString(props.numericValue));
|
||||
}, [props.numericValue]);
|
||||
|
||||
function secondsToString(seconds : number) {
|
||||
let ret = TextUtils.secondsToTimestamp(seconds);
|
||||
|
||||
if (ret.startsWith("00:")) {
|
||||
ret = ret.substr(3);
|
||||
|
||||
if (ret.startsWith("0")) {
|
||||
ret = ret.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function stringToSeconds(v : string) {
|
||||
if (!v) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let splits = v.split(":");
|
||||
|
||||
if (splits.length > 3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let seconds = 0;
|
||||
let factor = 1;
|
||||
while(splits.length > 0) {
|
||||
let thisSplit = splits.pop();
|
||||
if (thisSplit == undefined) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let thisInt = parseInt(thisSplit, 10);
|
||||
if (isNaN(thisInt)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
seconds += factor * thisInt;
|
||||
factor *= 60;
|
||||
}
|
||||
|
||||
return seconds;
|
||||
}
|
||||
|
||||
function increment() {
|
||||
let seconds = stringToSeconds(value);
|
||||
seconds += 1;
|
||||
props.onValueChange(seconds);
|
||||
}
|
||||
|
||||
function decrement() {
|
||||
let seconds = stringToSeconds(value);
|
||||
seconds -= 1;
|
||||
props.onValueChange(seconds);
|
||||
}
|
||||
|
||||
function renderButtons() {
|
||||
return (
|
||||
<ButtonGroup
|
||||
vertical={true}
|
||||
className={FIXED}
|
||||
>
|
||||
<Button
|
||||
icon="chevron-up"
|
||||
disabled={props.disabled}
|
||||
onClick={() => increment()}
|
||||
/>
|
||||
<Button
|
||||
icon="chevron-down"
|
||||
disabled={props.disabled}
|
||||
onClick={() => decrement()}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
)
|
||||
}
|
||||
|
||||
function onReset() {
|
||||
if (props.onReset) {
|
||||
props.onReset();
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderReset() {
|
||||
if (props.onReset) {
|
||||
return (
|
||||
<Button
|
||||
icon="time"
|
||||
onClick={() => onReset()}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ControlGroup className={NUMERIC_INPUT}>
|
||||
<InputGroup
|
||||
disabled={props.disabled}
|
||||
value={value}
|
||||
onChange={(e : any) => setValue(e.target.value)}
|
||||
onBlur={() => props.onValueChange(stringToSeconds(value))}
|
||||
placeholder="hh:mm:ss"
|
||||
rightElement={maybeRenderReset()}
|
||||
/>
|
||||
{renderButtons()}
|
||||
</ControlGroup>
|
||||
)
|
||||
};
|
||||
|
|
@ -19,6 +19,7 @@ import { MarkerTitleSuggest } from "../../select/MarkerTitleSuggest";
|
|||
import { WallPanel } from "../../Wall/WallPanel";
|
||||
import { SceneHelpers } from "../helpers";
|
||||
import { ErrorUtils } from "../../../utils/errors";
|
||||
import { DurationInput } from "../../Shared/DurationInput";
|
||||
|
||||
interface ISceneMarkersPanelProps {
|
||||
scene: GQL.SceneDataFragment;
|
||||
|
|
@ -148,14 +149,10 @@ export const SceneMarkersPanel: FunctionComponent<ISceneMarkersPanelProps> = (pr
|
|||
}
|
||||
function renderSecondsField(fieldProps: FieldProps<IFormFields>) {
|
||||
return (
|
||||
<NumericInput
|
||||
placeholder="Seconds"
|
||||
fill={true}
|
||||
allowNumericCharactersOnly={true}
|
||||
name={fieldProps.field.name}
|
||||
onValueChange={(_, s) => fieldProps.form.setFieldValue("seconds", s)}
|
||||
onBlur={fieldProps.field.onBlur}
|
||||
value={fieldProps.field.value}
|
||||
<DurationInput
|
||||
onValueChange={(s) => fieldProps.form.setFieldValue("seconds", s)}
|
||||
onReset={() => fieldProps.form.setFieldValue("seconds", Math.round(jwplayer.getPosition()))}
|
||||
numericValue={fieldProps.field.value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -197,7 +194,7 @@ export const SceneMarkersPanel: FunctionComponent<ISceneMarkersPanelProps> = (pr
|
|||
<FormGroup label="Scene Marker Title" labelFor="title" className="column is-full">
|
||||
<Field name="title" render={renderTitleField} />
|
||||
</FormGroup>
|
||||
<FormGroup label="Seconds" labelFor="seconds" className="column is-half">
|
||||
<FormGroup label="Time" labelFor="seconds" className="column is-half">
|
||||
<Field name="seconds" render={renderSecondsField} />
|
||||
</FormGroup>
|
||||
<FormGroup label="Primary Tag" labelFor="primaryTagId" className="column is-half">
|
||||
|
|
@ -228,11 +225,11 @@ export const SceneMarkersPanel: FunctionComponent<ISceneMarkersPanelProps> = (pr
|
|||
}
|
||||
return (
|
||||
<Collapse isOpen={isEditorOpen}>
|
||||
<Formik
|
||||
{isEditorOpen ? <Formik
|
||||
initialValues={initialValues}
|
||||
onSubmit={onSubmit}
|
||||
render={renderFormFields}
|
||||
/>
|
||||
/> : undefined}
|
||||
</Collapse>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue