-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Allow selecting previously uploaded image for picture upload #23072
Changes from 5 commits
1ce314d
a201faa
c4a6997
de5d995
5789587
d87bf9a
95156b8
e10e856
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,16 +2,23 @@ import { mdiImagePlus } from "@mdi/js"; | |
import type { TemplateResult } from "lit"; | ||
import { LitElement, css, html } from "lit"; | ||
import { customElement, property, state } from "lit/decorators"; | ||
import type { MediaPickedEvent } from "../data/media-player"; | ||
import { fireEvent } from "../common/dom/fire_event"; | ||
import { haStyle } from "../resources/styles"; | ||
import { createImage, generateImageThumbnailUrl } from "../data/image_upload"; | ||
import { | ||
MEDIA_PREFIX, | ||
getIdFromUrl, | ||
createImage, | ||
generateImageThumbnailUrl, | ||
} from "../data/image_upload"; | ||
import { showAlertDialog } from "../dialogs/generic/show-dialog-box"; | ||
import type { CropOptions } from "../dialogs/image-cropper-dialog/show-image-cropper-dialog"; | ||
import { showImageCropperDialog } from "../dialogs/image-cropper-dialog/show-image-cropper-dialog"; | ||
import type { HomeAssistant } from "../types"; | ||
import "./ha-button"; | ||
import "./ha-circular-progress"; | ||
import "./ha-file-upload"; | ||
import { showMediaBrowserDialog } from "./media-player/show-media-browser-dialog"; | ||
|
||
@customElement("ha-picture-upload") | ||
export class HaPictureUpload extends LitElement { | ||
|
@@ -29,6 +36,9 @@ export class HaPictureUpload extends LitElement { | |
|
||
@property({ type: Boolean }) public crop = false; | ||
|
||
@property({ type: Boolean, attribute: "select-media" }) public selectMedia = | ||
false; | ||
|
||
@property({ attribute: false }) public cropOptions?: CropOptions; | ||
|
||
@property({ type: Boolean }) public original = false; | ||
|
@@ -39,13 +49,32 @@ export class HaPictureUpload extends LitElement { | |
|
||
public render(): TemplateResult { | ||
if (!this.value) { | ||
/* eslint-disable lit-a11y/anchor-is-valid */ | ||
const secondary = | ||
this.secondary || | ||
(this.selectMedia | ||
? html`${this.hass.localize( | ||
"ui.components.picture-upload.secondary", | ||
{ | ||
select_media: html`<a | ||
href="javascript:" | ||
@click=${this._chooseMedia} | ||
>${this.hass.localize( | ||
"ui.components.picture-upload.select_media" | ||
)}</a | ||
>`, | ||
} | ||
)}` | ||
: undefined); | ||
/* eslint-enable lit-a11y/anchor-is-valid */ | ||
|
||
return html` | ||
<ha-file-upload | ||
.hass=${this.hass} | ||
.icon=${mdiImagePlus} | ||
.label=${this.label || | ||
this.hass.localize("ui.components.picture-upload.label")} | ||
.secondary=${this.secondary} | ||
.secondary=${secondary} | ||
.supports=${this.supports || | ||
this.hass.localize("ui.components.picture-upload.supported_formats")} | ||
.uploading=${this._uploading} | ||
|
@@ -93,7 +122,7 @@ export class HaPictureUpload extends LitElement { | |
this.value = null; | ||
} | ||
|
||
private async _cropFile(file: File) { | ||
private async _cropFile(file: File, mediaId?: string) { | ||
if (!["image/png", "image/jpeg", "image/gif"].includes(file.type)) { | ||
showAlertDialog(this, { | ||
text: this.hass.localize( | ||
|
@@ -109,7 +138,16 @@ export class HaPictureUpload extends LitElement { | |
aspectRatio: NaN, | ||
}, | ||
croppedCallback: (croppedFile) => { | ||
this._uploadFile(croppedFile); | ||
if (mediaId && croppedFile === file) { | ||
this.value = generateImageThumbnailUrl( | ||
mediaId, | ||
this.size, | ||
this.original | ||
); | ||
fireEvent(this, "change"); | ||
} else { | ||
this._uploadFile(croppedFile); | ||
} | ||
}, | ||
}); | ||
} | ||
|
@@ -141,16 +179,56 @@ export class HaPictureUpload extends LitElement { | |
} | ||
} | ||
|
||
private _chooseMedia = () => { | ||
showMediaBrowserDialog(this, { | ||
action: "pick", | ||
entityId: "browser", | ||
navigateIds: [ | ||
{ media_content_id: undefined, media_content_type: undefined }, | ||
{ | ||
media_content_id: MEDIA_PREFIX, | ||
media_content_type: "app", | ||
}, | ||
], | ||
minimumNavigateLevel: 2, | ||
mediaPickedCallback: async (pickedMedia: MediaPickedEvent) => { | ||
const mediaId = getIdFromUrl(pickedMedia.item.media_content_id); | ||
if (mediaId) { | ||
if (this.crop) { | ||
const url = generateImageThumbnailUrl(mediaId, undefined, true); | ||
const response = await fetch(url); | ||
const data = await response.blob(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can fail, please add error handling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you elaborate a bit what you want to see here? So HA gives us the list of images, we click on one, and then... it's not available? What should I do with that, a popup dialog that just says "unknown error"? I would have thought just whatever default logging exception to the console would be sufficient, and how this would usually be handled. Or what is the specific mode of failure you were thinking of? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good. If it fails to load use I know this is an edge case but http requests can always fail and showing it only in console won't help the user in the situation. |
||
const metadata = { | ||
type: pickedMedia.item.media_content_type, | ||
}; | ||
const file = new File([data], pickedMedia.item.title, metadata); | ||
this._cropFile(file, mediaId); | ||
} else { | ||
this.value = generateImageThumbnailUrl( | ||
mediaId, | ||
this.size, | ||
this.original | ||
); | ||
fireEvent(this, "change"); | ||
} | ||
} | ||
}, | ||
}); | ||
}; | ||
|
||
static get styles() { | ||
return [ | ||
haStyle, | ||
css` | ||
:host { | ||
display: block; | ||
height: 240px; | ||
} | ||
ha-file-upload { | ||
height: 100%; | ||
height: 240px; | ||
} | ||
ha-button.center { | ||
display: flex; | ||
align-items: center; | ||
} | ||
.center-vertical { | ||
display: flex; | ||
|
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 am not too sure about this check. Due I think to recent changes to dialogs/navigation, the href=# didn't work anymore, so I had to change to href="javascript:".
Eslint however doesn't seem to like the new "fake" anchor. I'm not sure how else to open a dialog from a link like was requested though.
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.
Mhh yeah not the nicest solution.
What about using a
button
tag and style it like a link?