Skip to content

Commit

Permalink
Add indicator for upvotes and downvotes
Browse files Browse the repository at this point in the history
Also fixes some issues with local storage not working and makes sure to not store anything when store submissions off.
  • Loading branch information
ajayyy committed May 10, 2024
1 parent d4aad43 commit c73749b
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 47 deletions.
4 changes: 4 additions & 0 deletions public/content.css
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ ytd-compact-playlist-renderer .ytd-compact-playlist-renderer #video-title:not(.c
cursor: pointer;
}

.cbButton path {
transition: fill 0.5s;
}

.cbButton img {
height: 60%;
top: 0;
Expand Down
46 changes: 42 additions & 4 deletions src/submission/SubmissionComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Tooltip } from "../utils/tooltip";
import { LicenseComponent } from "../license/LicenseComponent";
import { ToggleOptionComponent } from "../popup/ToggleOptionComponent";
import { FormattedText } from "../popup/FormattedTextComponent";
import { shouldStoreVotes } from "../utils/configUtils";

export interface SubmissionComponentProps {
videoID: VideoID;
Expand Down Expand Up @@ -81,7 +82,7 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
const originalTitle = await toSentenceCase(getCurrentPageTitle() || chrome.i18n.getMessage("OriginalTitle"), false);
setOriginalTitle(originalTitle);

setTitles([{
const newTitles = [{
title: originalTitle,
original: true,
votable: true,
Expand All @@ -98,7 +99,12 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
original: s.original,
votable: true,
locked: s.locked
}))]);
}))];

setTitles(newTitles);

const unsubmitted = Config.local!.unsubmitted[props.videoID];
updateUnsubmitted(unsubmitted, setExtraUnsubmittedThumbnails, setExtraUnsubmittedTitles, thumbnails, newTitles);
})();
}, []);

Expand Down Expand Up @@ -130,7 +136,31 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
const [selectedTitle, setSelectedTitle] = React.useState<RenderedTitleSubmission | null>(null);
const selectedThumbnail = React.useRef<ThumbnailSubmission | null>(null);
const [selectedTitleIndex, setSelectedTitleIndex] = React.useState(-1);
const [upvotedTitleIndex, setUpvotedTitleIndex] = React.useState(-1);
const [selectedThumbnailIndex, setSelectedThumbnailIndex] = React.useState(-1);
const [upvotedThumbnailIndex, setUpvotedThumbnailIndex] = React.useState(-1);

React.useEffect(() => {
const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const upvotedTitle = unsubmitted.titles.find((t) => t.selected);
if (upvotedTitle) {
const upvotedTitleIndex = titles.findIndex((t) => t.title === upvotedTitle.title);
if (upvotedTitleIndex !== -1) {
setUpvotedTitleIndex(upvotedTitleIndex);
}
}

const upvotedThumbnail = unsubmitted.thumbnails.find((t) => t.selected);
if (upvotedThumbnail) {
const upvotedThumbnailIndex = thumbnails.findIndex((t) => (t.type === ThumbnailType.Original && upvotedThumbnail.original)
|| (t.type === ThumbnailType.SpecifiedTime && !upvotedThumbnail.original && t.timestamp === upvotedThumbnail.timestamp));
if (upvotedThumbnailIndex !== -1) {
setUpvotedThumbnailIndex(upvotedThumbnailIndex);
}
}
}
}, [titles]);

// Load existing unsubmitted thumbnails whenever a videoID change happens
const [extraUnsubmittedThumbnails, setExtraUnsubmittedThumbnails] = React.useState<RenderedThumbnailSubmission[]>([]);
Expand Down Expand Up @@ -185,6 +215,7 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
videoId={props.videoID}
existingSubmissions={thumbnailSubmissions}
selectedThumbnailIndex={selectedThumbnailIndex}
upvotedThumbnailIndex={upvotedThumbnailIndex}
actAsVip={actAsVip}
onSelect={(t, i) => {
let selectedIndex = i;
Expand All @@ -195,7 +226,7 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
return;
}

if (!t.original) {
if (!t.original && shouldStoreVotes()) {
const unsubmitted = Config.local!.unsubmitted[props.videoID] ??= {
thumbnails: [],
titles: []
Expand Down Expand Up @@ -230,12 +261,16 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {

setSelectedThumbnailIndex(selectedIndex);
selectedThumbnail.current = t;
}}
onUpvote={(index) => {
setUpvotedThumbnailIndex(index);
}}></ThumbnailDrawerComponent>
</div>

<div>
<TitleDrawerComponent existingSubmissions={[...titles, ...extraUnsubmittedTitles]}
selectedTitleIndex={selectedTitleIndex}
upvotedTitleIndex={upvotedTitleIndex}
actAsVip={actAsVip}
videoID={props.videoID}
onDeselect={() => {
Expand All @@ -246,7 +281,7 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {
setSelectedTitleIndex(i);
setSelectedTitle(t);

if (t.title !== oldTitle) {
if (t.title !== oldTitle && shouldStoreVotes()) {
const unsubmitted = Config.local!.unsubmitted[props.videoID] ??= {
thumbnails: [],
titles: []
Expand Down Expand Up @@ -276,6 +311,9 @@ export const SubmissionComponent = (props: SubmissionComponentProps) => {

Config.forceLocalUpdate("unsubmitted");
}
}}
onUpvote={(index) => {
setUpvotedTitleIndex(index);
}}></TitleDrawerComponent>
</div>

Expand Down
6 changes: 6 additions & 0 deletions src/submission/ThumbnailDrawerComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export interface ThumbnailDrawerComponentProps {
videoId: VideoID;
existingSubmissions: RenderedThumbnailSubmission[];
selectedThumbnailIndex: number;
upvotedThumbnailIndex: number;
onSelect: (submission: ThumbnailSubmission, index: number) => void;
onUpvote: (index: number) => void;
actAsVip: boolean;
}

Expand Down Expand Up @@ -47,9 +49,13 @@ function getThumbnails(props: ThumbnailDrawerComponentProps,
<ThumbnailSelectionComponent
video={props.video}
selected={selectedThumbnail === i}
upvoted={props.upvotedThumbnailIndex === i}
onClick={(submission) => {
props.onSelect(submission, i);
}}
onUpvote={() => {
props.onUpvote(i);
}}
type={props.existingSubmissions[i].type}
videoID={props.videoId}
time={time}
Expand Down
54 changes: 45 additions & 9 deletions src/submission/ThumbnailSelectionComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ import { submitVideoBrandingAndHandleErrors } from "../dataFetching";
import { AnimationUtils } from "../../maze-utils/src/animationUtils";
import Config from "../config/config";
import { FormattedText } from "../popup/FormattedTextComponent";
import { shouldStoreVotes } from "../utils/configUtils";

export interface ThumbnailSelectionComponentProps {
video: HTMLVideoElement;
selected?: boolean;
upvoted?: boolean;
onClick?: (thumbnail: ThumbnailSubmission) => void;
onUpvote: () => void;
type: ThumbnailType;
videoID: VideoID;
hideTime?: boolean;
Expand All @@ -31,6 +34,7 @@ export interface ThumbnailSelectionComponentProps {
*/
export const ThumbnailSelectionComponent = (props: ThumbnailSelectionComponentProps) => {
const [error, setError] = React.useState("");
const [downvoted, setDownvoted] = React.useState(false);

function createThumbnailSubmission(): ThumbnailSubmission | null {
return props.type === ThumbnailType.Original ? {
Expand Down Expand Up @@ -82,19 +86,43 @@ export const ThumbnailSelectionComponent = (props: ThumbnailSelectionComponentPr
e.stopPropagation();

const stopAnimation = AnimationUtils.applyLoadingAnimation(e.currentTarget, 0.3);
submitVideoBrandingAndHandleErrors(null, createThumbnailSubmission(), false, props.actAsVip!).then(stopAnimation);
submitVideoBrandingAndHandleErrors(null, createThumbnailSubmission(), false, props.actAsVip!).then(() => {
stopAnimation();
setDownvoted(false);

const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const unsubmittedThumbnail = unsubmitted.thumbnails.find((t) => !t.original && t.timestamp === props.time);
props.onUpvote();
});

if (shouldStoreVotes()) {
const unsubmitted = Config.local!.unsubmitted[props.videoID] ??= {
thumbnails: [],
titles: []
};
unsubmitted.thumbnails.forEach((t) => t.selected = false);

const unsubmittedThumbnail = unsubmitted.thumbnails.find((t) =>(t.original && props.type === ThumbnailType.Original)
|| (!t.original && t.timestamp === props.time));
if (unsubmittedThumbnail) {
unsubmitted.thumbnails.forEach((t) => t.selected = false);
unsubmittedThumbnail.selected = true;
Config.forceLocalUpdate("unsubmitted");
} else {
if (props.type === ThumbnailType.Original) {
unsubmitted.thumbnails.push({
original: true,
selected: true
});
} else {
unsubmitted.thumbnails.push({
original: false,
timestamp: props.time!,
selected: true
});
}
}

Config.forceLocalUpdate("unsubmitted");
}
}}>
<UpvoteIcon/>
<UpvoteIcon selected={props.upvoted}/>
</button>

<button className="cbButton"
Expand All @@ -103,18 +131,26 @@ export const ThumbnailSelectionComponent = (props: ThumbnailSelectionComponentPr
e.stopPropagation();

const stopAnimation = AnimationUtils.applyLoadingAnimation(e.currentTarget, 0.3);
submitVideoBrandingAndHandleErrors(null, createThumbnailSubmission(), true, props.actAsVip!).then(stopAnimation);
submitVideoBrandingAndHandleErrors(null, createThumbnailSubmission(), true, props.actAsVip!).then(() => {
stopAnimation();
setDownvoted(true);
});

const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const unsubmittedThumbnail = unsubmitted.thumbnails.find((t) => !t.original && t.timestamp === props.time);
if (unsubmittedThumbnail) {
unsubmitted.thumbnails.splice(unsubmitted.thumbnails.indexOf(unsubmittedThumbnail), 1);

if (unsubmitted.titles.length === 0 && unsubmitted.thumbnails.length === 0) {
delete Config.local!.unsubmitted[props.videoID];
}

Config.forceLocalUpdate("unsubmitted");
}
}
}}>
<DownvoteIcon locked={ Config.config!.vip && props.locked }/>
<DownvoteIcon selected={downvoted} locked={ Config.config!.vip && props.locked }/>
</button>
</div>
: null
Expand Down
43 changes: 35 additions & 8 deletions src/submission/TitleComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import DownvoteIcon from "../svgIcons/downvoteIcon";
import { submitVideoBrandingAndHandleErrors } from "../dataFetching";
import { AnimationUtils } from "../../maze-utils/src/animationUtils";
import { VideoID } from "../../maze-utils/src/video";
import { shouldStoreVotes } from "../utils/configUtils";

export interface TitleComponentProps {
submission: RenderedTitleSubmission;
selected: boolean;
upvoted: boolean;
onSelectOrUpdate: (title: string, oldTitle: string) => void;
onUpvote: () => void;
onDeselect: () => void;
actAsVip: boolean;
videoID: VideoID;
Expand All @@ -24,6 +27,7 @@ export const TitleComponent = (props: TitleComponentProps) => {
const title = React.useRef(props.submission.title);
const [titleChanged, setTitleChanged] = React.useState(false);
const [focused, setFocused] = React.useState(false);
const [downvoted, setDownvoted] = React.useState(false);

React.useEffect(() => {
if (focused && title.current === "") {
Expand Down Expand Up @@ -109,19 +113,34 @@ export const TitleComponent = (props: TitleComponentProps) => {
e.stopPropagation();

const stopAnimation = AnimationUtils.applyLoadingAnimation(e.currentTarget, 0.3);
submitVideoBrandingAndHandleErrors(props.submission, null, false, props.actAsVip).then(stopAnimation);
submitVideoBrandingAndHandleErrors(props.submission, null, false, props.actAsVip).then(() => {
stopAnimation();
setDownvoted(false);

props.onUpvote();
});

if (shouldStoreVotes()) {
const unsubmitted = Config.local!.unsubmitted[props.videoID] ??= {
thumbnails: [],
titles: []
};
unsubmitted.titles.forEach((t) => t.selected = false);

const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const unsubmittedTitle = unsubmitted.titles.find((t) => t.title === props.submission.title);
if (unsubmittedTitle) {
unsubmitted.titles.forEach((t) => t.selected = false);
unsubmittedTitle.selected = true;
Config.forceLocalUpdate("unsubmitted");
} else {
unsubmitted.titles.push({
title: props.submission.title,
selected: true
})
}

Config.forceLocalUpdate("unsubmitted");
}
}}>
<UpvoteIcon/>
<UpvoteIcon selected={props.upvoted} />
</button>

<button className="cbButton"
Expand All @@ -130,18 +149,26 @@ export const TitleComponent = (props: TitleComponentProps) => {
e.stopPropagation();

const stopAnimation = AnimationUtils.applyLoadingAnimation(e.currentTarget, 0.3);
submitVideoBrandingAndHandleErrors(props.submission, null, true, props.actAsVip).then(stopAnimation);
submitVideoBrandingAndHandleErrors(props.submission, null, true, props.actAsVip).then(() => {
stopAnimation();
setDownvoted(true);
});

const unsubmitted = Config.local!.unsubmitted[props.videoID];
if (unsubmitted) {
const unsubmittedTitle = unsubmitted.titles.find((t) => t.title === props.submission.title);
if (unsubmittedTitle) {
unsubmitted.titles.splice(unsubmitted.titles.indexOf(unsubmittedTitle), 1);

if (unsubmitted.titles.length === 0 && unsubmitted.thumbnails.length === 0) {
delete Config.local!.unsubmitted[props.videoID];
}

Config.forceLocalUpdate("unsubmitted");
}
}
}}>
<DownvoteIcon locked={ Config.config!.vip && props.submission.locked }/>
<DownvoteIcon selected={downvoted} locked={ Config.config!.vip && props.submission.locked }/>
</button>
</div>

Expand Down
6 changes: 6 additions & 0 deletions src/submission/TitleDrawerComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export interface TitleDrawerComponentProps {
existingSubmissions: RenderedTitleSubmission[];
onSelectOrUpdate: (title: RenderedTitleSubmission, oldTitle: string, index: number) => void;
onDeselect: (index: number) => void;
onUpvote: (index: number) => void;
selectedTitleIndex: number;
upvotedTitleIndex: number;
actAsVip: boolean;
videoID: VideoID;
}
Expand All @@ -33,6 +35,7 @@ function getTitles(props: TitleDrawerComponentProps,
titles.push(
<TitleComponent
selected={selectedTitle === i}
upvoted={props.upvotedTitleIndex === i}
onSelectOrUpdate={(title, oldTitle) => {
props.onSelectOrUpdate({
...props.existingSubmissions[i],
Expand All @@ -42,6 +45,9 @@ function getTitles(props: TitleDrawerComponentProps,
onDeselect={() => {
props.onDeselect(i);
}}
onUpvote={() => {
props.onUpvote(i);
}}
actAsVip={props.actAsVip}
key={i}
submission={props.existingSubmissions[i]}
Expand Down
Loading

0 comments on commit c73749b

Please sign in to comment.