Add Play random button to scenes and scene markers page (#255)

* Add play random button for scenes

* Add play random to scene markers
This commit is contained in:
WithoutPants 2019-12-10 01:39:01 +11:00 committed by Leopere
parent c66d9fcc28
commit bb164f1895
7 changed files with 120 additions and 7 deletions

View file

@ -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<IListFilterProps> = (props: IListFilt
let options = [];
options.push(renderSelectAll());
options.push(renderSelectNone());
if (props.otherOperations) {
props.otherOperations.forEach((o) => {
options.push(<MenuItem onClick={o.onClick} text={o.text} />);
});
}
options = options.filter((o) => !!o);
let menuItems = options as JSX.Element[];

View file

@ -21,6 +21,7 @@ interface ISceneProps extends IBaseProps {}
export const Scene: FunctionComponent<ISceneProps> = (props: ISceneProps) => {
const [timestamp, setTimestamp] = useState<number>(0);
const [autoplay, setAutoplay] = useState<boolean>(false);
const [scene, setScene] = useState<Partial<GQL.SceneDataFragment>>({});
const [isLoading, setIsLoading] = useState(false);
const { data, error, loading } = StashService.useFindScene(props.match.params.id);
@ -37,6 +38,9 @@ export const Scene: FunctionComponent<ISceneProps> = (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<ISceneProps> = (props: ISceneProps) => {
return (
<>
<ScenePlayer scene={modifiedScene} timestamp={timestamp} />
<ScenePlayer scene={modifiedScene} timestamp={timestamp} autoplay={autoplay}/>
<Card id="details-container">
<Tabs
renderActiveTabPanelOnly={true}

View file

@ -10,18 +10,45 @@ import { WallPanel } from "../Wall/WallPanel";
import { SceneCard } from "./SceneCard";
import { SceneListTable } from "./SceneListTable";
import { SceneSelectedOptions } from "./SceneSelectedOptions";
import { StashService } from "../../core/StashService";
interface ISceneListProps extends IBaseProps {}
export const SceneList: FunctionComponent<ISceneListProps> = (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<FindScenesQuery, FindScenesVariables>, filter: ListFilterModel, selectedIds: Set<string>) {
// 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<FindScenesQuery, FindScenesVariables>, selectedIds: Set<string>) {
// find the selected items from the ids
if (!result.data || !result.data.findScenes) { return undefined; }

View file

@ -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<IProps> = (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<FindSceneMarkersQuery, FindSceneMarkersVariables>, filter: ListFilterModel, selectedIds: Set<string>) {
// 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<FindSceneMarkersQuery, FindSceneMarkersVariables>,
filter: ListFilterModel,

View file

@ -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<IScenePlayerProps, IScenePl
},
cast: {},
primary: "html5",
autostart: this.props.config ? this.props.config.autostartVideo : false,
autostart: this.props.autoplay || (this.props.config ? this.props.config.autostartVideo : false),
repeat: repeat,
playbackRateControls: true,
playbackRates: [0.75, 1, 1.5, 2, 3, 4],
@ -248,7 +249,7 @@ export class ScenePlayerImpl extends React.Component<IScenePlayerProps, IScenePl
let repeat = this.shouldRepeat(scene);
return {
autoplay: this.props.config ? this.props.config.autostartVideo : false,
autoplay: this.props.autoplay || (this.props.config ? this.props.config.autostartVideo : false),
loop: repeat,
};
}

View file

@ -110,6 +110,19 @@ export class StashService {
});
}
public static queryFindScenes(filter: ListFilterModel) {
let sceneFilter = {};
sceneFilter = filter.makeSceneFilter();
return StashService.client.query<GQL.FindScenesQuery>({
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<GQL.FindSceneMarkersQuery>({
query: GQL.FindSceneMarkersDocument,
variables: {
filter: filter.makeFindFilter(),
scene_marker_filter: sceneMarkerFilter,
}
});
}
public static useFindStudios(filter: ListFilterModel) {
return GQL.useFindStudios({
variables: {

View file

@ -18,10 +18,16 @@ export interface IListHookData {
onSelectChange: (id: string, selected : boolean, shiftKey: boolean) => void;
}
interface IListHookOperation {
text: string;
onClick: (result: QueryHookResult<any, any>, filter: ListFilterModel, selectedIds: Set<string>) => void;
}
export interface IListHookOptions {
filterMode: FilterMode;
props: IBaseProps;
zoomable?: boolean
zoomable?: boolean;
otherOperations?: IListHookOperation[];
renderContent: (result: QueryHookResult<any, any>, filter: ListFilterModel, selectedIds: Set<string>, zoomIndex: number) => JSX.Element | undefined;
renderSelectedOptions?: (result: QueryHookResult<any, any>, selectedIds: Set<string>) => 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 = (
<div>
<ListFilter
@ -274,6 +289,7 @@ export class ListHook {
onSelectNone={onSelectNone}
zoomIndex={options.zoomable ? zoomIndex : undefined}
onChangeZoom={options.zoomable ? onChangeZoom : undefined}
otherOperations={otherOperations}
filter={filter}
/>
{options.renderSelectedOptions && selectedIds.size > 0 ? options.renderSelectedOptions(result, selectedIds) : undefined}