Skip to content

Commit

Permalink
[FIX] mail: make image action usable on small images
Browse files Browse the repository at this point in the history
On small images, the actions to delete image is barely
usable. In mobile, these actions are always shown, so they
could even prevent clicking on attachment to view in dialog.
Also on big a image the 2 actions are far away, which is
can be exhausting.

This commit fixes the issue by using a dropdown when there
is more than 1 action or when the image is considered very
small. Images visual is at most 75px width and height, so
smaller images now show a background, which ensures image
actions and clicking on image for preview are both reachable
with ease.

closes odoo#180789

X-original-commit: 3466cb1
Signed-off-by: Didier Debondt (did) <[email protected]>
Signed-off-by: Alexandre Kühn (aku) <[email protected]>
  • Loading branch information
alexkuhn committed Sep 19, 2024
1 parent 7d72959 commit 64bdeed
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 17 deletions.
38 changes: 38 additions & 0 deletions addons/mail/static/src/core/common/attachment_list.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import { Component, useState } from "@odoo/owl";
import { isMobileOS } from "@web/core/browser/feature_detection";

import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { Dropdown } from "@web/core/dropdown/dropdown";
import { useDropdownState } from "@web/core/dropdown/dropdown_hooks";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { useFileViewer } from "@web/core/file_viewer/file_viewer_hook";
import { _t } from "@web/core/l10n/translation";
import { useService } from "@web/core/utils/hooks";
import { url } from "@web/core/utils/urls";

class ImageActions extends Component {
static components = { Dropdown, DropdownItem };
static props = ["actions", "imagesHeight"];
static template = "mail.ImageActions";

setup() {
super.setup();
this.actionsMenuState = useDropdownState();
this.isMobileOS = isMobileOS;
}
}

/**
* @typedef {Object} Props
* @property {import("models").Attachment[]} attachments
Expand All @@ -15,6 +31,7 @@ import { url } from "@web/core/utils/urls";
* @extends {Component<Props, Env>}
*/
export class AttachmentList extends Component {
static components = { ImageActions };
static props = ["attachments", "unlinkAttachment", "imagesHeight", "messageSearch?"];
static template = "mail.AttachmentList";

Expand All @@ -25,6 +42,8 @@ export class AttachmentList extends Component {
this.imagesWidth = 1920;
this.dialog = useService("dialog");
this.fileViewer = useFileViewer();
this.actionsMenuState = useDropdownState();
this.isMobileOS = isMobileOS;
}

/**
Expand Down Expand Up @@ -102,6 +121,25 @@ export class AttachmentList extends Component {
return this.env.inChatWindow && !this.env.alignedRight;
}

getActions(attachment) {
const res = [];
if (this.showDelete) {
res.push({
label: "Remove",
icon: "fa fa-trash",
onSelect: () => this.onClickUnlink(attachment),
});
}
if (this.canDownload(attachment)) {
res.push({
label: "Download",
icon: "fa fa-download",
onSelect: () => this.onClickDownload(attachment),
});
}
return res;
}

get showDelete() {
// in the composer they should all be implicitly deletable
if (this.env.inComposer) {
Expand Down
5 changes: 3 additions & 2 deletions addons/mail/static/src/core/common/attachment_list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
}

.o-mail-AttachmentImage {
min-width: 20px;
min-height: 20px;
min-width: 75px;
min-height: 75px;
background-color: $gray-200;

img {
object-fit: contain;
Expand Down
34 changes: 22 additions & 12 deletions addons/mail/static/src/core/common/attachment_list.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}" role="menu" >
<div t-foreach="images" t-as="attachment" t-key="attachment.id"
t-att-aria-label="attachment.filename"
class="o-mail-AttachmentImage d-flex position-relative flex-shrink-0 mw-100 mb-1 me-1"
class="o-mail-AttachmentImage d-flex position-relative flex-shrink-0 mw-100 mb-1 me-1 rounded"
t-att-title="attachment.name"
t-att-class="{ 'o-isUploading': attachment.uploading }"
tabindex="0"
Expand All @@ -34,16 +34,7 @@
<div t-if="attachment.uploading" class="position-absolute top-0 bottom-0 start-0 end-0 d-flex align-items-center justify-content-center" title="Uploading">
<i class="fa fa-spin fa-spinner"/>
</div>
<div class="position-absolute top-0 bottom-0 start-0 end-0 p-2 text-white o-opacity-hoverable opacity-0 opacity-100-hover d-flex align-items-end flax-wrap flex-column">
<button t-if="showDelete"
class="btn btn-sm btn-dark rounded opacity-75 opacity-100-hover"
tabindex="0" aria-label="Remove" role="menuitem" t-on-click.stop="() => this.onClickUnlink(attachment)" title="Remove">
<i class="fa fa-trash"/>
</button>
<button t-if="canDownload(attachment)" class="btn btn-sm btn-dark rounded opacity-75 opacity-100-hover mt-auto" t-on-click.stop="() => this.onClickDownload(attachment)" title="Download">
<i class="fa fa-download"/>
</button>
</div>
<ImageActions actions="getActions(attachment)" imagesHeight="props.imagesHeight"/>
</div>
</div>
<div class="grid row-gap-0 column-gap-0">
Expand Down Expand Up @@ -89,7 +80,7 @@
</button>
<!-- t-attf-class overridden in extensions -->
<button t-if="canDownload(attachment)" class="btn d-flex align-items-center justify-content-center w-100 h-100 rounded-0"
t-attf-class="bg-300"
t-attf-class="{{ bg-300 }}"
t-on-click.stop="() => this.onClickDownload(attachment)" title="Download"
>
<i class="fa fa-download" role="img" aria-label="Download"/>
Expand All @@ -100,4 +91,23 @@
</div>
</t>

<t t-name="mail.ImageActions">
<div class="position-absolute top-0 bottom-0 start-0 end-0 p-1 text-white o-opacity-hoverable opacity-100-hover d-flex align-items-end flax-wrap flex-column" t-att-class="{ 'opacity-0': !actionsMenuState.isOpen }">
<button t-if="props.actions.length === 1 and props.imagesHeight gt 75" class="btn btn-sm btn-light rounded px-1 py-0" t-att-class="{ 'opacity-75 opacity-100-hover': !isMobileOS }" tabindex="0" t-att-aria-label="props.actions[0].label" t-att-title="props.actions[0].label" role="menuitem" t-on-click.stop="props.actions[0].onSelect">
<i t-att-class="props.actions[0].icon"/>
</button>
<Dropdown t-else="" menuClass="'d-flex flex-column py-0' + (props.actions.length gt 1 ? ' py-0' : '')" state="actionsMenuState" position="'right-start'">
<button class="btn btn-sm btn-light rounded px-1 py-0" t-att-class="{ 'opacity-75 opacity-100-hover': !isMobileOS }" tabindex="0" aria-label="Actions" title="Actions" role="menuitem">
<i class="oi oi-chevron-down"/>
</button>
<t t-set-slot="content">
<DropdownItem t-foreach="props.actions" t-as="action" t-key="action_index" class="'px-2 py-1 d-flex align-items-center rounded-0'" onSelected="action.onSelect">
<i class="fa-fw" t-att-class="action.icon"/>
<span class="mx-2" t-esc="action.label"/>
</DropdownItem>
</t>
</Dropdown>
</div>
</t>

</templates>
2 changes: 1 addition & 1 deletion addons/mail/static/src/core/common/composer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
t-if="allowUpload and props.composer.attachments.length > 0"
attachments="props.composer.attachments"
unlinkAttachment.bind="(...args) => attachmentUploader.unlink(...args)"
imagesHeight="50"/>
imagesHeight="75"/>
<Picker t-props="picker"/>
</div>
</div>
Expand Down
6 changes: 4 additions & 2 deletions addons/mail/static/tests/message/message.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,8 @@ test("allow attachment delete on authored message", async () => {
});
await start();
await openDiscuss(channelId);
await click(".o-mail-AttachmentImage [title='Remove']");
await click(".o-mail-AttachmentImage [title='Actions']");
await click(".dropdown-item", { text: "Remove" });
await contains(".modal-dialog .modal-body", { text: 'Do you really want to delete "BLAH"?' });
await click(".modal-footer .btn-primary");
await contains(".o-mail-AttachmentCard", { count: 0 });
Expand Down Expand Up @@ -1257,7 +1258,8 @@ test("allow attachment image download on message", async () => {
});
await start();
await openDiscuss(channelId);
await contains(".o-mail-AttachmentImage .fa-download");
await click(".o-mail-AttachmentImage [title='Actions']");
await contains(".dropdown-item", { text: "Download" });
});

test("Can download all files of a message", async () => {
Expand Down

0 comments on commit 64bdeed

Please sign in to comment.