-
-
Notifications
You must be signed in to change notification settings - Fork 664
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
ActionSheets: Refactor to tighten up types #4541
ActionSheets: Refactor to tighten up types #4541
Conversation
0b63cc4
to
15edce8
Compare
There's still some stuff that's not great about this: particularly, every Not sure what the best way to do something like this in flow is. Maybe each button should have it's own type, and we should have a |
The current state of where the Required by both message and header actionsheets: However, we probably want to change header actionsheets to stop using |
And just to be abundantly clear on where this stands: I think merging this PR as-is is an improvement (in that it's a step towards #4541), although this refactor is far from complete (I still need to make the changes I mentioned above). I'm going to keep working on this refactor, but I think it makes sense to review and merge this now just so the refactor doesn't turn into an enormous PR. |
Thanks @WesleyAC ! I like splitting I'm not such a fan of turning these signatures into having long lists of positional arguments (here 8 of them) -- I think well before that point it typically becomes better to use objects to effectively get named parameters, to avoid having to match up a long somewhat arbitrary sequence between definition and call site. That's part of what backgroundData.auth,
backgroundData.mute,
backgroundData.subscriptions,
backgroundData.ownUser,
backgroundData.flags, would be cleaner as an object, or as part of an object. Perhaps the simplest way to do this would be to pass literally Zooming out a bit, one thing you'll see we like to do in a refactor like this is to split it into a series of relatively small commits, each self-contained but only expressing a single idea. For some recent examples, take a look at #4437, #4424, or #4442. Here that might look something like:
I find that strategy helps a lot in reading and understanding and reviewing the changes. It also helps in making it possible to develop larger refactors and manage the complexity of them. (BTW chat thread here: https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/shared.20actionsheets.20code/near/1134303 for cross-reference when someone else, or our future selves after a few days from now, is reading this.) |
Definitely agreed it'd be good to stop passing it a (And then we should do something in the names to make it clear that this is the narrow the header is about, not the narrow of the surrounding view -- whereas the |
15edce8
to
e9f9f7d
Compare
@gnprice ok, I've split it up into multiple commits and changed most of the functions to take objects as args instead of positional args, should be ready for a review. I'm not sure what the preferred way of writing a function that takes only an object argument is — I've opted to use destructuring, and duplicate the names of the args in the function signature, but passing a named |
Oh, hmm, I didn't do it this way, but that does seem cleaner — I'll add another commit to change it to work like this. |
Ok, now it should be all good :) |
Just manually tested the new commits, everything appears to work as expected. |
Since this is split into separate commits, I'm just keeping on pushing refactoring commits here, let me know if that's not the correct thing to do. I figure we can merge them a few at a time, if we need/want to. |
5557600
to
a7d152e
Compare
Ok, I think I'm done for now — this is a pretty large stack of commits, but each individual one should be pretty easy to review, I think. Let me know if I should bias more towards waiting for feedback before making a big commit stack in the future. |
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.
Thanks for the revision! I appreciate how nicely split out these changes are.
I've read through to about here:
c261b26 ActionSheets: Split showActionSheet into multiple functions
489b6d2 ActionSheets: Factor out makeButtonCallback function
a6956b0 ActionSheets: Refactor construct*ActionButtons to avoid BackgroundData
0096646 ActionSheets: Replace ConstructSheetParams with more specific types
664626c ActionSheets: Remove ButtonCode, pass around objects instead
99efbd4 ActionSheets: Change ButtonDescription type to be more specific
963c978 ActionSheets: Have constructHeaderActionButtons stop taking message arg
and am about to go make and eat dinner, and I figure you may be online before I'm back at my desk. So I wanted to send you the comments I have so far. The remaining commits I haven't looked closely at are:
3f443c6 ActionSheets: Get rid of makeButtonCallback function
63d03d5 ActionSheets: Change HeaderButton callback to take stream and topic
769d85b ActionSheets: Remove message arg from showHeaderActionSheet
a7d152e ActionSheets: Remove startEditMessage from showHeaderActionSheet
Let me know if I should bias more towards waiting for feedback before making a big commit stack in the future.
This is about right for the scope to send as one PR (when the overall scope of a project is this or more, that is -- smaller PRs are of course great when the work can be done in something smaller 🙂 ).
I think the key thing to aim for is to try to post as a PR, or else post something on Zulip about what you've done / what's hard / what you've learned / etc., at least every day that you're working on a given thing. So if it's getting toward the end of your day and there's something you spent time on that day and haven't posted, then try to take some initial segment of those commits and polish them up to send as a PR.
src/message/messageActionSheet.js
Outdated
try { | ||
await pressedButton({ | ||
subscriptions: params.backgroundData.subscriptions, | ||
auth: params.backgroundData.auth, | ||
ownUser: params.backgroundData.ownUser, | ||
...params, | ||
...callbacks, | ||
}); |
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.
Seeing this duplication, I realize that it would have been a bit cleaner to have factored this piece out first and then split this function into two versions, rather than vice versa as I suggested above. 🙂 This is fine, though -- it's not a huge amount of duplication, and it goes away in the next commit.
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 ended up actually keeping the duplication, since that turned out much easier than making the types work out once we had more than one type of button — that's worth the pretty small amount of duplication, IMO (although if there's a nice flow way to write it, I'm happy to see it)
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.
Sent #4566 with a way to do this. I agree the duplication isn't a big problem because the code is so small. But the Alert.alert
bit in particular feels like the sort of thing that can easily get annoyingly out of sync when duplicated, so I think there's some value in keeping it deduplicated.
6124ae2
to
72ae42c
Compare
I've tested that the final commit here works on my android device, and |
72ae42c
to
082b7f7
Compare
082b7f7
to
1f0427b
Compare
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.
Thanks for the revisions! This all looks great, modulo the nit below. I'm going to go ahead and merge with just a small commit on top fixing that.
I also see your question at #4541 (comment) above, and after merging I'll take a few minutes to see what I can come up with.
src/message/messageActionSheet.js
Outdated
flags: FlagsState, | ||
}>, |
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: make explicitly inexact (here and a few others below)
This splits showActionSheet into a showHeaderActionSheet and a showMessageActionSheet function, since the two of them conceptually require different arguments and do different things. Right now, they take the same set of arguments, but this commit sets us up to change that in the future, and tighten up the typing more.
This changes the: * constructHeaderActionButtons * constructNonHeaderActionButtons * constructMessageActionButtons * constructOutboxActionButtons * showHeaderActionSheet * showMessageActionSheet functions in a few ways: * They no longer explicitly take a `BackgroundData` object, but instead take an inexact object with just the parameters that each function uses. * The show*ActionSheet functions have been converted to use named arguments via an object.
This removes the ButtonCode infrastructure, and instead has the code for constructing button lists pass around ButtonDescription objects. This will enable us to split `ButtonDescription` into a `HeaderButton` and `MessageButton` type (or a `Button<Message | Header>` type, more likely), and have each of those take only the arguments it needs - for instance, we can avoid passing `startEditMessage` callback to a `Button<Header>`, since we know that'll never be used. This also lets us avoid keeping around a global list of all possible buttons, while still being able to share button code across multiple actionsheets in a typesafe way (for instance, the cancel button). The main downside is that our tests now rely on the `title` of the button to check if the correct buttons have been inserted, since we no longer have a `ButtonCode` to compare. At first glance, this seems bad, but I think it's actually OK: * We apply i18n in the rendering step, so we don't need to worry about the strings being translated - there are no calls to `_` in the codepath that the tests are checking. * We're not really much worse off than we were before - previously, changing the name of a button in the code would necessitate changing the tests, now changing the title will require that. While a title change is probably more common, I don't think we're at any increased risk of "stringly typed" typo bugs - if we change a title, the tests will start failing and we'll need to go through and patch it up, but none of the non-test logic relies on the button titles.
This commit replaces the `ButtonDescription` type with a `Button<Args>` type, which will allow us to in the future just pass in the required arguments for each type of button (so that, for instance, a `Button<HeaderArgs>` doesn't need to require a `startEditMessage` callback).
Previously, long-pressing a PM header in the "All Messages" (or similar) view would pop up a actionsheet, which only showed the name of the PM and a "Cancel" button. This was pretty silly, and makes the ActionSheet code more complicated than it needs to be, so we'll just pop up a toast showing the name of the PM instead. This is useful in the case of a PM where the title is long enough that it's truncated in the UI. The code for the toast text is taken from `getActionSheetTitle` in src/message/messageActionSheet.js - it's duplicated in this commit for type safety reasons, but the duplication will be removed in the next commit.
This changes the constructHeaderActionButtons function to take a stream and topic, instead of a message, since that is conceptually closer to what it's doing. I haven't routed this through to showHeaderActionButton yet, since all of the button callbacks currently still require a Message, but that's the goal in the future.
…opic This changes the Button<HeaderArgs> callback to take a stream and topic, rather than a message, since the only thing the callbacks need is the stream and topic.
showHeaderActionSheet now takes a stream and topic, rather than a message, since we only used the stream and topic anyways.
It's intentional that these "background data" types are inexact object types: they're meant to be passed values that may have a larger menu of different pieces of background data (in particular values of the BackgroundData type defined in MessageList.js), and these types just specify the particular pieces of data that the particular function requires.
1f0427b
to
96ef22d
Compare
This will allow us to use the shared messageActionSheet code in the
React Native parts of the codebase, rather than only the webview parts
of the codebase. It's also generally a cleaner and more type-safe
approach.
The test coverage for this seems not great, but I manually tested
clicking on most of the buttons on both styles of action sheet in the
app.