Closed mvtglobally closed 1 year ago
Triggered auto assignment to @trjExpensify (AutoAssignerTriage
), see https://stackoverflow.com/c/expensify/questions/4749 for more details.
Triggered auto assignment to @megankelso (Design
), see these Stack Overflow questions for more details.
Oh, this is cool! What are we thinking in terms of the UI for the controls for this? We should probably loop in design before moving this on to further, so I'm adding the design
label for now and dropping the priority to weekly
. After which, we can update the OP.
In the meantime, here are some quick thoughts:
When the member is on the most recent attachment in the chat, there's only a left arrow icon (centered and left-aligned?) in the preview screen.
If the member is previewing an attachment "further back" in the history, there will also be a right arrow icon (centered and right-aligned?) to navigate "forward" to the next attachment preview
On desktop/Web: The arrow can be clicked to navigate to the next attachment preview, or the left/right arrow keys on the keyboard can be used
On mobile/mWeb: The arrow can be tapped or the member can swipe left/right on the preview to navigate to the next attachment preview depending on the direction
Should we give members the ability to dismiss/hide the navigation arrows in some capacity? On web/desktop I can see maybe only revealing the arrow(s) on hover? On smaller screens like mobile/mWeb they might get in the way, if we don't offer the ability to tap to dismiss/hide them in some capacity?
CC: @shawnborton
Yeah I'm mostly curious what we consider to be the total batch of attachments that you would cycle between. Is it only the attachments on a given message/thread, or could you cycle through all attachments across all messages in a chat?
Taking a look at Slack, it seems like on desktop you can only cycle through the group of attachments found throughout an entire message + subsequent thread messages. On mobile, it seems like you can cycle through everything found in a given chat/room.
@trjExpensify do you prefer one or the other? Maybe we can take this to the room for a quick discussion too.
Yeah, good question. I personally prefer being able to cycle through all attachments across all messages in a chat. The limit on message + threaded messages on Slack desktop is always a bit of a pain, IMO.
A neat thing WhatsApp does if you exit out of the attachment is navigate you back in the chat history to where it was originally posted for the added context in and around when it was sent.
Posted on the original thread here.
Followed up in the slack thread, sorry I missed the replies! 😅
Pulling a couple of things out of the Slack thread..
We don't have threads yet, and similarly one message is one attachment, so cycling through all attachments across all messages in a chat seems to be where we're at here?
I think we can probably descope this for now, though I agree it would be nice for speed scrolling. Especially if you know you're trying to get back to a point in time looking for something.
As I mentioned in the thread, I don’t have a strong opinion on looping back to the most recent/oldest when you reach the end/beginning. I think we’d need to make that clear if we allowed for it though, which presumably means including some indication of date/time as well. Otherwise you'd have the perception of infinitely scrolling back, unaware that you've looped back to the start.
Agree with your first two points. I think we can descope wrapping too.
Nice, works for me! 👍
Okay cool, so what are the next steps here? We're ready to mock it up at this point, right?
That makes sense to me - looks like this is already assigned to @megankelso.
@trjExpensify can you update the original comment to reflect what the desired solution/expected result should be, and then Megan can make some mocks? I think we'll just need some left/right arrows to exist in the attachment viewer modal.
Okay cool, OP has been updated! The only thing I'm unsure of for how we're going to handle at this point is this one:
Should we give members the ability to dismiss/hide the navigation arrows in some capacity? On web/desktop I can see maybe only revealing the arrow(s) on hover? On smaller screens like mobile/mWeb they might get in the way, if we don't offer the ability to tap to dismiss/hide them in some capacity?
I like the idea of using hover for web. On mobile, we could just do it where a single tap on the image hides/shows the arrows?
On mobile, we could just do it where a single tap on the image hides/shows the arrows?
Works for me! 👍
some ideas for this
the hover/tap made me think y'all were suggesting the arrows as an overlay, would probably need to style differently but on first pass I prefer them not appearing over the image. curious for thoughts
I think it's pretty standard that the arrows would always be on the left & right edges of the screen, so I prefer those mockups in comparison to the mockups where the arrows are below the image.
My concern with using white arrows is that if the attachment was white, you wouldn't see the arrow. Could we see a version where the arrows just use our standard button styling? Perhaps even borrowing some of the round styles you used for the video call mocks you made.
Also a small nitpick: can you update the screenshots to use the current attachment modal styling? It has a subheader for the filename as well as a bottom border:
I'm not sure what our standard button styling is but here are the ones I know of. I think the icon alone looks best but even the grey disappears on some images (big time on this one)
also, do they the arrows in the circles feel a bit big to you? there's at 20 px but I wonder if we could bump down to 16 to allow for a smaller circle.
You can find all of our standard button styles in our component library, here is for reference though:
So you have the sizes of:
I think we'd want these to be at least medium size so they are reasonably tappable on mobile devices. So that being said, 40px button with a 20px icon might feel good.
I think having a gray background is a good idea because this way we guarantee that the arrow will be visible on this gray background, even if the gray gets lost on the image. Also, this way we stay consistent and we don't introduce a new button style.
here's the 40/20 button size. also it appears vertical photos may not appear with a border on mobile, so I updated that.
I personally think these looks pretty chunky and prefer the arrows alone below the image. For mobile, I assume most people will swipe to see other attachments so I think including these are mostly to show you can scroll.
I can understand how the 40/20 buttons are more standard though. If we do the tap to hide/show, perhaps they won't feel so obtrusive.
Personally I think that looks great. Again, with arrows only, they can easily get lost depending on the image that is behind them so we very easily run into a usability issue. This also feels consistent with other button styles.
I was suggesting the arrows go below the image not on top.
Anyway, understand this solution feels more consistent. Thinking web would look something like this then
For web, I was thinking the arrows would be closer to the edge of the screen. Especially since the attachment could be wider. Here is what Slack does for reference:
Thoughts?
yeah we could move them over
Cool, I think that makes more sense. Thanks!
ok for easy reference, mockups here! I think this is all we need.
Purrrrfect, thanks! 😸
Updated the OP to include the mocks and passing this over to engineering
triage before going external. 👍
Triggered auto assignment to @alex-mechler (Engineering
), see https://stackoverflow.com/c/expensify/questions/4319 for more details.
I didnt realize how much I needed this before I saw this issue 😅
Looks good to go external!
Current assignee @trjExpensify is eligible for the External assigner, not assigning anyone new.
Triggered auto assignment to Contributor-plus team member for initial proposal review - @Santhosh-Sellavel (Exported
)
Triggered auto assignment to @chiragsalian (Exported
), see https://stackoverflow.com/c/expensify/questions/7972 for more details.
Job on Upwork here: https://www.upwork.com/jobs/~011ca7e66b62951030
@trjExpensify Let's Double this one!
cc: @chiragsalian
Yep, back from OoO today. Doubled the job on Upwork.
Waiting on proposals.
I think it's time to double this! cc: @trjExpensify @chiragsalian
Doubled on Upwork here.
Let's double this one up @trjExpensify.
cc: @chiragsalian
Doubled!.
Use the navigator to retrieve the reportId from within the ImageRenderer.
Navigation.getActiveRoute().replace('/r/', "")
This allows the modal to use Onyx and retrieve the reportActions for the proper id. From here a function called show
is called when an image is pressed inside a chat, which can be used to create an array of attachment urls from the reportActions data. The array's findIndex is called to get the matching index of the current url and a page is set up to track the index. An event on press for the arrow will check if the page is within bounds and iterate along with changing the sourceURL on the state.
The arrows are set up using a View component with flexbox and absolute position, they sit next to the attachment view with a boolean that disables them is the reportId doesn't exist. I think there might a couple places I need to add these arrows so I might just create a function to reduce code.
I know the arrows don't match the previous designs, but I wanted to get the positioning right before exploring what's available with the icons and any use cases I should cover with disabling them.
@JediWattson Seems you are new here, welcome! Thanks for your interest to solve this, the results look promising!
Would you please elaborate more on technical code changes? so that I can review the proposal.
Look at this past jobs as a reference to write proposals!
And If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
I actually made a few changes to the previous, but I'll get into more details with code examples this time!
I'll start with the modal showing, which seems to be this callback function that sets the state in the modal. I added a piece of data to obtain the report id here.
show: () => {
const reportId = Navigation.getActiveRoute().replace('/r/', "")
this.setState({ reportId, isModalOpen: true});
},
the report id, along with a callback function from the modal are sent to a component. The current url is sent so the current index can be found in the creation of the attachment array.
{this.state.reportId && (
<AttachmentNav
reportId={this.state.reportId}
onArrowPress={this.onArrowPress}
sourceURL={this.state.sourceURL}
/>
)}
I moved most of what I described before into a component, which is wrapped in withOnyx to provide the data for attachments.
export default withOnyx({
reportActions: {
key: ({reportId}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportId}`,
canEvict: true
},
})(AttachmentsNav)
I start the creation of the attachment array by converting the actions to an array using Object.values, this value also is used as a dependency in useEffect by determining if the function should be called based on the length of this array.
const actionsArr = Object.values(reportActions)
I use the reduce function to essentially filter and map the actions into only the urls for attachments
const nextAttachments = actionsArr.reduce((arr, rep, index) => {
const matches = CONST.REGEX.ATTACHMENT_SRC.exec(rep.originalMessage?.html)
if(matches){
if(matches[1].includes(sourceURL))
setPage(arr.length)
const url = matches[1].replace(
CONFIG.EXPENSIFY.EXPENSIFY_URL,
CONFIG.EXPENSIFY.URL_API_ROOT,
)
arr.push(url)
}
return arr
}, [])
setAttachments(nextAttachments)
I guess a few things to note here as well is, I'm using a function component for AttachmentsNav and the useState hook to hold both the attachments along with a page or index that I initialize with the matching sourceURL. Finally I tried to use the replace function along with these url constants provided to prevent CORS I believe.
Next I'll show the pagination here, and I'll start with the jsx because it's where the event starts.
<View style={{ width: "90%", position: "absolute", justifyContent: "space-between", alignItems: "center", flexDirection: "row" }}>
<Pressable onPress={() => handlePress(true)} style={{ cursor: "pointer" }}>
<Icon src={BackArrow} height={42} width={42} />
</Pressable>
<Pressable onPress={() => handlePress()} style={{ cursor: "pointer" }}>
<Icon src={ArrowRight} height={42} width={42} />
</Pressable>
</View>
I'll say right off the bat that I should use constants for styles here, in fact I'll try to get that in later. But what you see in the Pressable component is an event onPress that calls a function handlePress. The idea is to keep the code clean and send true if it's a back press and I'll show the function here to get a better understanding.
function handlePress(isBack){
if(isBack ? page-1 < 0 : page+1 === attachments.length) return
const nextIndex = isBack ? page-1 : page+1
onArrowPress(attachments[nextIndex])
setPage(nextIndex)
}
Here it starts with a guard to check the index is within bounds, then appropriately changes the index and set it along with the new sourceURL, which is sent to the parent component.
onArrowPress(sourceURL){
this.setState({sourceURL})
}
now the modal will reload the with the new url and it'll look like the use is navigating through the chat's attachments.
Thanks for your consideration!
@JediWattson I appreciate your effort, Sorry I am not able to follow you completely. Can you share the full proposal or elaborate a bit more clearly.
Example:
// Full Code for the component
// Overview of component code snippets
Existing
component Image, making the following changes.
// Changes snippet and elaborate why if needed.
.....
Sure thing, I think I've been looking at bug proposals when I should have picked out a feature from the link you posted. I certainly don't mind trying to get this right.
/// imports up here
function AttachmentsNav({ reportActions, onArrowPress, sourceURL }) {
const actionsArr = Object.values(reportActions)
const [page, setPage] = useState(-1)
const [attachments, setAttachments] = useState([])
useEffect(function(){
const nextAttachments = actionsArr.reduce((arr, rep, index) => {
const matches = CONST.REGEX.ATTACHMENT_SRC.exec(rep.originalMessage?.html)
if(matches){
if(matches[1].includes(sourceURL))
setPage(arr.length)
const url = matches[1].replace(
CONFIG.EXPENSIFY.EXPENSIFY_URL,
CONFIG.EXPENSIFY.URL_API_ROOT,
)
arr.push(url)
}
return arr
}, [])
setAttachments(nextAttachments)
}, [actionsArr.length])
function handlePress(isBack){
if(isBack ? page-1 < 0 : page+1 === attachments.length) return
const nextIndex = isBack ? page-1 : page+1
onArrowPress(attachments[nextIndex])
setPage(nextIndex)
}
return (
<View style={{ width: "90%", position: "absolute", justifyContent: "space-between", alignItems: "center", flexDirection: "row" }}>
<Pressable onPress={() => handlePress(true)} style={{ cursor: "pointer" }}>
<Icon src={BackArrow} height={42} width={42} />
</Pressable>
<Pressable onPress={() => handlePress()} style={{ cursor: "pointer" }}>
<Icon src={ArrowRight} height={42} width={42} />
</Pressable>
</View>
)
}
export default withOnyx({
reportActions: {
key: ({reportId}) => ${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportId}
,
canEvict: true
},
})(AttachmentsNav)
2. Use the existing component AttachmentModal, making the following changes
in the show function here:
https://github.com/Expensify/App/blob/75d9014c75befb7655e78653c65f4d2e0c0f0cdf/src/components/AttachmentModal.js#L227
I added reportId to the state update which I get using the Navigation route
```js
show: () => {
const reportId = Navigation.getActiveRoute().replace('/r/', "")
this.setState({ reportId, isModalOpen: true});
}
the carousel component will sit next to the AttachmentView component here https://github.com/Expensify/App/blob/75d9014c75befb7655e78653c65f4d2e0c0f0cdf/src/components/AttachmentModal.js#L183
this will render if reportId exists
{this.state.reportId && (
<AttachmentNav
reportId={this.state.reportId}
onArrowPress={this.onArrowPress}
sourceURL={this.state.sourceURL}
/>
)}
lastly, there's a callback function added to AttachmentModal called onArrowPress, this will set the new url from the carousel component.
onArrowPress(sourceURL){
this.setState({sourceURL})
}
Still discussing proposals. Not overdue. Also demoting to weekly.
@JediWattson can you share ATTACHMENT_SRC
regex?
That would look like:
{
...,
ATTACHMENT_SRC: /data-expensify-source="([^"]+)"/
}
I found it in this forum and modified it to look at data-expensify-source since that seemed unique to attachments that I found in this boolean https://github.com/Expensify/App/blob/75d9014c75befb7655e78653c65f4d2e0c0f0cdf/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js#L30
I'm not sure what I am missing pressing next or back not working, can you share a working video?
@JediWattson
If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Problem:
It will be a nice UX touch for the user, adding convenience while finding an old media file.
Solution:
Add an option to cycle between media when opened via swipe/arrow keys/buttons.
Action Performed:
Expected Result:
Actual Result:
We don't support cycling through attachments in a chat currently.
Workaround:
Close the attachment modal, then scroll to the next attachment and open it.
Platform:
Where is this issue occurring?
Version Number: 1.1.39-1 Reproducible in staging?: Y Reproducible in production?: Y Logs: https://stackoverflow.com/c/expensify/questions/4856 Notes/Photos/Videos:
Upwork URL: https://www.upwork.com/jobs/~011ca7e66b62951030 Issue reported by: @sig5 Slack conversation: https://expensify.slack.com/archives/C01GTK53T8Q/p1644597095180509
View all open jobs on GitHub