-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/record movie UI #483
Conversation
… and title in download handler
color: var(--dark-theme-viewport-button-disabled-color); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are not general to any other viewport buttons but need this disabled state so they are here, see note above for my questions.
const startRecordIcon = ( | ||
<span className={styles.iconContainer}> | ||
<span | ||
className={classNames("icon-moon", "record-icon-circle")} | ||
></span> | ||
<span | ||
className={classNames("icon-moon", "record-icon-ring")} | ||
></span> | ||
</span> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To do multicolor icons via icomoon requires stacking glyphs. This was the best I could come up with, but I'm open to feedback if there is a better way!
Debated defining this in Icons.tsx
with inline styles and importing from there, but that file typically doesn't handle any thing related to icomoon icons... Style rules for this icon also got a bit spread out, some in primary stylesheet, some here, and some in viewport button. Not ideal? Could consolidate somewhat by moving most of it to ViewportButton stylesheet but it seems a bit case-specific for that, so I only put the things that relied on disabled state there. This works, but I'm definitely down to refactor/move things around.
const useFormattedDuration = () => { | ||
const [formattedDuration, setFormattedDuration] = useState(""); | ||
|
||
useEffect(() => { | ||
const video = document.createElement("video"); | ||
video.src = movieUrl; | ||
video.onloadedmetadata = () => { | ||
const durationInSeconds = video.duration; | ||
const minutes = Math.floor((durationInSeconds % 3600) / 60); | ||
const secs = Math.ceil(durationInSeconds) % 60; | ||
|
||
const minutesStr = minutes.toString().padStart(2, "0"); | ||
const secondsStr = secs.toString().padStart(2, "0"); | ||
|
||
setFormattedDuration(`${minutesStr}:${secondsStr}`); | ||
video.src = ""; | ||
video.load(); | ||
}; | ||
}, [movieUrl]); | ||
|
||
return formattedDuration; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onloadedmetadata
is async hence the need for a hook, Promise or callback. Code was less complicated if this is handled up in ViewerPanel
and store in state there but that file is already very cluttered with many concerns...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you just move this out into its own file?
const getTooltip = () => | ||
!disabled || tooltipWhenDisabled ? tooltipText : ""; | ||
|
||
const getClickHandler = () => (!disabled ? clickHandler : undefined); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needed these tweaks to manage the new case of a button that is disabled but has a tooltip.
commit f622cae Author: Joe Heffernan <interim17@gmail.com> Date: Tue Apr 2 09:12:34 2024 -0700 Fix/update custom modal (#482) * use custom modal wrapper for more layout and styling * remove duplicate and unused colors * remove more duplicated colors * remove comments * remove unused import from starcheckbox * simplify time input css selector * fix spelling errors in "shareable" * omit unused ModalProps from CustomModalProps * add comment to share modal input styles commit 0af4198 Author: Joe Heffernan <interim17@gmail.com> Date: Mon Apr 1 09:48:40 2024 -0700 Fix/header buttons (#484) * custom nav button component for header buttons * remove tooltip button stylesheet * make header a functional component and implement nav buttons * remove animation on home button * remove unneeded style sheets and class names from action button components * use interface for tooltip text * remove unused import * delete unused stylesheet * move tooltip placement type to constants * default nav buttons to action styling and trim selectors * provide default disabled tooltip text and simplify conditional checks commit f527adb Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu Mar 28 11:16:17 2024 -0700 Bump webpack-dev-middleware from 5.3.3 to 5.3.4 (#481) Bumps [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) from 5.3.3 to 5.3.4. - [Release notes](https://github.com/webpack/webpack-dev-middleware/releases) - [Changelog](https://github.com/webpack/webpack-dev-middleware/blob/v5.3.4/CHANGELOG.md) - [Commits](webpack/webpack-dev-middleware@v5.3.3...v5.3.4) --- updated-dependencies: - dependency-name: webpack-dev-middleware dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Coverage report
Test suite run success102 tests passing in 7 suites. Report generated by 🧪jest coverage report action from e93b7a9 |
const stopRecordingIcon = isHovering | ||
? "stop-record-icon" | ||
: activeRecordingIcon; | ||
|
||
const getIcon = () => { | ||
return isRecording ? stopRecordingIcon : startRecordingIcon; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: but these two things seem really similar, but one is just a constant and one is a function? unless there is a reason I would pick one setup and go with it for both
@@ -99,6 +103,7 @@ interface ViewerPanelState { | |||
particleTypeIds: string[]; | |||
height: number; | |||
width: number; | |||
movieURL: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this is stored in local state and only sent down to one component, why not just have it stored by that one component?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The onRecordedMovie
handler receives the blob of data from the viewer, so we need to do something with that blob in the component where the callback is defined and passed to the viewer.
We could pass the blob to the lower component as a prop and define the URL there, but I figured that passing the blob around, rather than just a URL, could potentially have performance implications?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh never mind, I see, you needed it for the onRecordMovie prop
src/containers/ViewerPanel/index.tsx
Outdated
}); | ||
}; | ||
|
||
private getMovieTitle = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems like it could be a selector?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good call
const getTooltip = () => | ||
!disabled || tooltipWhenDisabled ? tooltipText : ""; | ||
|
||
const getClickHandler = () => (!disabled ? clickHandler : undefined); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised typescript isn't upset about having onClick={undefined}
.
Just a suggestion:
const getClickHandler = () => (!disabled ? clickHandler : undefined); | |
onClick = () => { | |
if (disabled) {return} else {clickHander()} | |
} | |
onClick={onClick} | |
the only difference being that it's now a function that returns nothing rather than setting it to undefined. but it's fine either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine either way, happy to make a change if its less confusing.
I think TS doesn't mind because the antd Button component onClick prop is optional, so undefined is an acceptable thing to return from that function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning undefined
seems fine to me, but I might consider making these just plain constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you have a linting error with a now un-needed import, otherwise looks good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
const getTooltip = () => | ||
!disabled || tooltipWhenDisabled ? tooltipText : ""; | ||
|
||
const getClickHandler = () => (!disabled ? clickHandler : undefined); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning undefined
seems fine to me, but I might consider making these just plain constants.
Time estimate or Size
Review time: medium
Problem
Closes #327
Solution
RecordMovieComponent
manages the modal and button, retrieves and formats the various display icons and text, defines the downloading function, and calls the viewer handlers it receives.Modal is trim, no logic.
Minimized storing state in
ViewerPanel
: only holding the url for the blob.Steps to Verify:
On supported browsers:
On unsupported browsers (Firefox, and apparently sometimes Safari):
Screenshots (optional):