diff --git a/src/components/media-player/ha-media-player-browse.ts b/src/components/media-player/ha-media-player-browse.ts
index 97b8963919..be644eacca 100644
--- a/src/components/media-player/ha-media-player-browse.ts
+++ b/src/components/media-player/ha-media-player-browse.ts
@@ -1,7 +1,7 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item";
-import { mdiPlay, mdiPlus } from "@mdi/js";
+import { mdiArrowUpRight, mdiPlay, mdiPlus } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip";
import {
css,
@@ -265,32 +265,25 @@ export class HaMediaPlayerBrowse extends LitElement {
: !currentItem.children?.length
? html`
+ `
+ : this.hass.localize(
+ "ui.components.media-browser.no_items"
+ )}
`
: childrenMediaClass.layout === "grid"
@@ -772,6 +765,18 @@ export class HaMediaPlayerBrowse extends LitElement {
padding-left: 32px;
}
+ .highlight-add-button {
+ display: flex;
+ flex-direction: row-reverse;
+ margin-right: 48px;
+ }
+
+ .highlight-add-button ha-svg-icon {
+ position: relative;
+ top: -0.5em;
+ margin-left: 8px;
+ }
+
.content {
overflow-y: auto;
box-sizing: border-box;
diff --git a/src/panels/media-browser/ha-panel-media-browser.ts b/src/panels/media-browser/ha-panel-media-browser.ts
index 7a2590b903..ad47077d0f 100644
--- a/src/panels/media-browser/ha-panel-media-browser.ts
+++ b/src/panels/media-browser/ha-panel-media-browser.ts
@@ -15,6 +15,7 @@ import { LocalStorage } from "../../common/decorators/local-storage";
import { fireEvent, HASSDomEvent } from "../../common/dom/fire_event";
import { navigate } from "../../common/navigate";
import "../../components/ha-menu-button";
+import "../../components/ha-circular-progress";
import "../../components/ha-icon-button";
import "../../components/ha-svg-icon";
import "../../components/media-player/ha-media-player-browse";
@@ -64,6 +65,8 @@ class PanelMediaBrowser extends LitElement {
@state() _currentItem?: MediaPlayerItem;
+ @state() _uploading = 0;
+
private _navigateIds: MediaPlayerItemId[] = [
{
media_content_id: undefined,
@@ -107,12 +110,34 @@ class PanelMediaBrowser extends LitElement {
)
? html`
0
+ ? this.hass.localize(
+ "ui.components.media-browser.file_management.uploading",
+ {
+ count: this._uploading,
+ }
+ )
+ : this.hass.localize(
+ "ui.components.media-browser.file_management.add_media"
+ )}
+ .disabled=${this._uploading > 0}
@click=${this._startUpload}
>
-
+ ${this._uploading > 0
+ ? html`
+
+ `
+ : html`
+
+ `}
`
: ""}
@@ -255,29 +280,41 @@ class PanelMediaBrowser extends LitElement {
}
private async _startUpload() {
+ if (this._uploading > 0) {
+ return;
+ }
const input = document.createElement("input");
input.type = "file";
input.accept = "audio/*,video/*,image/*";
- input.addEventListener("change", async () => {
- try {
- await uploadLocalMedia(
- this.hass,
- this._currentItem!.media_content_id!,
- input.files![0]
- );
- } catch (err: any) {
- showAlertDialog(this, {
- text: this.hass.localize(
- "ui.components.media-browser.file_management.upload_failed",
- {
- reason: err.message || err,
- }
- ),
- });
- return;
- }
- await this._browser.refresh();
- });
+ input.multiple = true;
+ input.addEventListener(
+ "change",
+ async () => {
+ const files = input.files!;
+ const target = this._currentItem!.media_content_id!;
+
+ for (let i = 0; i < files.length; i++) {
+ this._uploading = files.length - i;
+ try {
+ // eslint-disable-next-line no-await-in-loop
+ await uploadLocalMedia(this.hass, target, files[i]);
+ } catch (err: any) {
+ showAlertDialog(this, {
+ text: this.hass.localize(
+ "ui.components.media-browser.file_management.upload_failed",
+ {
+ reason: err.message || err,
+ }
+ ),
+ });
+ break;
+ }
+ }
+ this._uploading = 0;
+ await this._browser.refresh();
+ },
+ { once: true }
+ );
input.click();
}
@@ -285,6 +322,12 @@ class PanelMediaBrowser extends LitElement {
return [
haStyle,
css`
+ app-toolbar mwc-button {
+ --mdc-theme-primary: var(--app-header-text-color);
+ /* We use icon + text to show disabled state */
+ --mdc-button-disabled-ink-color: var(--app-header-text-color);
+ }
+
ha-media-player-browse {
height: calc(100vh - (100px + var(--header-height)));
}
@@ -300,7 +343,8 @@ class PanelMediaBrowser extends LitElement {
right: 0;
}
- ha-svg-icon[slot="icon"] {
+ ha-svg-icon[slot="icon"],
+ ha-circular-progress[slot="icon"] {
vertical-align: middle;
}
`,
diff --git a/src/translations/en.json b/src/translations/en.json
index 5bcc4ce4e8..b4892018a6 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -525,8 +525,10 @@
"no_media_folder": "It looks like you have not yet created a media directory.",
"setup_local_help": "Check the {documentation} on how to setup local media.",
"file_management": {
+ "highlight_button": "Click here to upload your first media",
"upload_failed": "Upload failed: {reason}",
- "add_media": "Add Media"
+ "add_media": "Add Media",
+ "uploading": "Uploading {count} {count, plural,\n one {file}\n other {files}\n}"
},
"class": {
"album": "Album",