mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Create a section in the history panel to reset scene activity (#5168)
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
parent
68738bd227
commit
96fdd94a01
9 changed files with 184 additions and 1 deletions
|
|
@ -276,6 +276,13 @@ type Mutation {
|
|||
"Sets the resume time point (if provided) and adds the provided duration to the scene's play duration"
|
||||
sceneSaveActivity(id: ID!, resume_time: Float, playDuration: Float): Boolean!
|
||||
|
||||
"Resets the resume time point and play duration"
|
||||
sceneResetActivity(
|
||||
id: ID!
|
||||
reset_resume: Boolean
|
||||
reset_duration: Boolean
|
||||
): Boolean!
|
||||
|
||||
"Increments the play count for the scene. Returns the new play count value."
|
||||
sceneIncrementPlayCount(id: ID!): Int!
|
||||
@deprecated(reason: "Use sceneAddPlay instead")
|
||||
|
|
|
|||
|
|
@ -847,6 +847,24 @@ func (r *mutationResolver) SceneSaveActivity(ctx context.Context, id string, res
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SceneResetActivity(ctx context.Context, id string, resetResume *bool, resetDuration *bool) (ret bool, err error) {
|
||||
sceneID, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("converting id: %w", err)
|
||||
}
|
||||
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.Scene
|
||||
|
||||
ret, err = qb.ResetActivity(ctx, sceneID, utils.IsTrue(resetResume), utils.IsTrue(resetDuration))
|
||||
return err
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// deprecated
|
||||
func (r *mutationResolver) SceneIncrementPlayCount(ctx context.Context, id string) (ret int, err error) {
|
||||
sceneID, err := strconv.Atoi(id)
|
||||
|
|
|
|||
|
|
@ -1267,6 +1267,27 @@ func (_m *SceneReaderWriter) QueryCount(ctx context.Context, sceneFilter *models
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// ResetActivity provides a mock function with given fields: ctx, sceneID, resetResume, resetDuration
|
||||
func (_m *SceneReaderWriter) ResetActivity(ctx context.Context, sceneID int, resetResume bool, resetDuration bool) (bool, error) {
|
||||
ret := _m.Called(ctx, sceneID, resetResume, resetDuration)
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int, bool, bool) bool); ok {
|
||||
r0 = rf(ctx, sceneID, resetResume, resetDuration)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int, bool, bool) error); ok {
|
||||
r1 = rf(ctx, sceneID, resetResume, resetDuration)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ResetO provides a mock function with given fields: ctx, id
|
||||
func (_m *SceneReaderWriter) ResetO(ctx context.Context, id int) (int, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ type SceneWriter interface {
|
|||
OHistoryWriter
|
||||
ViewHistoryWriter
|
||||
SaveActivity(ctx context.Context, sceneID int, resumeTime *float64, playDuration *float64) (bool, error)
|
||||
ResetActivity(ctx context.Context, sceneID int, resetResume bool, resetDuration bool) (bool, error)
|
||||
}
|
||||
|
||||
// SceneReaderWriter provides all scene methods.
|
||||
|
|
|
|||
|
|
@ -1234,6 +1234,30 @@ func (qb *SceneStore) SaveActivity(ctx context.Context, id int, resumeTime *floa
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (qb *SceneStore) ResetActivity(ctx context.Context, id int, resetResume bool, resetDuration bool) (bool, error) {
|
||||
if err := qb.tableMgr.checkIDExists(ctx, id); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
record := goqu.Record{}
|
||||
|
||||
if resetResume {
|
||||
record["resume_time"] = 0.0
|
||||
}
|
||||
|
||||
if resetDuration {
|
||||
record["play_duration"] = 0.0
|
||||
}
|
||||
|
||||
if len(record) > 0 {
|
||||
if err := qb.tableMgr.updateByID(ctx, id, record); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (qb *SceneStore) GetURLs(ctx context.Context, sceneID int) ([]string, error) {
|
||||
return scenesURLsTableMgr.get(ctx, sceneID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,18 @@ mutation SceneSaveActivity(
|
|||
)
|
||||
}
|
||||
|
||||
mutation SceneResetActivity(
|
||||
$id: ID!
|
||||
$reset_resume: Boolean!
|
||||
$reset_duration: Boolean!
|
||||
) {
|
||||
sceneResetActivity(
|
||||
id: $id
|
||||
reset_resume: $reset_resume
|
||||
reset_duration: $reset_duration
|
||||
)
|
||||
}
|
||||
|
||||
mutation SceneAddPlay($id: ID!, $times: [Timestamp!]) {
|
||||
sceneAddPlay(id: $id, times: $times) {
|
||||
count
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@ import {
|
|||
useSceneIncrementPlayCount,
|
||||
useSceneResetO,
|
||||
useSceneResetPlayCount,
|
||||
useSceneResetActivity,
|
||||
} from "src/core/StashService";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { useToast } from "src/hooks/Toast";
|
||||
import { TextField } from "src/utils/field";
|
||||
import TextUtils from "src/utils/text";
|
||||
|
||||
|
|
@ -72,9 +74,19 @@ const History: React.FC<{
|
|||
|
||||
const HistoryMenu: React.FC<{
|
||||
hasHistory: boolean;
|
||||
showResetResumeDuration: boolean;
|
||||
onAddDate: () => void;
|
||||
onClearDates: () => void;
|
||||
}> = ({ hasHistory, onAddDate, onClearDates }) => {
|
||||
resetResume: () => void;
|
||||
resetDuration: () => void;
|
||||
}> = ({
|
||||
hasHistory,
|
||||
showResetResumeDuration,
|
||||
onAddDate,
|
||||
onClearDates,
|
||||
resetResume,
|
||||
resetDuration,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
|
|
@ -101,6 +113,22 @@ const HistoryMenu: React.FC<{
|
|||
<FormattedMessage id="actions.clear_date_data" />
|
||||
</Dropdown.Item>
|
||||
)}
|
||||
{showResetResumeDuration && (
|
||||
<Dropdown.Item
|
||||
className="bg-secondary text-white"
|
||||
onClick={() => resetResume()}
|
||||
>
|
||||
<FormattedMessage id="actions.reset_resume_time" />
|
||||
</Dropdown.Item>
|
||||
)}
|
||||
{showResetResumeDuration && (
|
||||
<Dropdown.Item
|
||||
className="bg-secondary text-white"
|
||||
onClick={() => resetDuration()}
|
||||
>
|
||||
<FormattedMessage id="actions.reset_play_duration" />
|
||||
</Dropdown.Item>
|
||||
)}
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
);
|
||||
|
|
@ -142,6 +170,7 @@ interface ISceneHistoryProps {
|
|||
|
||||
export const SceneHistoryPanel: React.FC<ISceneHistoryProps> = ({ scene }) => {
|
||||
const intl = useIntl();
|
||||
const Toast = useToast();
|
||||
|
||||
const [dialogs, setDialogs] = React.useState({
|
||||
playHistory: false,
|
||||
|
|
@ -160,6 +189,8 @@ export const SceneHistoryPanel: React.FC<ISceneHistoryProps> = ({ scene }) => {
|
|||
const [incrementOCount] = useSceneIncrementO(scene.id);
|
||||
const [decrementOCount] = useSceneDecrementO(scene.id);
|
||||
const [resetO] = useSceneResetO(scene.id);
|
||||
const [resetResume] = useSceneResetActivity(scene.id, true, false);
|
||||
const [resetDuration] = useSceneResetActivity(scene.id, false, true);
|
||||
|
||||
function dateStringToISOString(time: string) {
|
||||
const date = TextUtils.stringToFuzzyDateTime(time);
|
||||
|
|
@ -221,6 +252,52 @@ export const SceneHistoryPanel: React.FC<ISceneHistoryProps> = ({ scene }) => {
|
|||
});
|
||||
}
|
||||
|
||||
async function handleResetResume() {
|
||||
try {
|
||||
await resetResume({
|
||||
variables: {
|
||||
id: scene.id,
|
||||
reset_resume: true,
|
||||
reset_duration: false,
|
||||
},
|
||||
});
|
||||
|
||||
Toast.success(
|
||||
intl.formatMessage(
|
||||
{ id: "toast.updated_entity" },
|
||||
{
|
||||
entity: intl.formatMessage({ id: "scene" }).toLocaleLowerCase(),
|
||||
}
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleResetDuration() {
|
||||
try {
|
||||
await resetDuration({
|
||||
variables: {
|
||||
id: scene.id,
|
||||
reset_resume: false,
|
||||
reset_duration: true,
|
||||
},
|
||||
});
|
||||
|
||||
Toast.success(
|
||||
intl.formatMessage(
|
||||
{ id: "toast.updated_entity" },
|
||||
{
|
||||
entity: intl.formatMessage({ id: "scene" }).toLocaleLowerCase(),
|
||||
}
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderDialogs() {
|
||||
return (
|
||||
<>
|
||||
|
|
@ -296,8 +373,11 @@ export const SceneHistoryPanel: React.FC<ISceneHistoryProps> = ({ scene }) => {
|
|||
</Button>
|
||||
<HistoryMenu
|
||||
hasHistory={playHistory.length > 0}
|
||||
showResetResumeDuration={true}
|
||||
onAddDate={() => setDialogPartial({ addPlay: true })}
|
||||
onClearDates={() => setDialogPartial({ playHistory: true })}
|
||||
resetResume={() => handleResetResume()}
|
||||
resetDuration={() => handleResetDuration()}
|
||||
/>
|
||||
</span>
|
||||
</h5>
|
||||
|
|
@ -336,8 +416,11 @@ export const SceneHistoryPanel: React.FC<ISceneHistoryProps> = ({ scene }) => {
|
|||
</Button>
|
||||
<HistoryMenu
|
||||
hasHistory={oHistory.length > 0}
|
||||
showResetResumeDuration={false}
|
||||
onAddDate={() => setDialogPartial({ addO: true })}
|
||||
onClearDates={() => setDialogPartial({ oHistory: true })}
|
||||
resetResume={() => handleResetResume()}
|
||||
resetDuration={() => handleResetDuration()}
|
||||
/>
|
||||
</span>
|
||||
</h5>
|
||||
|
|
|
|||
|
|
@ -786,6 +786,21 @@ export const useSceneResetO = (id: string) =>
|
|||
},
|
||||
});
|
||||
|
||||
export const useSceneResetActivity = (
|
||||
id: string,
|
||||
reset_resume: boolean,
|
||||
reset_duration: boolean
|
||||
) =>
|
||||
GQL.useSceneResetActivityMutation({
|
||||
variables: { id, reset_resume, reset_duration },
|
||||
update(cache, result) {
|
||||
if (!result.data?.sceneResetActivity) return;
|
||||
|
||||
evictTypeFields(cache, sceneMutationImpactedTypeFields);
|
||||
evictQueries(cache, sceneMutationImpactedQueries);
|
||||
},
|
||||
});
|
||||
|
||||
export const useSceneGenerateScreenshot = () =>
|
||||
GQL.useSceneGenerateScreenshotMutation();
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@
|
|||
"remove_from_gallery": "Remove from Gallery",
|
||||
"rename_gen_files": "Rename generated files",
|
||||
"rescan": "Rescan",
|
||||
"reset_play_duration": "Reset play duration",
|
||||
"reset_resume_time": "Reset resume time",
|
||||
"reset_cover": "Restore Default Cover",
|
||||
"reshuffle": "Reshuffle",
|
||||
"running": "running",
|
||||
|
|
|
|||
Loading…
Reference in a new issue