Skip to content

Commit

Permalink
Add O-counter (stashapp#334)
Browse files Browse the repository at this point in the history
  • Loading branch information
Infinite committed Mar 1, 2020
1 parent f23247d commit e6d9d38
Show file tree
Hide file tree
Showing 11 changed files with 369 additions and 11 deletions.
19 changes: 17 additions & 2 deletions ui/v2.5/src/components/Scenes/SceneCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cx from "classnames";
import * as GQL from "src/core/generated-graphql";
import { StashService } from "src/core/StashService";
import { VideoHoverHook } from "src/hooks";
import { Icon, TagLink, HoverPopover } from "src/components/Shared";
import { Icon, TagLink, HoverPopover, SweatDrops } from "src/components/Shared";
import { TextUtils } from "src/utils";

interface ISceneCardProps {
Expand Down Expand Up @@ -135,11 +135,25 @@ export const SceneCard: React.FC<ISceneCardProps> = (
);
}

function maybeRenderOCounter() {
if (props.scene.o_counter) {
return (
<div>
<Button className="minimal">
<SweatDrops />
<span>{props.scene.o_counter}</span>
</Button>
</div>
)
}
}

function maybeRenderPopoverButtonGroup() {
if (
props.scene.tags.length > 0 ||
props.scene.performers.length > 0 ||
props.scene.scene_markers.length > 0
props.scene.scene_markers.length > 0 ||
props.scene?.o_counter
) {
return (
<>
Expand All @@ -148,6 +162,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
{maybeRenderTagPopoverButton()}
{maybeRenderPerformerPopoverButton()}
{maybeRenderSceneMarkerPopoverButton()}
{maybeRenderOCounter()}
</ButtonGroup>
</>
);
Expand Down
67 changes: 67 additions & 0 deletions ui/v2.5/src/components/Scenes/SceneDetails/OCounterButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from "react";
import { Button, Spinner } from 'react-bootstrap';
import { Icon, HoverPopover, SweatDrops } from 'src/components/Shared';

export interface IOCounterButtonProps {
loading: boolean
value: number
onIncrement: () => void
onDecrement: () => void
onReset: () => void
onMenuOpened?: () => void
onMenuClosed?: () => void
}

export const OCounterButton: React.FC<IOCounterButtonProps> = (props: IOCounterButtonProps) => {
if(props.loading)
return <Spinner animation="border" role="status" />;

const renderButton = () => (
<Button
className="minimal"
onClick={props.onIncrement}
variant="secondary"
>
<SweatDrops />
<span className="ml-2">{props.value}</span>
</Button>
);

if (props.value) {
return (
<HoverPopover
content={
<div>
<div>
<Button
className="minimal"
onClick={props.onDecrement}
variant="secondary"
>
<Icon icon="minus" />
<span>Decrement</span>
</Button>
</div>
<div>
<Button
className="minimal"
onClick={props.onReset}
variant="secondary"
>
<Icon icon="ban" />
<span>Reset</span>
</Button>
</div>
</div>
}
enterDelay={1000}
placement="bottom"
onOpen={props.onMenuOpened}
onClose={props.onMenuClosed}
>
{ renderButton() }
</HoverPopover>
);
}
return renderButton();
}
61 changes: 61 additions & 0 deletions ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,27 @@ import * as GQL from "src/core/generated-graphql";
import { StashService } from "src/core/StashService";
import { GalleryViewer } from "src/components/Galleries/GalleryViewer";
import { LoadingIndicator } from "src/components/Shared";
import { useToast } from 'src/hooks';
import { ScenePlayer } from "src/components/ScenePlayer";
import { ScenePerformerPanel } from "./ScenePerformerPanel";
import { SceneMarkersPanel } from "./SceneMarkersPanel";
import { SceneFileInfoPanel } from "./SceneFileInfoPanel";
import { SceneEditPanel } from "./SceneEditPanel";
import { SceneDetailPanel } from "./SceneDetailPanel";
import { OCounterButton } from './OCounterButton';

export const Scene: React.FC = () => {
const { id = "new" } = useParams();
const location = useLocation();
const history = useHistory();
const Toast = useToast();
const [timestamp, setTimestamp] = useState<number>(getInitialTimestamp());
const [scene, setScene] = useState<GQL.SceneDataFragment | undefined>();
const { data, error, loading } = StashService.useFindScene(id);
const [oLoading, setOLoading] = useState(false);
const [incrementO] = StashService.useSceneIncrementO(scene?.id ?? "0");
const [decrementO] = StashService.useSceneDecrementO(scene?.id ?? "0");
const [resetO] = StashService.useSceneResetO(scene?.id ?? "0");

const queryParams = queryString.parse(location.search);
const autoplay = queryParams?.autoplay === "true";
Expand All @@ -37,6 +44,51 @@ export const Scene: React.FC = () => {
);
}

const updateOCounter = (newValue: number) => {
const modifiedScene = { ...scene } as GQL.SceneDataFragment;
modifiedScene.o_counter = newValue;
setScene(modifiedScene);
}

const onIncrementClick = async () => {
try {
setOLoading(true);
const result = await incrementO();
if(result.data)
updateOCounter(result.data.sceneIncrementO);
} catch (e) {
Toast.error(e);
} finally {
setOLoading(false);
}
}

const onDecrementClick = async () => {
try {
setOLoading(true);
const result = await decrementO();
if(result.data)
updateOCounter(result.data.sceneDecrementO);
} catch (e) {
Toast.error(e);
} finally {
setOLoading(false);
}
}

const onResetClick = async () => {
try {
setOLoading(true);
const result = await resetO();
if(result.data)
updateOCounter(result.data.sceneResetO);
} catch (e) {
Toast.error(e);
} finally {
setOLoading(false);
}
}

function onClickMarker(marker: GQL.SceneMarkerDataFragment) {
setTimestamp(marker.seconds);
}
Expand All @@ -51,6 +103,15 @@ export const Scene: React.FC = () => {
<>
<ScenePlayer scene={scene} timestamp={timestamp} autoplay={autoplay} />
<div id="scene-details-container" className="col col-sm-9 m-sm-auto">
<div className="float-right">
<OCounterButton
loading={oLoading}
value={scene.o_counter || 0}
onIncrement={onIncrementClick}
onDecrement={onDecrementClick}
onReset={onResetClick}
/>
</div>
<Tabs id="scene-tabs" mountOnEnter>
<Tab eventKey="scene-details-panel" title="Details">
<SceneDetailPanel scene={scene} />
Expand Down
20 changes: 15 additions & 5 deletions ui/v2.5/src/components/Shared/HoverPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ interface IHoverPopover {
content: JSX.Element[] | JSX.Element | string;
className?: string;
placement?: OverlayProps["placement"];
onOpen?: () => void;
onClose?: () => void;
}

export const HoverPopover: React.FC<IHoverPopover> = ({
Expand All @@ -15,7 +17,9 @@ export const HoverPopover: React.FC<IHoverPopover> = ({
content,
children,
className,
placement = "top"
placement = "top",
onOpen,
onClose
}) => {
const [show, setShow] = useState(false);
const triggerRef = useRef<HTMLDivElement>(null);
Expand All @@ -24,13 +28,19 @@ export const HoverPopover: React.FC<IHoverPopover> = ({

const handleMouseEnter = useCallback(() => {
window.clearTimeout(leaveTimer.current);
enterTimer.current = window.setTimeout(() => setShow(true), enterDelay);
}, [enterDelay]);
enterTimer.current = window.setTimeout(() => {
setShow(true)
onOpen?.();
}, enterDelay);
}, [enterDelay, onOpen]);

const handleMouseLeave = useCallback(() => {
window.clearTimeout(enterTimer.current);
leaveTimer.current = window.setTimeout(() => setShow(false), leaveDelay);
}, [leaveDelay]);
leaveTimer.current = window.setTimeout(() => {
setShow(false)
onClose?.();
}, leaveDelay);
}, [leaveDelay, onClose]);

useEffect(
() => () => {
Expand Down
10 changes: 10 additions & 0 deletions ui/v2.5/src/components/Shared/SweatDrops.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';

export const SweatDrops = () => (
<span>
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="1em" height="1em" style={{transform: "rotate(360deg)"}} preserveAspectRatio="xMidYMid meet" viewBox="0 0 36 36">
<path fill="currentColor" d="M22.855.758L7.875 7.024l12.537 9.733c2.633 2.224 6.377 2.937 9.77 1.518c4.826-2.018 7.096-7.576 5.072-12.413C33.232 1.024 27.68-1.261 22.855.758zm-9.962 17.924L2.05 10.284L.137 23.529a7.993 7.993 0 0 0 2.958 7.803a8.001 8.001 0 0 0 9.798-12.65zm15.339 7.015l-8.156-4.69l-.033 9.223c-.088 2 .904 3.98 2.75 5.041a5.462 5.462 0 0 0 7.479-2.051c1.499-2.644.589-6.013-2.04-7.523z" />
<rect x="0" y="0" width="36" height="36" fill="rgba(0, 0, 0, 0)" />
</svg>
</span>
);
1 change: 1 addition & 0 deletions ui/v2.5/src/components/Shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export { TagLink } from "./TagLink";
export { HoverPopover } from "./HoverPopover";
export { default as LoadingIndicator } from "./LoadingIndicator";
export { ImageInput } from "./ImageInput";
export { SweatDrops } from './SweatDrops';
18 changes: 18 additions & 0 deletions ui/v2.5/src/core/StashService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,24 @@ export class StashService {
return GQL.useScenesUpdateMutation({ variables: { input } });
}

public static useSceneIncrementO(id: string) {
return GQL.useSceneIncrementOMutation({
variables: {id}
});
}

public static useSceneDecrementO(id: string) {
return GQL.useSceneDecrementOMutation({
variables: {id}
});
}

public static useSceneResetO(id: string) {
return GQL.useSceneResetOMutation({
variables: {id}
});
}

public static useSceneDestroy(input: GQL.SceneDestroyInput) {
return GQL.useSceneDestroyMutation({
variables: input,
Expand Down
Loading

0 comments on commit e6d9d38

Please sign in to comment.