diff --git a/graphql/documents/data/movie-slim.graphql b/graphql/documents/data/movie-slim.graphql index 49f458921..8150986a8 100644 --- a/graphql/documents/data/movie-slim.graphql +++ b/graphql/documents/data/movie-slim.graphql @@ -2,4 +2,4 @@ fragment SlimMovieData on Movie { id name front_image_path -} \ No newline at end of file +} diff --git a/graphql/documents/data/movie.graphql b/graphql/documents/data/movie.graphql index e8e378926..f566e535d 100644 --- a/graphql/documents/data/movie.graphql +++ b/graphql/documents/data/movie.graphql @@ -17,4 +17,10 @@ fragment MovieData on Movie { front_image_path back_image_path scene_count + + scenes { + id + title + path + } } diff --git a/graphql/schema/types/movie.graphql b/graphql/schema/types/movie.graphql index 3fb156311..104c68176 100644 --- a/graphql/schema/types/movie.graphql +++ b/graphql/schema/types/movie.graphql @@ -17,6 +17,7 @@ type Movie { front_image_path: String # Resolver back_image_path: String # Resolver scene_count: Int # Resolver + scenes: [Scene!]! } input MovieCreateInput { @@ -60,4 +61,4 @@ input MovieDestroyInput { type FindMoviesResultType { count: Int! movies: [Movie!]! -} \ No newline at end of file +} diff --git a/pkg/api/resolver_model_movie.go b/pkg/api/resolver_model_movie.go index 6bfa759f7..0b3597d49 100644 --- a/pkg/api/resolver_model_movie.go +++ b/pkg/api/resolver_model_movie.go @@ -125,6 +125,18 @@ func (r *movieResolver) SceneCount(ctx context.Context, obj *models.Movie) (ret return &res, err } +func (r *movieResolver) Scenes(ctx context.Context, obj *models.Movie) (ret []*models.Scene, err error) { + if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error { + var err error + ret, err = repo.Scene().FindByMovieID(obj.ID) + return err + }); err != nil { + return nil, err + } + + return ret, nil +} + func (r *movieResolver) CreatedAt(ctx context.Context, obj *models.Movie) (*time.Time, error) { return &obj.CreatedAt.Timestamp, nil } diff --git a/ui/v2.5/src/components/Changelog/versions/v0100.md b/ui/v2.5/src/components/Changelog/versions/v0100.md index fe0ceaf8b..53e69481d 100644 --- a/ui/v2.5/src/components/Changelog/versions/v0100.md +++ b/ui/v2.5/src/components/Changelog/versions/v0100.md @@ -13,6 +13,7 @@ * Support filtering Movies by Performers. ([#1675](https://github.com/stashapp/stash/pull/1675)) ### 🎨 Improvements +* Added date and details to Movie card, and move scene count to icon. ([#1758](https://github.com/stashapp/stash/pull/1758)) * Added date and details to Gallery card, and move image count to icon. ([#1763](https://github.com/stashapp/stash/pull/1763)) * Optimised image thumbnail generation (optionally using `libvips`) and made optional. ([#1655](https://github.com/stashapp/stash/pull/1655)) * Added missing image table indexes, resulting in a significant performance improvement. ([#1740](https://github.com/stashapp/stash/pull/1740)) diff --git a/ui/v2.5/src/components/Movies/MovieCard.tsx b/ui/v2.5/src/components/Movies/MovieCard.tsx index 96f6c69a5..ea8c3904f 100644 --- a/ui/v2.5/src/components/Movies/MovieCard.tsx +++ b/ui/v2.5/src/components/Movies/MovieCard.tsx @@ -1,7 +1,14 @@ import React, { FunctionComponent } from "react"; -import { FormattedPlural } from "react-intl"; +import { Button, ButtonGroup } from "react-bootstrap"; import * as GQL from "src/core/generated-graphql"; -import { GridCard } from "src/components/Shared"; +import { + GridCard, + HoverPopover, + Icon, + TagLink, + TruncatedText, +} from "src/components/Shared"; +import { FormattedMessage } from "react-intl"; import { RatingBanner } from "../Shared/RatingBanner"; interface IProps { @@ -14,20 +21,47 @@ interface IProps { export const MovieCard: FunctionComponent = (props: IProps) => { function maybeRenderSceneNumber() { - if (!props.sceneIndex) { - return ( - - {props.movie.scene_count}  - + if (!props.sceneIndex) return; + + return ( + <> +
+ + #{props.sceneIndex} + + ); + } + + function maybeRenderScenesPopoverButton() { + if (props.movie.scenes.length === 0) return; + + const popoverContent = props.movie.scenes.map((scene) => ( + + )); + + return ( + + + + ); + } + + function maybeRenderPopoverButtonGroup() { + if (props.sceneIndex || props.movie.scenes.length > 0) { + return ( + <> + {maybeRenderSceneNumber()} +
+ + {maybeRenderScenesPopoverButton()} + + ); } - - return Scene number: {props.sceneIndex}; } return ( @@ -46,10 +80,18 @@ export const MovieCard: FunctionComponent = (props: IProps) => { } - details={maybeRenderSceneNumber()} + details={ + <> + {props.movie.date} +

+ +

+ + } selected={props.selected} selecting={props.selecting} onSelectedChanged={props.onSelectedChanged} + popovers={maybeRenderPopoverButtonGroup()} /> ); }; diff --git a/ui/v2.5/src/components/Movies/styles.scss b/ui/v2.5/src/components/Movies/styles.scss index c87122a55..3452b265f 100644 --- a/ui/v2.5/src/components/Movies/styles.scss +++ b/ui/v2.5/src/components/Movies/styles.scss @@ -17,6 +17,10 @@ object-fit: contain; width: 100%; } + + .movie-scene-number { + text-align: center; + } } .movie-images {