diff --git a/ui/v2/src/components/list/ListFilter.tsx b/ui/v2/src/components/list/ListFilter.tsx index 62b8ff029..9524ea896 100644 --- a/ui/v2/src/components/list/ListFilter.tsx +++ b/ui/v2/src/components/list/ListFilter.tsx @@ -1,8 +1,6 @@ import { - AnchorButton, Button, ButtonGroup, - ControlGroup, HTMLSelect, InputGroup, Menu, @@ -13,12 +11,17 @@ import { Slider, } from "@blueprintjs/core"; import { debounce } from "lodash"; -import React, { FunctionComponent, SyntheticEvent, useEffect, useRef, useState } from "react"; +import React, { FunctionComponent, SyntheticEvent, useEffect, useState } from "react"; import { Criterion } from "../../models/list-filter/criteria/criterion"; import { ListFilterModel } from "../../models/list-filter/filter"; import { DisplayMode } from "../../models/list-filter/types"; import { AddFilter } from "./AddFilter"; +interface IListFilterOperation { + text: string; + onClick: () => void; +} + interface IListFilterProps { onChangePageSize: (pageSize: number) => void; onChangeQuery: (query: string) => void; @@ -31,6 +34,7 @@ interface IListFilterProps { onChangeZoom?: (zoomIndex: number) => void; onSelectAll?: () => void; onSelectNone?: () => void; + otherOperations?: IListFilterOperation[]; filter: ListFilterModel; } @@ -169,6 +173,13 @@ export const ListFilter: FunctionComponent = (props: IListFilt let options = []; options.push(renderSelectAll()); options.push(renderSelectNone()); + + if (props.otherOperations) { + props.otherOperations.forEach((o) => { + options.push(); + }); + } + options = options.filter((o) => !!o); let menuItems = options as JSX.Element[]; diff --git a/ui/v2/src/components/scenes/SceneDetails/Scene.tsx b/ui/v2/src/components/scenes/SceneDetails/Scene.tsx index b2ba64b10..38a9b5f55 100644 --- a/ui/v2/src/components/scenes/SceneDetails/Scene.tsx +++ b/ui/v2/src/components/scenes/SceneDetails/Scene.tsx @@ -21,6 +21,7 @@ interface ISceneProps extends IBaseProps {} export const Scene: FunctionComponent = (props: ISceneProps) => { const [timestamp, setTimestamp] = useState(0); + const [autoplay, setAutoplay] = useState(false); const [scene, setScene] = useState>({}); const [isLoading, setIsLoading] = useState(false); const { data, error, loading } = StashService.useFindScene(props.match.params.id); @@ -37,6 +38,9 @@ export const Scene: FunctionComponent = (props: ISceneProps) => { const newTimestamp = parseInt(queryParams.t, 10); setTimestamp(newTimestamp); } + if (queryParams.autoplay && typeof queryParams.autoplay === "string") { + setAutoplay(queryParams.autoplay === "true"); + } }); function onClickMarker(marker: GQL.SceneMarkerDataFragment) { @@ -52,7 +56,7 @@ export const Scene: FunctionComponent = (props: ISceneProps) => { return ( <> - + = (props: ISceneListProps) => { + const otherOperations = [ + { + text: "Play Random", + onClick: playRandom, + } + ]; + const listData = ListHook.useList({ filterMode: FilterMode.Scenes, props, zoomable: true, + otherOperations: otherOperations, renderContent, renderSelectedOptions }); + async function playRandom(result: QueryHookResult, filter: ListFilterModel, selectedIds: Set) { + // query for a random scene + if (result.data && result.data.findScenes) { + let count = result.data.findScenes.count; + + let index = Math.floor(Math.random() * count); + let filterCopy = _.cloneDeep(filter); + filterCopy.itemsPerPage = 1; + filterCopy.currentPage = index + 1; + const singleResult = await StashService.queryFindScenes(filterCopy); + if (singleResult && singleResult.data && singleResult.data.findScenes && singleResult.data.findScenes.scenes.length === 1) { + let id = singleResult!.data!.findScenes!.scenes[0].id; + // navigate to the scene player page + props.history.push("/scenes/" + id + "?autoplay=true"); + } + } + } + function renderSelectedOptions(result: QueryHookResult, selectedIds: Set) { // find the selected items from the ids if (!result.data || !result.data.findScenes) { return undefined; } diff --git a/ui/v2/src/components/scenes/SceneMarkerList.tsx b/ui/v2/src/components/scenes/SceneMarkerList.tsx index 932a3bab2..c865f9d08 100644 --- a/ui/v2/src/components/scenes/SceneMarkerList.tsx +++ b/ui/v2/src/components/scenes/SceneMarkerList.tsx @@ -7,16 +7,44 @@ import { IBaseProps } from "../../models/base-props"; import { ListFilterModel } from "../../models/list-filter/filter"; import { DisplayMode, FilterMode } from "../../models/list-filter/types"; import { WallPanel } from "../Wall/WallPanel"; +import { StashService } from "../../core/StashService"; +import { NavigationUtils } from "../../utils/navigation"; interface IProps extends IBaseProps {} export const SceneMarkerList: FunctionComponent = (props: IProps) => { + const otherOperations = [ + { + text: "Play Random", + onClick: playRandom, + } + ]; + const listData = ListHook.useList({ filterMode: FilterMode.SceneMarkers, + otherOperations: otherOperations, props, renderContent, }); + async function playRandom(result: QueryHookResult, filter: ListFilterModel, selectedIds: Set) { + // query for a random scene + if (result.data && result.data.findSceneMarkers) { + let count = result.data.findSceneMarkers.count; + + let index = Math.floor(Math.random() * count); + let filterCopy = _.cloneDeep(filter); + filterCopy.itemsPerPage = 1; + filterCopy.currentPage = index + 1; + const singleResult = await StashService.queryFindSceneMarkers(filterCopy); + if (singleResult && singleResult.data && singleResult.data.findSceneMarkers && singleResult.data.findSceneMarkers.scene_markers.length === 1) { + // navigate to the scene player page + let url = NavigationUtils.makeSceneMarkerUrl(singleResult!.data!.findSceneMarkers!.scene_markers[0]) + props.history.push(url); + } + } + } + function renderContent( result: QueryHookResult, filter: ListFilterModel, diff --git a/ui/v2/src/components/scenes/ScenePlayer/ScenePlayer.tsx b/ui/v2/src/components/scenes/ScenePlayer/ScenePlayer.tsx index 05040ac6d..80c2a4a39 100644 --- a/ui/v2/src/components/scenes/ScenePlayer/ScenePlayer.tsx +++ b/ui/v2/src/components/scenes/ScenePlayer/ScenePlayer.tsx @@ -11,6 +11,7 @@ import { StashService } from "../../../core/StashService"; interface IScenePlayerProps { scene: GQL.SceneDataFragment; timestamp: number; + autoplay?: boolean; onReady?: any; onSeeked?: any; onTime?: any; @@ -235,7 +236,7 @@ export class ScenePlayerImpl extends React.Component({ + query: GQL.FindScenesDocument, + variables: { + filter: filter.makeFindFilter(), + scene_filter: sceneFilter, + } + }); + } + public static useFindSceneMarkers(filter: ListFilterModel) { let sceneMarkerFilter = {}; // if (!!filter && filter.criteriaFilterOpen) { @@ -129,6 +142,19 @@ export class StashService { }); } + public static queryFindSceneMarkers(filter: ListFilterModel) { + let sceneMarkerFilter = {}; + sceneMarkerFilter = filter.makeSceneMarkerFilter(); + + return StashService.client.query({ + query: GQL.FindSceneMarkersDocument, + variables: { + filter: filter.makeFindFilter(), + scene_marker_filter: sceneMarkerFilter, + } + }); + } + public static useFindStudios(filter: ListFilterModel) { return GQL.useFindStudios({ variables: { diff --git a/ui/v2/src/hooks/ListHook.tsx b/ui/v2/src/hooks/ListHook.tsx index 4671e0562..de230a5e3 100644 --- a/ui/v2/src/hooks/ListHook.tsx +++ b/ui/v2/src/hooks/ListHook.tsx @@ -18,10 +18,16 @@ export interface IListHookData { onSelectChange: (id: string, selected : boolean, shiftKey: boolean) => void; } +interface IListHookOperation { + text: string; + onClick: (result: QueryHookResult, filter: ListFilterModel, selectedIds: Set) => void; +} + export interface IListHookOptions { filterMode: FilterMode; props: IBaseProps; - zoomable?: boolean + zoomable?: boolean; + otherOperations?: IListHookOperation[]; renderContent: (result: QueryHookResult, filter: ListFilterModel, selectedIds: Set, zoomIndex: number) => JSX.Element | undefined; renderSelectedOptions?: (result: QueryHookResult, selectedIds: Set) => JSX.Element | undefined; } @@ -260,6 +266,15 @@ export class ListHook { setZoomIndex(newZoomIndex); } + const otherOperations = options.otherOperations ? options.otherOperations.map((o) => { + return { + text: o.text, + onClick: () => { + o.onClick(result, filter, selectedIds); + } + } + }) : undefined; + const template = (
{options.renderSelectedOptions && selectedIds.size > 0 ? options.renderSelectedOptions(result, selectedIds) : undefined}