Skip to content
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

Dynamic Typists #2

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open

Dynamic Typists #2

wants to merge 22 commits into from

Conversation

janine9vn
Copy link
Contributor

No description provided.

thijsfranck and others added 22 commits August 28, 2023 21:01
Co-authored-by: Oliver Wilkes <[email protected]>
Co-authored-by: Thijs Franck <[email protected]>
Co-authored-by: Istalantar <[email protected]>
Co-authored-by: Thijs <[email protected]>
Co-authored-by: Oliver Wilkes <[email protected]>
Co-authored-by: Oliver Wilkes <[email protected]>
Co-authored-by: Thijs <[email protected]>
Co-authored-by: maxyodedara5 <[email protected]>
Co-authored-by: Thijs <[email protected]>
Co-authored-by: Thijs Franck <[email protected]>
…047fcb8'

git-subtree-dir: dynamic-typists
git-subtree-mainline: 4bae50a
git-subtree-split: 0b38e8c
Copy link
Contributor Author

@janine9vn janine9vn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello! Thanks for your patience as we get this review sorted out in GH format.

Documentation & README

The documentation throughout this project is of a very high level and impressive. This project would have been much more difficult to review with out. The READMEs in each section are helpful for explaining the layout and some decisions made. In some cases it may even be too thorough and in-depth, although I don't think you'll find anyone complaining. There are still a handful of instances that could use a bit more explanation or comments, but by and far the documentation for this is very well done.

The module docstrings can either be removed or be expanded on. Right now they're sitting in a bit of an uncertain zone of having some basic information, but not enough to prevent someone from going elsewhere to get a deeper-than-surface-level understanding of what the module is doing.

Also shoutout for the inclusion of the js.pyi, it was helpful for this review and to stop my IDE from complaining.

Code Quality & Organization

The code is also very well done. There are a few instances where I think some things are unnecessarily complicated, a little too long for a single function, or there are nested functions that can be broken apart / simplified. I'm not familiar with pyodide in the slightest, but the this code was still (mostly) easy to reason about.

That being said, I did get a bit lost in the sauce trying to make sense and understand the different controllers. That was one area where I do wish there a bit more documentation explaining what controller is used where and why. For instance, the drag_drop_grid_controller and the image_grid_controller sound like they do the exact same thing but worded slightly differently. Turns out that image_grid_controller does user drag_drop_grid_controller, but it took a little bit to trace that back and keep track of it all. So either a combination of a slight re-organization and slight-renaming or a document/diagram illustrating how they're all used could go a long way.

Commits

21 commits is not a lot of commits for a project this size. That number alone, looking at the scale and scope of this project, implies that some commits are likely bigger than they should be. Digging into it a bit, the true number of commits is lost at the Pull Request stage. The individual commit information is retained in the pull request, but when I'm viewing it locally there are just these giant commits that do a lot that I can't break apart into more manageable peices. So I recommend following an atomic git commit approach in the future. I like recommending Make Atomic Git Commits for further reading about atomic git commits and why they are beneficial.

Summary

Overall, this project is very well done. It has really solid code quality, excellent documentation, and the actual execution of it is impressive. Good job y'all~

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type of documentation is very impressive and thorough. Having READMEs in the differnt subfolders to dive deeper into the details of each is very much appreciated.

Comment on lines +74 to +75
# chose contrast based on the originals image brightness
watermark_contrast = int(self._get_brightness() * 0.8)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nicely done and a helpful comment as well.

@@ -0,0 +1,145 @@
"""Scramble functions for scrambling images in different ways."""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think a comment like this at the top of files is necessary. The name of this file and the functions contained within are enough imo.

Comment on lines +27 to +32
co_ordinates = [
(0, 0, 512, 512),
(512, 0, 1024, 512),
(0, 512, 512, 1024),
(512, 512, 1024, 1024),
]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fairly hardcoded for specific image sizes. Is the picture given guaranteed to be provided in the correct size?

Comment on lines +115 to +121
match scrambler:
case "rows":
scramble_rows(picture)
case "grid":
scramble_grid(picture)
case "circle":
scramble_circle(picture)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the most ideal usage of match-case, but I like the readability it provides here even if it's equivalent to if-elif statements.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preferred match for this since the performance impact is negligible

Comment on lines +68 to +69
num_tiles = len(picture.tiles)
for ring_position in range(1, num_tiles):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be condensed, having num_tiles as its own variable isn't doing much here.

background_element.classList.add("background-image")
self.root.appendChild(background_element)

for image in reversed(rotatable):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why reversed here? It's not clear why this needs to be reversed.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definitely requires some explanation.

We receive images from the API in the order: [background_image, smallest_ring, ..., largest_ring]. In HTML rendering, the last element in the list appears on top. Since each ring must remain selectable for user rotation, and considering the transparent part of a ring is still part of its clickable element, we need to ensure that smaller rings aren't obscured by larger ones. Thus, by reversing the list, we ensure smaller rings are rendered last (and therefore on top), keeping them selectable.

List[float]
List of rotation values in degrees.
"""
return [controller.current_rotation for controller in reversed(self._controllers)]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the order of the list of rotation values is important, but it's not clear which direction it should be or which direction it's starting in.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we create the controllers in reverse order, we need to again reverse the order here to build the solution that the API expects.


add_event_listener(confirm_button, "click", handle_post_solution) # type: ignore
add_event_listener(refresh_button, "click", handle_load_captcha) # type: ignore
add_event_listener(restart_button, "click", lambda _: app.reset())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than have a lambda to "eat" the argument, I would rather the reset() function itself in app.py discard/ignore all arguments given to it. reset() is only called here, so it feels a bit odd to know it will be passed an unnecessary event and that you have to go out of your way to discard it with a lambda.

Comment on lines +48 to +50
The function utilizes a nonlocal variable `is_loading_captcha` to prevent multiple
concurrent requests when the user repeatedly clicks the button. This ensures that the
application does not request another captcha until the previous one has been loaded.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Smart choice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants