Still converting to bootstrap 5. Moved away from Wt's boostrap5 theme to better stick to vanilla bootstrap
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
<label class="form-label" for="${id:media-directory}">
|
<label class="form-label" for="${id:media-directory}">
|
||||||
${tr:Lms.Admin.Database.path}
|
${tr:Lms.Admin.Database.path}
|
||||||
</label>
|
</label>
|
||||||
${media-directory}
|
${media-directory class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${media-directory-info}
|
${media-directory-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<label class="form-label" for="${id:update-period}">
|
<label class="form-label" for="${id:update-period}">
|
||||||
${tr:Lms.Admin.Database.update-period}
|
${tr:Lms.Admin.Database.update-period}
|
||||||
</label>
|
</label>
|
||||||
${update-period}
|
${update-period class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${update-period-info"}
|
${update-period-info"}
|
||||||
</div>
|
</div>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<label class="form-label" for="${id:update-start-time}">
|
<label class="form-label" for="${id:update-start-time}">
|
||||||
${tr:Lms.Admin.Database.update-start-time}
|
${tr:Lms.Admin.Database.update-start-time}
|
||||||
</label>
|
</label>
|
||||||
${update-start-time}
|
${update-start-time class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${update-start-time-info}
|
${update-start-time-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<label class="form-label" for="${id:recommendation-engine-type}">
|
<label class="form-label" for="${id:recommendation-engine-type}">
|
||||||
${tr:Lms.Admin.Database.recommendation-engine-type}
|
${tr:Lms.Admin.Database.recommendation-engine-type}
|
||||||
</label>
|
</label>
|
||||||
${recommendation-engine-type}
|
${recommendation-engine-type class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${recommendation-engine-type-info}
|
${recommendation-engine-type-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -47,13 +47,13 @@
|
|||||||
<label class="form-label" for="${id:tags}">
|
<label class="form-label" for="${id:tags}">
|
||||||
${tr:Lms.Admin.Database.tags}
|
${tr:Lms.Admin.Database.tags}
|
||||||
</label>
|
</label>
|
||||||
${tags}
|
${tags class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${tags-info}
|
${tags-info}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
${apply-btn class="btn-primary me-1"}${discard-btn}
|
${apply-btn class="btn btn-primary me-1"}${discard-btn class="btn btn-secondary"}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<label class="form-label" for="${id:login}">
|
<label class="form-label" for="${id:login}">
|
||||||
${tr:Lms.login}
|
${tr:Lms.login}
|
||||||
</label>
|
</label>
|
||||||
${login}
|
${login class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${login-info}
|
${login-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<label class="form-label" for="${id:password}">
|
<label class="form-label" for="${id:password}">
|
||||||
${tr:Lms.password-new}
|
${tr:Lms.password-new}
|
||||||
</label>
|
</label>
|
||||||
${password}
|
${password class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${password-info}
|
${password-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
</div>
|
</div>
|
||||||
${</if-demo>}
|
${</if-demo>}
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
${save-btn class="btn-primary"}
|
${save-btn class="btn btn-primary"}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</message>
|
</message>
|
||||||
|
|||||||
+22
-3
@@ -5,17 +5,36 @@
|
|||||||
<h2>${tr:Lms.Admin.Users.users}</h2>
|
<h2>${tr:Lms.Admin.Users.users}</h2>
|
||||||
${users}
|
${users}
|
||||||
${<if-can-create-user>}
|
${<if-can-create-user>}
|
||||||
${add-btn class="btn-primary Lms-admin-users-add-btn"}
|
${add-btn class="btn btn-primary"}
|
||||||
${</if-can-create-user>}
|
${</if-can-create-user>}
|
||||||
</message>
|
</message>
|
||||||
|
|
||||||
<message id="Lms.Admin.Users.template.entry">
|
<message id="Lms.Admin.Users.template.entry">
|
||||||
<div class="row align-items-center mb-3">
|
<div class="row align-items-center mb-3">
|
||||||
<div class="col-auto me-auto">
|
<div class="col-auto me-auto">
|
||||||
${name}${<if-tag>} <span class="badge bg-info">${tag}</span>${</if-tag>}
|
${name}${<if-tag>}<span class="badge bg-info ms-2">${tag}</span>${</if-tag>}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
${<if-edit>}${edit-btn class="btn-warning btn-sm"} ${del-btn class="btn-danger btn-sm"}${</if-edit>}
|
${<if-edit>}${edit-btn class="btn btn-sm btn-warning me-1"} ${del-btn class="btn btn-sm btn-danger"}${</if-edit>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</message>
|
||||||
|
|
||||||
|
<message id="Lms.Admin.Users.template.delete-user">
|
||||||
|
<div class="modal fade" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">${tr:Lms.Admin.Users.del-user}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Modal body text goes here.</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
${del-btn class="btn btn-danger me-1"}${cancel-btn class="btn btn-secondary"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</message>
|
</message>
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<message id="Lms.Explore.Artist.template">
|
<message id="Lms.Explore.Artist.template">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
${name}
|
<h3>${name}</h3>
|
||||||
${clusters class="mb-2"}
|
${clusters class="mb-2"}
|
||||||
${play-btn class="btn btn-outline-primary me-2"}${more-btn class="btn btn-outline-primary"}
|
${play-btn class="btn btn-outline-primary me-2"}${more-btn class="btn btn-outline-primary"}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-2
@@ -9,7 +9,7 @@
|
|||||||
<message id="Lms.Explore.template.play-btn"><i class="fa fa-fw fa-play"></i></message>
|
<message id="Lms.Explore.template.play-btn"><i class="fa fa-fw fa-play"></i></message>
|
||||||
|
|
||||||
<message id="Lms.Explore.template.filters">
|
<message id="Lms.Explore.template.filters">
|
||||||
${add-filter class="btn-sm btn-outline-primary me-2"}${clusters class="d-inline-block align-items-center"}
|
${add-filter class="btn btn-sm btn-outline-primary me-2"}${clusters class="d-inline-block align-items-center"}
|
||||||
</message>
|
</message>
|
||||||
|
|
||||||
<message id="Lms.Explore.template.add-filter">
|
<message id="Lms.Explore.template.add-filter">
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
${add-btn class="btn-primary me-1"}${cancel-btn}
|
${add-btn class="btn btn-primary me-1"}${cancel-btn class="btn btn-secondary"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+3
-3
@@ -11,7 +11,7 @@
|
|||||||
<label class="form-label" for="${id:login-name}">
|
<label class="form-label" for="${id:login-name}">
|
||||||
${tr:Lms.login}
|
${tr:Lms.login}
|
||||||
</label>
|
</label>
|
||||||
${login-name}
|
${login-name class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${login-name-info}
|
${login-name-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
<label class="form-label" for="${id:password}">
|
<label class="form-label" for="${id:password}">
|
||||||
${tr:Lms.password}
|
${tr:Lms.password}
|
||||||
</label>
|
</label>
|
||||||
${password}
|
${password class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${password-info}
|
${password-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
${login-btn class="btn-primary"}
|
${login-btn class="btn btn-primary"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+2
-1
@@ -5,7 +5,8 @@
|
|||||||
${navbar}
|
${navbar}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
${contents}
|
${contents}
|
||||||
${notifications class="toast-container position-fixed top-0 end-0 p-3"}
|
${notifications class="toast-container Lms-notification-container p-3"}
|
||||||
|
${modal}
|
||||||
</div>
|
</div>
|
||||||
${player class="fixed-bottom bg-dark Lms-player"}
|
${player class="fixed-bottom bg-dark Lms-player"}
|
||||||
</message>
|
</message>
|
||||||
|
|||||||
@@ -117,7 +117,6 @@
|
|||||||
<message id="Lms.Explore.download">Download</message>
|
<message id="Lms.Explore.download">Download</message>
|
||||||
<message id="Lms.Explore.filter-added">Filter added</message>
|
<message id="Lms.Explore.filter-added">Filter added</message>
|
||||||
<message id="Lms.Explore.filters">Filters</message>
|
<message id="Lms.Explore.filters">Filters</message>
|
||||||
<message id="Lms.Explore.links">Links</message>
|
|
||||||
<message id="Lms.Explore.most-played">Most played</message>
|
<message id="Lms.Explore.most-played">Most played</message>
|
||||||
<message id="Lms.Explore.musicbrainz-artist">MusicBrainz Artist</message>
|
<message id="Lms.Explore.musicbrainz-artist">MusicBrainz Artist</message>
|
||||||
<message id="Lms.Explore.musicbrainz-release">MusicBrainz Release</message>
|
<message id="Lms.Explore.musicbrainz-release">MusicBrainz Release</message>
|
||||||
|
|||||||
@@ -117,7 +117,6 @@
|
|||||||
<message id="Lms.Explore.download">Télécharger</message>
|
<message id="Lms.Explore.download">Télécharger</message>
|
||||||
<message id="Lms.Explore.filter-added">Filtre ajouté</message>
|
<message id="Lms.Explore.filter-added">Filtre ajouté</message>
|
||||||
<message id="Lms.Explore.filters">Filtres</message>
|
<message id="Lms.Explore.filters">Filtres</message>
|
||||||
<message id="Lms.Explore.links">Liens</message>
|
|
||||||
<message id="Lms.Explore.most-played">Plus joués</message>
|
<message id="Lms.Explore.most-played">Plus joués</message>
|
||||||
<message id="Lms.Explore.musicbrainz-artist">MusicBrainz Artist</message>
|
<message id="Lms.Explore.musicbrainz-artist">MusicBrainz Artist</message>
|
||||||
<message id="Lms.Explore.musicbrainz-release">MusicBrainz Release</message>
|
<message id="Lms.Explore.musicbrainz-release">MusicBrainz Release</message>
|
||||||
|
|||||||
@@ -116,7 +116,6 @@
|
|||||||
<message id="Lms.Explore.download">Download</message>
|
<message id="Lms.Explore.download">Download</message>
|
||||||
<message id="Lms.Explore.filter-added">Filtro aggiunto</message>
|
<message id="Lms.Explore.filter-added">Filtro aggiunto</message>
|
||||||
<message id="Lms.Explore.filters">Filtri</message>
|
<message id="Lms.Explore.filters">Filtri</message>
|
||||||
<message id="Lms.Explore.links">Collegamenti</message>
|
|
||||||
<message id="Lms.Explore.most-played">Più ascoltati</message>
|
<message id="Lms.Explore.most-played">Più ascoltati</message>
|
||||||
<message id="Lms.Explore.musicbrainz-artist">Artista MusicBrainz</message>
|
<message id="Lms.Explore.musicbrainz-artist">Artista MusicBrainz</message>
|
||||||
<message id="Lms.Explore.musicbrainz-release">Album MusicBrainz</message>
|
<message id="Lms.Explore.musicbrainz-release">Album MusicBrainz</message>
|
||||||
|
|||||||
@@ -117,7 +117,6 @@
|
|||||||
<message id="Lms.Explore.download">下载</message>
|
<message id="Lms.Explore.download">下载</message>
|
||||||
<message id="Lms.Explore.filter-added">筛选已添加</message>
|
<message id="Lms.Explore.filter-added">筛选已添加</message>
|
||||||
<message id="Lms.Explore.filters">筛选</message>
|
<message id="Lms.Explore.filters">筛选</message>
|
||||||
<message id="Lms.Explore.links">链接</message>
|
|
||||||
<message id="Lms.Explore.most-played">播放最多</message>
|
<message id="Lms.Explore.most-played">播放最多</message>
|
||||||
<message id="Lms.Explore.musicbrainz-artist">MusicBrainz 歌手</message>
|
<message id="Lms.Explore.musicbrainz-artist">MusicBrainz 歌手</message>
|
||||||
<message id="Lms.Explore.musicbrainz-release">MusicBrainz 专辑</message>
|
<message id="Lms.Explore.musicbrainz-release">MusicBrainz 专辑</message>
|
||||||
|
|||||||
+11
-8
@@ -16,11 +16,20 @@
|
|||||||
${<if-has-release-artists>}${artists}${</if-has-release-artists>}
|
${<if-has-release-artists>}${artists}${</if-has-release-artists>}
|
||||||
${<if-has-various-release-artists>}${tr:Lms.Explore.various-artists}${</if-has-various-release-artists>}
|
${<if-has-various-release-artists>}${tr:Lms.Explore.various-artists}${</if-has-various-release-artists>}
|
||||||
<div class="small text-muted">${<if-has-year>}${year}${<if-has-orig-year>} (${orig-year})${</if-has-orig-year>} · ${</if-has-year>}${duration}</div>
|
<div class="small text-muted">${<if-has-year>}${year}${<if-has-orig-year>} (${orig-year})${</if-has-orig-year>} · ${</if-has-year>}${duration}</div>
|
||||||
${clusters}
|
${clusters class="mb-2"}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
${play-btn class="btn btn-outline-primary me-2"}${more-btn class="btn btn-outline-primary"}
|
${play-btn class="btn btn-outline-primary me-2"}
|
||||||
|
<span class="dropdown">
|
||||||
|
<button class="btn btn-outline-primary" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">...</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
|
||||||
|
<li>${play-shuffled class="btn dropdown-item"}</li>
|
||||||
|
${<if-has-mbid>}
|
||||||
|
<li><a href="${mbid-link}" target="_blank" class="dropdown-item">${tr:Lms.Explore.musicbrainz-release}</a></li>
|
||||||
|
${</if-has-mbid>}
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
${container class="d-grid gap-3"}
|
${container class="d-grid gap-3"}
|
||||||
</div>
|
</div>
|
||||||
@@ -38,12 +47,6 @@
|
|||||||
${copyright class="text-muted"}
|
${copyright class="text-muted"}
|
||||||
</div>
|
</div>
|
||||||
${</if-has-copyright>}
|
${</if-has-copyright>}
|
||||||
${<if-has-mbid>}
|
|
||||||
<div class="col-12 col-md-4">
|
|
||||||
<h3>${tr:Lms.Explore.links}</h3>
|
|
||||||
${mbid-link class="text-muted"}
|
|
||||||
</div>
|
|
||||||
${</if-has-mbid>}
|
|
||||||
</div>
|
</div>
|
||||||
</message>
|
</message>
|
||||||
|
|
||||||
|
|||||||
+20
-1
@@ -4,7 +4,26 @@
|
|||||||
|
|
||||||
<message id="Lms.Explore.Releases.template">
|
<message id="Lms.Explore.Releases.template">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
${mode class="nav nav-pills mb-2"}
|
<ul class="nav nav-pills mb-2">
|
||||||
|
<li class="nav-item">
|
||||||
|
${random class="nav-link"}
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
${starred class="nav-link"}
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
${recently-played class="nav-link"}
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
${most-played class="nav-link"}
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
${recently-added class="nav-link"}
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
${all class="nav-link"}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
${play-btn class="btn btn-outline-primary me-2"}${more-btn class="btn btn-outline-primary"}
|
${play-btn class="btn btn-outline-primary me-2"}${more-btn class="btn btn-outline-primary"}
|
||||||
</div>
|
</div>
|
||||||
${releases}
|
${releases}
|
||||||
|
|||||||
+16
-16
@@ -13,7 +13,7 @@
|
|||||||
<label class="form-label" for="${id:transcode-mode}">
|
<label class="form-label" for="${id:transcode-mode}">
|
||||||
${tr:Lms.Settings.transcode-mode}
|
${tr:Lms.Settings.transcode-mode}
|
||||||
</label>
|
</label>
|
||||||
${transcode-mode}
|
${transcode-mode class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${transcode-mode-info}
|
${transcode-mode-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<label class="form-label" for="${id:transcode-format}">
|
<label class="form-label" for="${id:transcode-format}">
|
||||||
${tr:Lms.Settings.transcode-format}
|
${tr:Lms.Settings.transcode-format}
|
||||||
</label>
|
</label>
|
||||||
${transcode-format}
|
${transcode-format class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${transcode-format-info}
|
${transcode-format-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
${tr:Lms.Settings.transcode-bitrate}
|
${tr:Lms.Settings.transcode-bitrate}
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
${transcode-bitrate}
|
${transcode-bitrate class="form-control"}
|
||||||
<span class="input-group-text">kbps</span>
|
<span class="input-group-text">kbps</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
<label class="form-label" for="${id:replaygain-mode}">
|
<label class="form-label" for="${id:replaygain-mode}">
|
||||||
${tr:Lms.Settings.replaygain-mode}
|
${tr:Lms.Settings.replaygain-mode}
|
||||||
</label>
|
</label>
|
||||||
${replaygain-mode}
|
${replaygain-mode class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${replaygain-mode-info}
|
${replaygain-mode-info}
|
||||||
</div>
|
</div>
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
${tr:Lms.Settings.replaygain-preamp}
|
${tr:Lms.Settings.replaygain-preamp}
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
${replaygain-preamp}
|
${replaygain-preamp class="form-control"}
|
||||||
<span class="input-group-text">dB</span>
|
<span class="input-group-text">dB</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
${tr:Lms.Settings.replaygain-preamp-no-rg-info}
|
${tr:Lms.Settings.replaygain-preamp-no-rg-info}
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
${replaygain-preamp-no-rg-info}
|
${replaygain-preamp-no-rg-info class="form-control"}
|
||||||
<span class="input-group-text">dB</span>
|
<span class="input-group-text">dB</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
${subsonic-transcode-enable class="form-check-input"}
|
${subsonic-transcode-enable class="form-check-input"}
|
||||||
<label class="form-check-label" for="${id:subsonic-transcode-enable}">
|
<label class="form-check-label" for="${id:subsonic-transcode-enable}">
|
||||||
${tr:Lms.Settings.transcode-enable}
|
${tr:Lms.Settings.transcode-enable class="form-control"}
|
||||||
</label>
|
</label>
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${subsonic-transcode-enable-info}
|
${subsonic-transcode-enable-info}
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
<label class="form-label" for="${id:subsonic-transcode-format}">
|
<label class="form-label" for="${id:subsonic-transcode-format}">
|
||||||
${tr:Lms.Settings.transcode-format}
|
${tr:Lms.Settings.transcode-format}
|
||||||
</label>
|
</label>
|
||||||
${subsonic-transcode-format}
|
${subsonic-transcode-format class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${subsonic-transcode-format-info class="help-block"}
|
${subsonic-transcode-format-info class="help-block"}
|
||||||
</div>
|
</div>
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
${tr:Lms.Settings.transcode-bitrate}
|
${tr:Lms.Settings.transcode-bitrate}
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
${subsonic-transcode-bitrate}
|
${subsonic-transcode-bitrate class="form-control"}
|
||||||
<span class="input-group-text">kbps</span>
|
<span class="input-group-text">kbps</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
<label class="form-label" for="${id:subsonic-artist-list-mode}">
|
<label class="form-label" for="${id:subsonic-artist-list-mode}">
|
||||||
${tr:Lms.Settings.subsonic-artist-list-mode}
|
${tr:Lms.Settings.subsonic-artist-list-mode}
|
||||||
</label>
|
</label>
|
||||||
${subsonic-artist-list-mode}
|
${subsonic-artist-list-mode class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${subsonic-artist-list-mode-info class="help-block"}
|
${subsonic-artist-list-mode-info class="help-block"}
|
||||||
</div>
|
</div>
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
<label class="form-label" for="${id:scrobbler}">
|
<label class="form-label" for="${id:scrobbler}">
|
||||||
${tr:Lms.Settings.scrobbling.scrobbler}
|
${tr:Lms.Settings.scrobbling.scrobbler}
|
||||||
</label>
|
</label>
|
||||||
${scrobbler}
|
${scrobbler class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${scrobbler-info class="help-block"}
|
${scrobbler-info class="help-block"}
|
||||||
</div>
|
</div>
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
<label class="form-label" for="${id:listenbrainz-token}">
|
<label class="form-label" for="${id:listenbrainz-token}">
|
||||||
${tr:Lms.Settings.scrobbling.listenbrainz-token}
|
${tr:Lms.Settings.scrobbling.listenbrainz-token}
|
||||||
</label>
|
</label>
|
||||||
${listenbrainz-token}
|
${listenbrainz-token class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${listenbrainz-token-info class="help-block"}
|
${listenbrainz-token-info class="help-block"}
|
||||||
</div>
|
</div>
|
||||||
@@ -142,7 +142,7 @@
|
|||||||
<label class="form-label" for="${id:password-old}">
|
<label class="form-label" for="${id:password-old}">
|
||||||
${tr:Lms.password-old}
|
${tr:Lms.password-old}
|
||||||
</label>
|
</label>
|
||||||
${password-old}
|
${password-old class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${password-old-info class="help-block"}
|
${password-old-info class="help-block"}
|
||||||
</div>
|
</div>
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
<label class="col-lg-3 control-label" for="${id:password}">
|
<label class="col-lg-3 control-label" for="${id:password}">
|
||||||
${tr:Lms.password-new}
|
${tr:Lms.password-new}
|
||||||
</label>
|
</label>
|
||||||
${password}
|
${password class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${password-info class="help-block"}
|
${password-info class="help-block"}
|
||||||
</div>
|
</div>
|
||||||
@@ -161,14 +161,14 @@
|
|||||||
<label class="col-lg-3 control-label" for="${id:password-confirm}">
|
<label class="col-lg-3 control-label" for="${id:password-confirm}">
|
||||||
${tr:Lms.password-confirm}
|
${tr:Lms.password-confirm}
|
||||||
</label>
|
</label>
|
||||||
${password-confirm}
|
${password-confirm class="form-control"}
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
${password-confirm-info class="help-block"}
|
${password-confirm-info class="help-block"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${</if-has-change-password>}
|
${</if-has-change-password>}
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
${apply-btn class="btn-primary me-1"}${discard-btn}
|
${apply-btn class="btn btn-primary me-1"}${discard-btn class="btn btn-secondary"}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</message>
|
</message>
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ body {
|
|||||||
padding-bottom: 78px;
|
padding-bottom: 78px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Lms-notification-container {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 78px;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.Lms-player {
|
.Lms-player {
|
||||||
height: 70px;
|
height: 70px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
add_executable(lms
|
add_executable(lms
|
||||||
main.cpp
|
main.cpp
|
||||||
ui/Auth.cpp
|
ui/Auth.cpp
|
||||||
|
ui/Bootstrap5Theme.cpp
|
||||||
ui/LmsApplication.cpp
|
ui/LmsApplication.cpp
|
||||||
ui/LmsApplicationManager.cpp
|
ui/LmsApplicationManager.cpp
|
||||||
ui/LmsTheme.cpp
|
ui/LmsTheme.cpp
|
||||||
ui/MediaPlayer.cpp
|
ui/MediaPlayer.cpp
|
||||||
|
ui/ModalManager.cpp
|
||||||
ui/NotificationContainer.cpp
|
ui/NotificationContainer.cpp
|
||||||
ui/PlayQueue.cpp
|
ui/PlayQueue.cpp
|
||||||
ui/SettingsView.cpp
|
ui/SettingsView.cpp
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Emweb bv, Herent, Belgium.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for terms of use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Bootstrap5Theme.h"
|
||||||
|
|
||||||
|
#include <Wt/WApplication.h>
|
||||||
|
#include <Wt/WLinkedCssStyleSheet.h>
|
||||||
|
#include <Wt/WText.h>
|
||||||
|
|
||||||
|
namespace UserInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
void
|
||||||
|
Bootstrap5Theme::init(Wt::WApplication* app) const
|
||||||
|
{
|
||||||
|
app->require(resourcesUrl() + "js/bootstrap.bundle.min.js");
|
||||||
|
Wt::WString v = app->metaHeader(Wt::MetaHeaderType::Meta, "viewport");
|
||||||
|
if (v.empty())
|
||||||
|
app->addMetaHeader("viewport", "width=device-width, initial-scale=1");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Bootstrap5Theme::name() const
|
||||||
|
{
|
||||||
|
return "bootstrap5";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Bootstrap5Theme::resourcesUrl() const
|
||||||
|
{
|
||||||
|
return Wt::WApplication::relativeResourcesUrl() + "themes/bootstrap/5/";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Wt::WLinkedCssStyleSheet>
|
||||||
|
Bootstrap5Theme::styleSheets() const
|
||||||
|
{
|
||||||
|
std::vector<Wt::WLinkedCssStyleSheet> result;
|
||||||
|
|
||||||
|
const std::string themeDir {resourcesUrl()};
|
||||||
|
|
||||||
|
result.emplace_back(Wt::WLink {themeDir + "css/bootstrap.min.css"});
|
||||||
|
result.emplace_back(Wt::WLink {themeDir + "wt.css"});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Bootstrap5Theme::utilityCssClass(int utilityCssClassRole) const
|
||||||
|
{
|
||||||
|
switch (utilityCssClassRole) {
|
||||||
|
case Wt::ToolTipInner:
|
||||||
|
return "tooltip-inner";
|
||||||
|
case Wt::ToolTipOuter:
|
||||||
|
return "tooltip fade top in";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bootstrap5Theme::applyValidationStyle(Wt::WWidget* widget, const Wt::WValidator::Result& validation, Wt::WFlags<Wt::ValidationStyleFlag> styles) const
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const bool validStyle {(validation.state() == Wt::ValidationState::Valid) && styles.test(Wt::ValidationStyleFlag::ValidStyle)};
|
||||||
|
widget->toggleStyleClass("is-valid", validStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const bool invalidStyle {(validation.state() != Wt::ValidationState::Valid) && styles.test(Wt::ValidationStyleFlag::InvalidStyle)};
|
||||||
|
widget->toggleStyleClass("is-invalid", invalidStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace UserInterface
|
||||||
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Wt/WTheme.h>
|
||||||
|
|
||||||
|
namespace UserInterface
|
||||||
|
{
|
||||||
|
class Bootstrap5Theme : public Wt::WTheme
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void init(Wt::WApplication *app) const override;
|
||||||
|
|
||||||
|
std::string name() const override;
|
||||||
|
std::string resourcesUrl() const override;
|
||||||
|
std::vector<Wt::WLinkedCssStyleSheet> styleSheets() const override;
|
||||||
|
void apply(Wt::WWidget*, Wt::WWidget*, int) const override {};
|
||||||
|
void apply(Wt::WWidget*, Wt::DomElement&, int) const override {};
|
||||||
|
std::string disabledClass() const override { return "disabled"; }
|
||||||
|
std::string activeClass() const override { return "active"; };
|
||||||
|
std::string utilityCssClass(int utilityCssClassRole) const override;
|
||||||
|
bool canStyleAnchorAsButton() const override { return true; };
|
||||||
|
void applyValidationStyle(Wt::WWidget* widget,
|
||||||
|
const Wt::WValidator::Result& validation,
|
||||||
|
Wt::WFlags<Wt::ValidationStyleFlag> flags) const override;
|
||||||
|
bool canBorderBoxElement(const Wt::DomElement&) const override { return true; }
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
#include "LmsApplicationManager.hpp"
|
#include "LmsApplicationManager.hpp"
|
||||||
#include "LmsTheme.hpp"
|
#include "LmsTheme.hpp"
|
||||||
#include "MediaPlayer.hpp"
|
#include "MediaPlayer.hpp"
|
||||||
|
#include "ModalManager.hpp"
|
||||||
#include "NotificationContainer.hpp"
|
#include "NotificationContainer.hpp"
|
||||||
#include "PlayQueue.hpp"
|
#include "PlayQueue.hpp"
|
||||||
#include "SettingsView.hpp"
|
#include "SettingsView.hpp"
|
||||||
@@ -462,6 +463,7 @@ LmsApplication::createHome()
|
|||||||
Wt::WTemplate* navbar {main->bindNew<Wt::WTemplate>("navbar", Wt::WString::tr("Lms.main.template.navbar"))};
|
Wt::WTemplate* navbar {main->bindNew<Wt::WTemplate>("navbar", Wt::WString::tr("Lms.main.template.navbar"))};
|
||||||
|
|
||||||
_notificationContainer = main->bindNew<NotificationContainer>("notifications");
|
_notificationContainer = main->bindNew<NotificationContainer>("notifications");
|
||||||
|
_modalManager = main->bindNew<ModalManager>("modal");
|
||||||
|
|
||||||
// MediaPlayer
|
// MediaPlayer
|
||||||
_mediaPlayer = main->bindNew<MediaPlayer>("player");
|
_mediaPlayer = main->bindNew<MediaPlayer>("player");
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ class MediaPlayer;
|
|||||||
class PlayQueue;
|
class PlayQueue;
|
||||||
class LmsApplicationManager;
|
class LmsApplicationManager;
|
||||||
class NotificationContainer;
|
class NotificationContainer;
|
||||||
|
class ModalManager;
|
||||||
|
|
||||||
class LmsApplication : public Wt::WApplication
|
class LmsApplication : public Wt::WApplication
|
||||||
{
|
{
|
||||||
@@ -91,6 +92,7 @@ class LmsApplication : public Wt::WApplication
|
|||||||
|
|
||||||
MediaPlayer& getMediaPlayer() const { return *_mediaPlayer; }
|
MediaPlayer& getMediaPlayer() const { return *_mediaPlayer; }
|
||||||
PlayQueue& getPlayQueue() const { return *_playQueue; }
|
PlayQueue& getPlayQueue() const { return *_playQueue; }
|
||||||
|
ModalManager& getModalManager() const { return *_modalManager; }
|
||||||
|
|
||||||
// Signal emitted just before the session ends (user may already be logged out)
|
// Signal emitted just before the session ends (user may already be logged out)
|
||||||
Wt::Signal<>& preQuit() { return _preQuit; }
|
Wt::Signal<>& preQuit() { return _preQuit; }
|
||||||
@@ -125,6 +127,7 @@ class LmsApplication : public Wt::WApplication
|
|||||||
PlayQueue* _playQueue {};
|
PlayQueue* _playQueue {};
|
||||||
std::unique_ptr<Wt::WPopupMenu> _popupMenu;
|
std::unique_ptr<Wt::WPopupMenu> _popupMenu;
|
||||||
NotificationContainer* _notificationContainer {};
|
NotificationContainer* _notificationContainer {};
|
||||||
|
ModalManager* _modalManager {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ namespace UserInterface
|
|||||||
static const std::vector<Wt::WLinkedCssStyleSheet> files
|
static const std::vector<Wt::WLinkedCssStyleSheet> files
|
||||||
{
|
{
|
||||||
{"css/bootstrap.solar.min.css"},
|
{"css/bootstrap.solar.min.css"},
|
||||||
{"resources/themes/bootstrap/5/wt.min.css"},
|
|
||||||
{"css/lms.css"},
|
{"css/lms.css"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,13 +20,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <Wt/WBootstrap5Theme.h>
|
|
||||||
#include <Wt/WLinkedCssStyleSheet.h>
|
#include <Wt/WLinkedCssStyleSheet.h>
|
||||||
|
|
||||||
|
#include "Bootstrap5Theme.h"
|
||||||
|
|
||||||
namespace UserInterface
|
namespace UserInterface
|
||||||
{
|
{
|
||||||
class LmsTheme : public Wt::WBootstrap5Theme
|
class LmsTheme : public Bootstrap5Theme
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::vector<Wt::WLinkedCssStyleSheet> styleSheets() const override;
|
std::vector<Wt::WLinkedCssStyleSheet> styleSheets() const override;
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ModalManager.hpp"
|
||||||
|
#include "utils/Logger.hpp"
|
||||||
|
|
||||||
|
namespace UserInterface
|
||||||
|
{
|
||||||
|
ModalManager::ModalManager()
|
||||||
|
: _closed {this, "closed"}
|
||||||
|
{
|
||||||
|
_closed.connect([=](const std::string& id)
|
||||||
|
{
|
||||||
|
LMS_LOG(UI, DEBUG) << "Received closed for id '" << id << "'";
|
||||||
|
for (int i {}; i < count(); ++i)
|
||||||
|
{
|
||||||
|
Wt::WWidget* widget {this->widget(i)};
|
||||||
|
LMS_LOG(UI, DEBUG) << "Widget " << i << ", id = '" << widget->id();
|
||||||
|
if (widget->id() == id)
|
||||||
|
{
|
||||||
|
removeWidget(widget);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModalManager::show(std::unique_ptr<Wt::WWidget> modalWidget)
|
||||||
|
{
|
||||||
|
assert(count() == 0);
|
||||||
|
|
||||||
|
LMS_LOG(UI, DEBUG) << "Want to show, id = " << modalWidget->id();
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss
|
||||||
|
<< R"({const modalElement = )" << jsRef() << R"(.getElementsByClassName('modal')[0];)"
|
||||||
|
<< R"(const modal = bootstrap.Modal.getOrCreateInstance(modalElement);)"
|
||||||
|
<< R"(modal.show();)"
|
||||||
|
<< R"(modalElement.addEventListener('hidden.bs.modal', function () {)"
|
||||||
|
<< _closed.createCall({"'" + modalWidget->id() + "'"})
|
||||||
|
<< R"(modal.dispose();)"
|
||||||
|
<< R"(});})";
|
||||||
|
|
||||||
|
LMS_LOG(UI, DEBUG) << "Running JS '" << oss.str() << "'";
|
||||||
|
|
||||||
|
doJavaScript(oss.str());
|
||||||
|
|
||||||
|
addWidget(move(modalWidget));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModalManager::dispose(Wt::WWidget* modalWidget)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss
|
||||||
|
<< R"({const modalElementParent = document.getElementById(')" << modalWidget->id() << R"(');)"
|
||||||
|
<< R"(const modalElement = modalElementParent.getElementsByClassName('modal')[0];)"
|
||||||
|
<< R"(const modal = bootstrap.Modal.getInstance(modalElement);)"
|
||||||
|
<< R"(modal.hide();)"
|
||||||
|
<< R"(})";
|
||||||
|
|
||||||
|
LMS_LOG(UI, DEBUG) << "Running JS '" << oss.str() << "'";
|
||||||
|
|
||||||
|
doJavaScript(oss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Wt/WContainerWidget.h>
|
||||||
|
#include <Wt/WSignal.h>
|
||||||
|
#include <Wt/WWidget.h>
|
||||||
|
|
||||||
|
namespace UserInterface
|
||||||
|
{
|
||||||
|
class ModalManager : public Wt::WContainerWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModalManager();
|
||||||
|
|
||||||
|
// should handle only one modal at a time
|
||||||
|
// Widget must contain a "modal" element
|
||||||
|
void show(std::unique_ptr<Wt::WWidget> modalWidget);
|
||||||
|
void dispose(Wt::WWidget* modalWidget);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Wt::JSignal<std::string> _closed;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,3 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "NotificationContainer.hpp"
|
#include "NotificationContainer.hpp"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|||||||
@@ -1,3 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "utils/Service.hpp"
|
#include "utils/Service.hpp"
|
||||||
|
|
||||||
#include "LmsApplication.hpp"
|
#include "LmsApplication.hpp"
|
||||||
|
#include "ModalManager.hpp"
|
||||||
|
|
||||||
namespace UserInterface {
|
namespace UserInterface {
|
||||||
|
|
||||||
@@ -101,14 +102,12 @@ UsersView::refreshView()
|
|||||||
Wt::WPushButton* delBtn = entry->bindNew<Wt::WPushButton>("del-btn", Wt::WString::tr("Lms.Admin.Users.del"));
|
Wt::WPushButton* delBtn = entry->bindNew<Wt::WPushButton>("del-btn", Wt::WString::tr("Lms.Admin.Users.del"));
|
||||||
delBtn->clicked().connect([=]
|
delBtn->clicked().connect([=]
|
||||||
{
|
{
|
||||||
auto msgBox = delBtn->addChild(std::make_unique<Wt::WMessageBox>(Wt::WString::tr("Lms.Admin.Users.del-user"),
|
auto modal {std::make_unique<Wt::WTemplate>(Wt::WString::tr("Lms.Admin.Users.template.delete-user"))};
|
||||||
Wt::WString::tr("Lms.Admin.Users.del-user-name"),
|
modal->addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||||
Wt::Icon::Warning, Wt::StandardButton::Yes | Wt::StandardButton::No));
|
Wt::WWidget* modalPtr {modal.get()};
|
||||||
|
|
||||||
msgBox->setModal(true);
|
auto* delBtn {modal->bindNew<Wt::WPushButton>("del-btn", Wt::WString::tr("Lms.Admin.Users.del"))};
|
||||||
msgBox->buttonClicked().connect([=] (Wt::StandardButton btn)
|
delBtn->clicked().connect([=]
|
||||||
{
|
|
||||||
if (btn == Wt::StandardButton::Yes)
|
|
||||||
{
|
{
|
||||||
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
|
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
|
||||||
|
|
||||||
@@ -117,14 +116,17 @@ UsersView::refreshView()
|
|||||||
user.remove();
|
user.remove();
|
||||||
|
|
||||||
_container->removeWidget(entry);
|
_container->removeWidget(entry);
|
||||||
}
|
|
||||||
else
|
LmsApp->getModalManager().dispose(modalPtr);
|
||||||
{
|
|
||||||
delBtn->removeChild(msgBox);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
msgBox->show();
|
auto* cancelBtn {modal->bindNew<Wt::WPushButton>("cancel-btn", Wt::WString::tr("Lms.cancel"))};
|
||||||
|
cancelBtn->clicked().connect([=]
|
||||||
|
{
|
||||||
|
LmsApp->getModalManager().dispose(modalPtr);
|
||||||
|
});
|
||||||
|
|
||||||
|
LmsApp->getModalManager().show(std::move(modal));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,10 +168,11 @@ Release::refreshView()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Wt::WPushButton* moreBtn {bindNew<Wt::WPushButton>("more-btn", Wt::WString::tr("Lms.Explore.template.more-btn"), Wt::TextFormat::XHTML)};
|
Wt::WPushButton* playShuffled {bindNew<Wt::WPushButton>("play-shuffled", Wt::WString::tr("Lms.Explore.play-shuffled"), Wt::TextFormat::Plain)};
|
||||||
moreBtn->clicked().connect([=]
|
playShuffled->setDefault(false);
|
||||||
|
playShuffled->clicked().connect([=]
|
||||||
{
|
{
|
||||||
displayReleasePopupMenu(*moreBtn, *releaseId, releasesAction);
|
releasesAction.emit(PlayQueueAction::PlayShuffled, {*releaseId});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,11 +352,7 @@ Release::refreshLinks(const Database::Release::pointer& release)
|
|||||||
if (mbid)
|
if (mbid)
|
||||||
{
|
{
|
||||||
setCondition("if-has-mbid", true);
|
setCondition("if-has-mbid", true);
|
||||||
|
bindString("mbid-link", std::string {"https://musicbrainz.org/release/"} + std::string {mbid->getAsString()});
|
||||||
Wt::WLink link {"https://musicbrainz.org/release/" + std::string {mbid->getAsString()}};
|
|
||||||
link.setTarget(Wt::LinkTarget::NewWindow);
|
|
||||||
|
|
||||||
bindNew<Wt::WAnchor>("mbid-link", link, Wt::WString::tr("Lms.Explore.musicbrainz-release"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,25 +41,30 @@ Releases::Releases(Filters& filters)
|
|||||||
{
|
{
|
||||||
addFunction("tr", &Wt::WTemplate::Functions::tr);
|
addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||||
|
|
||||||
|
auto bindMenuItem {[this](const std::string& var, const Wt::WString& title, ReleaseCollector::Mode mode)
|
||||||
{
|
{
|
||||||
auto* menu {bindNew<Wt::WMenu>("mode")};
|
auto *menuItem {bindNew<Wt::WPushButton>(var, title)};
|
||||||
|
menuItem->clicked().connect([=]
|
||||||
auto addItem = [this](Wt::WMenu& menu,const Wt::WString& str, ReleaseCollector::Mode mode)
|
|
||||||
{
|
{
|
||||||
auto* item {menu.addItem(str)};
|
refreshView(mode);
|
||||||
item->clicked().connect([this, mode] { refreshView(mode); });
|
_currentActiveItem->removeStyleClass("active");
|
||||||
|
menuItem->addStyleClass("active");
|
||||||
|
_currentActiveItem = menuItem;
|
||||||
|
});
|
||||||
|
|
||||||
if (mode == _defaultMode)
|
if (mode == _defaultMode)
|
||||||
item->renderSelected(true);
|
{
|
||||||
};
|
_currentActiveItem = menuItem;
|
||||||
|
_currentActiveItem->addStyleClass("active");
|
||||||
addItem(*menu, Wt::WString::tr("Lms.Explore.random"), ReleaseCollector::Mode::Random);
|
|
||||||
addItem(*menu, Wt::WString::tr("Lms.Explore.starred"), ReleaseCollector::Mode::Starred);
|
|
||||||
addItem(*menu, Wt::WString::tr("Lms.Explore.recently-played"), ReleaseCollector::Mode::RecentlyPlayed);
|
|
||||||
addItem(*menu, Wt::WString::tr("Lms.Explore.most-played"), ReleaseCollector::Mode::MostPlayed);
|
|
||||||
addItem(*menu, Wt::WString::tr("Lms.Explore.recently-added"), ReleaseCollector::Mode::RecentlyAdded);
|
|
||||||
addItem(*menu, Wt::WString::tr("Lms.Explore.all"), ReleaseCollector::Mode::All);
|
|
||||||
}
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
bindMenuItem("random", Wt::WString::tr("Lms.Explore.random"), ReleaseCollector::Mode::Random);
|
||||||
|
bindMenuItem("starred", Wt::WString::tr("Lms.Explore.starred"), ReleaseCollector::Mode::Starred);
|
||||||
|
bindMenuItem("recently-played", Wt::WString::tr("Lms.Explore.recently-played"), ReleaseCollector::Mode::RecentlyPlayed);
|
||||||
|
bindMenuItem("most-played", Wt::WString::tr("Lms.Explore.most-played"), ReleaseCollector::Mode::MostPlayed);
|
||||||
|
bindMenuItem("recently-added", Wt::WString::tr("Lms.Explore.recently-added"), ReleaseCollector::Mode::RecentlyAdded);
|
||||||
|
bindMenuItem("all", Wt::WString::tr("Lms.Explore.all"), ReleaseCollector::Mode::All);
|
||||||
|
|
||||||
Wt::WPushButton* playBtn {bindNew<Wt::WPushButton>("play-btn", Wt::WString::tr("Lms.Explore.template.play-btn"), Wt::TextFormat::XHTML)};
|
Wt::WPushButton* playBtn {bindNew<Wt::WPushButton>("play-btn", Wt::WString::tr("Lms.Explore.template.play-btn"), Wt::TextFormat::XHTML)};
|
||||||
playBtn->clicked().connect([this]
|
playBtn->clicked().connect([this]
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ namespace UserInterface
|
|||||||
static constexpr std::size_t _batchSize {_maxItemsPerLine};
|
static constexpr std::size_t _batchSize {_maxItemsPerLine};
|
||||||
static constexpr std::size_t _maxCount {_maxItemsPerLine * 32};
|
static constexpr std::size_t _maxCount {_maxItemsPerLine * 32};
|
||||||
|
|
||||||
|
Wt::WWidget* _currentActiveItem {};
|
||||||
InfiniteScrollingContainer* _container {};
|
InfiniteScrollingContainer* _container {};
|
||||||
ReleaseCollector _releaseCollector;
|
ReleaseCollector _releaseCollector;
|
||||||
static constexpr ReleaseCollector::Mode _defaultMode {ReleaseCollector::Mode::Random};
|
static constexpr ReleaseCollector::Mode _defaultMode {ReleaseCollector::Mode::Random};
|
||||||
|
|||||||
Reference in New Issue
Block a user