Skip to content

Commit

Permalink
#2347 - Build Image viewer in the app (#2367)
Browse files Browse the repository at this point in the history
* build the skeleton ImageViwerModal.vue / make sure it open/close

* add blurry bg / add modal-btn / implement onLoad handler

* calculation logic to determine the minimum zoom value

* update the min zoom calc logic again (incomplete)

* fix the initial render logic

* add zoom slider UI to the modal

* fix typo in slider component

* custom UI/UX for the slider / dynamic zoom update to the image

* extract PointerEventsMixin.js and add it to the image viewer

* allow moving around the image

* add some helper comments for auto-translation logic

* fix the broken blurry-bg and work on Greg's feedback

* make sure ImageViwerModal.vue is triggered by various call-to-actions

* implement zoom in/out triggered by wheel event

* pass image meta-data to ImageViewerModal.vue

* image metadata UI on the modal

* implement zoom/move by touch events

* fix/optimize zoom action by pinch gesture

* fix linter err

* make sure the color looks good in both themes

* use css transform() instead of updating width and height

* fix the slider bug / fix cypress failure

* typo in name / fix pinned-msg issue

* Fix for Greg CR 1.

* pass the zoom action point

* simplify auto-translation logic for when zoom without center-point

* zooming into a certain point

* percent x,y while pointed zoom action should be fixed

* fix the buggy zoom-into-certain-point

* fix linter err

* fix all bugs related to 'zoom-into-ceertain-point'

* uncomment the err handling logic

* resolve TODO: debouncing the resize handler

* Greg's CR / fix the bug where zoom-slider value is string

* fix the bug where pinch-out -> in is not seamless

* uncomment SW err handling

* comments update

* comment update again

* remove console.log

* cursor style

* implement instant zoom in/out upon single click

* fix the linter error

* make sure the logic is not executed in touch-devices

* update resizehandler

* minor consistency fix

---------

Co-authored-by: Greg Slepak <contact@taoeffect.com>
  • Loading branch information
SebinSong and taoeffect authored Oct 21, 2024
1 parent f3250c1 commit 349e622
Show file tree
Hide file tree
Showing 15 changed files with 960 additions and 94 deletions.
2 changes: 1 addition & 1 deletion cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = defineConfig({
projectId: 'q6whky',
experimentalMemoryManagement: true,
// NOTE: When running 'cypress open' on a browser, high memory usage often leads to crashing the browser.
// So setting 'numTestsKeptInMemory' to a relatvely low number here. (reference: https://docs.cypress.io/guides/references/configuration#Global)
// So setting 'numTestsKeptInMemory' to a relatively low number here. (reference: https://docs.cypress.io/guides/references/configuration#Global)
numTestsKeptInMemory: 3,
e2e: {
// We've imported your old cypress plugins here.
Expand Down
1 change: 1 addition & 0 deletions frontend/utils/lazyLoadedView.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ lazyModal('SendThankYouModal', () => import('../views/containers/payments/SendTh
lazyModal('ThankYouNoteModal', () => import('../views/containers/payments/ThankYouNoteModal.vue'))
lazyModal('AvatarEditorModal', () => import('../views/components/avatar-editor/AvatarEditorModal.vue'))
lazyModal('ChatFileAttachmentWarningModal', () => import('../views/containers/chatroom/file-attachment/ChatFileAttachmentWarningModal.vue'))
lazyModal('ImageViewerModal', () => import('../views/containers/chatroom/image-viewer/ImageViewerModal.vue'))
lazyModalFullScreen('GroupCreationModal', () => import('../views/containers/group-settings/GroupCreationModal.vue'))
lazyModalFullScreen('GroupJoinModal', () => import('../views/containers/group-settings/GroupJoinModal.vue'))
lazyModalFullScreen('GroupMembersAllModal', () => import('../views/containers/dashboard/GroupMembersAllModal.vue'))
Expand Down
13 changes: 13 additions & 0 deletions frontend/views/components/SliderContinuous.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ export default ({
const percent = this.getPercent(value)
this.ephemeral.styleVars = `--percent: ${percent}%; --factor: ${this.getFactor(percent)};`
}
},
watch: {
value (newVal) {
if (newVal !== undefined) {
this.updateSlider(newVal)
}
},
min () {
this.updateSlider(this.value)
},
max () {
this.updateSlider(this.value)
}
}
}: Object)
</script>
Expand Down
8 changes: 4 additions & 4 deletions frontend/views/components/avatar-editor/AvatarEditorModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ modal-template(
:zoom='zoom'
:imageUrl='ephemeral.replaceImageUrl'
@pointer-wheel='HandleWheelOnCanvas'
@pinch-in='decrementSlider(3)'
@pinch-out='incrementSlider(3)'
@pinch-in='decrementSlider(4)'
@pinch-out='incrementSlider(4)'
)

.c-slider-container
Expand Down Expand Up @@ -138,8 +138,8 @@ export default ({
this.$refs.slider.updateSlider(this.form.slider)
},
HandleWheelOnCanvas ({ deltaY }) {
if (deltaY < 0) this.incrementSlider(2)
else this.decrementSlider(2)
if (deltaY < 0) this.incrementSlider(3)
else this.decrementSlider(3)
},
loadPhotoChange (fileList) {
if (!fileList.length) return
Expand Down
4 changes: 2 additions & 2 deletions frontend/views/components/avatar-editor/EditorCanvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
import { mapGetters } from 'vuex'
import { imageDataURItoBlob } from '@utils/image.js'
import { EDITED_AVATAR_DIAMETER } from './avatar-editor-constants.js'
import pointerEventsMixin from './avatar-editor-pointer-events-setup.js'
import pointerEventsMixinFactory from '@view-utils/pointerEventsMixins.js'
export default {
name: 'AvatarEditorCanvas',
mixins: [pointerEventsMixin],
mixins: [pointerEventsMixinFactory()],
data () {
return {
ephemeral: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ export const ZOOM_SLIDER_MAX = 100
export const IMAGE_SCALE_MIN = 1
export const IMAGE_SCALE_MAX = 5
export const EDITED_AVATAR_DIAMETER = 512
export const PINCH_ZOOM_THRESHOLD = 2.5

This file was deleted.

2 changes: 2 additions & 0 deletions frontend/views/containers/chatroom/MessageBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
:variant='variant'
:isForDownload='true'
:isMsgSender='isMsgSender'
:ownerID='from'
:createdAt='datetime'
:isGroupCreator='isGroupCreator'
@delete-attachment='deleteAttachment'
)
Expand Down
1 change: 1 addition & 0 deletions frontend/views/containers/chatroom/PinnedMessages.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
v-if='hasAttachments(msg)'
:attachmentList='msg.attachments'
:isForDownload='true'
:ownerID='msg.from'
:variant='messageSentVariant'
)
.c-message-reactions-wrapper
Expand Down
1 change: 1 addition & 0 deletions frontend/views/containers/chatroom/SendArea.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
chat-attachment-preview(
v-if='ephemeral.attachments.length'
:attachmentList='ephemeral.attachments'
:ownerID='ourIdentityContractId'
@remove='removeAttachment'
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<template lang='pug'>
.c-attachment-container(ref='container' :class='{ "is-for-download": isForDownload }')

// Displaying attachments as part of message
template(v-if='isForDownload')
.c-attachment-preview(
v-for='(entry, entryIndex) in attachmentList'
Expand All @@ -20,6 +22,7 @@
v-if='objectURLList[entryIndex]'
:src='objectURLList[entryIndex]'
:alt='entry.name'
@click='openImageViewer(objectURLList[entryIndex], entry)'
)
.loading-box(v-else :style='loadingBoxStyles[entryIndex]')

Expand Down Expand Up @@ -51,11 +54,13 @@
)
i.icon-trash-alt

// Displaying attachments as part of <send-area />
template(v-else)
.c-attachment-preview(
v-for='(entry, entryIndex) in attachmentList'
:key='entryIndex'
:class='"is-" + fileType(entry)'
@click='openImageViewer(entry.url, entry)'
)
img.c-preview-img(
v-if='fileType(entry) === "image" && entry.url'
Expand All @@ -73,7 +78,7 @@
button.c-attachment-remove-btn(
type='button'
:aria-label='L("Remove attachment")'
@click='$emit("remove", entry.url)'
@click.stop='$emit("remove", entry.url)'
)
i.icon-times

Expand All @@ -88,6 +93,7 @@ import Tooltip from '@components/Tooltip.vue'
import { MESSAGE_VARIANTS } from '@model/contracts/shared/constants.js'
import { getFileExtension, getFileType } from '@view-utils/filters.js'
import { Secret } from '~/shared/domains/chelonia/Secret.js'
import { OPEN_MODAL } from '@utils/events.js'
export default {
name: 'ChatAttachmentPreview',
Expand All @@ -107,7 +113,9 @@ export default {
},
isGroupCreator: Boolean,
isForDownload: Boolean,
isMsgSender: Boolean
isMsgSender: Boolean,
ownerID: String,
createdAt: [Date, String]
},
data () {
return {
Expand Down Expand Up @@ -203,6 +211,22 @@ export default {
width: `${widthInPixel}px`,
height: `${heightInPixel}px`
}
},
openImageViewer (objectURL, data) {
if (objectURL) {
sbp(
'okTurtles.events/emit', OPEN_MODAL, 'ImageViewerModal',
null,
{
metaData: {
name: data.name,
ownerID: this.ownerID,
imgUrl: objectURL,
createdAt: this.createdAt || new Date()
}
}
)
}
}
},
watch: {
Expand Down Expand Up @@ -252,7 +276,6 @@ export default {
position: absolute;
right: 0.5rem;
top: 0;
bottom: 0;
.c-attachment-actions {
display: flex;
Expand Down Expand Up @@ -290,7 +313,8 @@ export default {
padding: 0.5rem;
img {
pointer-events: none;
user-select: none;
cursor: pointer;
max-width: 100%;
max-height: 20rem;
Expand Down Expand Up @@ -320,6 +344,7 @@ export default {
&.is-image {
width: 4.5rem;
height: 4.5rem;
cursor: pointer;
.c-preview-img {
pointer-events: none;
Expand Down
Loading

0 comments on commit 349e622

Please sign in to comment.