Skip to content

Commit 7293722

Browse files
committed
Merge branch 'development' into feature/auto-load-next-page
* development: Translated using Weblate (Czech) Translated using Weblate (Slovenian) Add search playlists with matching videos function (FreeTubeApp#4537) Translated using Weblate (Danish) Translated using Weblate (Danish) Translated using Weblate (Danish) # Conflicts: # src/renderer/views/UserPlaylists/UserPlaylists.js
2 parents 0b17cbd + bef0486 commit 7293722

File tree

19 files changed

+488
-124
lines changed

19 files changed

+488
-124
lines changed

src/renderer/components/ft-element-list/ft-element-list.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ export default defineComponent({
3333
hideForbiddenTitles: {
3434
type: Boolean,
3535
default: true
36-
}
36+
},
37+
searchQueryText: {
38+
type: String,
39+
required: false,
40+
default: '',
41+
},
3742
},
3843
computed: {
3944
listType: function () {

src/renderer/components/ft-element-list/ft-element-list.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
:show-video-with-last-viewed-playlist="showVideoWithLastViewedPlaylist"
1414
:use-channels-hidden-preference="useChannelsHiddenPreference"
1515
:hide-forbidden-titles="hideForbiddenTitles"
16+
:search-query-text="searchQueryText"
1617
/>
1718
</ft-auto-grid>
1819
</template>

src/renderer/components/ft-list-lazy-wrapper/ft-list-lazy-wrapper.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export default defineComponent({
4747
type: Boolean,
4848
default: true
4949
},
50+
searchQueryText: {
51+
type: String,
52+
required: false,
53+
default: '',
54+
},
5055
},
5156
data: function () {
5257
return {

src/renderer/components/ft-list-lazy-wrapper/ft-list-lazy-wrapper.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
v-else-if="finalDataType === 'playlist'"
2929
:appearance="appearance"
3030
:data="data"
31+
:search-query-text="searchQueryText"
3132
/>
3233
<ft-community-post
3334
v-else-if="finalDataType === 'community'"

src/renderer/components/ft-list-playlist/ft-list-playlist.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ export default defineComponent({
1515
appearance: {
1616
type: String,
1717
required: true
18-
}
18+
},
19+
searchQueryText: {
20+
type: String,
21+
required: false,
22+
default: '',
23+
},
1924
},
2025
data: function () {
2126
return {
@@ -79,6 +84,7 @@ export default defineComponent({
7984
path: `/playlist/${this.playlistId}`,
8085
query: {
8186
playlistType: this.isUserPlaylist ? 'user' : '',
87+
searchQueryText: this.searchQueryText,
8288
},
8389
}
8490
},

src/renderer/components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.css

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,36 @@
1616
flex-direction: column;
1717
}
1818

19+
.searchInputsRow {
20+
display: grid;
21+
22+
/* 2 columns */
23+
grid-template-columns: 1fr auto;
24+
column-gap: 16px;
25+
}
26+
@media only screen and (max-width: 800px) {
27+
.searchInputsRow {
28+
/* Switch to 2 rows from 2 columns */
29+
grid-template-columns: auto;
30+
grid-template-rows: auto auto;
31+
}
32+
}
33+
34+
.optionsRow {
35+
display: grid;
36+
grid-template-columns: repeat(2, 1fr);
37+
grid-template-rows: 1fr;
38+
align-items: center;
39+
}
40+
@media only screen and (max-width: 800px) {
41+
.optionsRow {
42+
/* Switch to 2 rows from 2 columns */
43+
grid-template-columns: auto;
44+
grid-template-rows: auto auto;
45+
align-items: stretch;
46+
}
47+
}
48+
1949
.sortSelect {
2050
/* Put it on the right */
2151
margin-inline-start: auto;

src/renderer/components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import FtButton from '../ft-button/ft-button.vue'
77
import FtPlaylistSelector from '../ft-playlist-selector/ft-playlist-selector.vue'
88
import FtInput from '../../components/ft-input/ft-input.vue'
99
import FtSelect from '../../components/ft-select/ft-select.vue'
10+
import FtToggleSwitch from '../../components/ft-toggle-switch/ft-toggle-switch.vue'
1011
import {
1112
showToast,
1213
} from '../../helpers/utils'
@@ -31,12 +32,14 @@ export default defineComponent({
3132
'ft-playlist-selector': FtPlaylistSelector,
3233
'ft-input': FtInput,
3334
'ft-select': FtSelect,
35+
'ft-toggle-switch': FtToggleSwitch,
3436
},
3537
data: function () {
3638
return {
3739
selectedPlaylistIdList: [],
3840
createdSincePromptShownPlaylistIdList: [],
3941
query: '',
42+
doSearchPlaylistsWithMatchingVideos: false,
4043
updateQueryDebounce: function() {},
4144
lastShownAt: Date.now(),
4245
lastActiveElement: null,
@@ -115,6 +118,12 @@ export default defineComponent({
115118
return this.allPlaylists.filter((playlist) => {
116119
if (typeof (playlist.playlistName) !== 'string') { return false }
117120

121+
if (this.doSearchPlaylistsWithMatchingVideos) {
122+
if (playlist.videos.some((v) => v.title.toLowerCase().includes(this.processedQuery))) {
123+
return true
124+
}
125+
}
126+
118127
return playlist.playlistName.toLowerCase().includes(this.processedQuery)
119128
})
120129
},

src/renderer/components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,37 @@
1212
playlistCount: selectedPlaylistCount,
1313
}) }}
1414
</p>
15-
<ft-input
16-
ref="searchBar"
17-
:placeholder="$t('User Playlists.AddVideoPrompt.Search in Playlists')"
18-
:show-clear-text-button="true"
19-
:show-action-button="false"
20-
@input="(input) => updateQueryDebounce(input)"
21-
@clear="updateQueryDebounce('')"
22-
/>
23-
<ft-select
24-
v-if="allPlaylists.length > 1"
25-
class="sortSelect"
26-
:value="sortBy"
27-
:select-names="sortBySelectNames"
28-
:select-values="sortBySelectValues"
29-
:placeholder="$t('User Playlists.Sort By.Sort By')"
30-
@change="sortBy = $event"
31-
/>
15+
<div
16+
class="searchInputsRow"
17+
>
18+
<ft-input
19+
ref="searchBar"
20+
:placeholder="$t('User Playlists.AddVideoPrompt.Search in Playlists')"
21+
:show-clear-text-button="true"
22+
:show-action-button="false"
23+
@input="(input) => updateQueryDebounce(input)"
24+
@clear="updateQueryDebounce('')"
25+
/>
26+
</div>
27+
<div
28+
class="optionsRow"
29+
>
30+
<ft-toggle-switch
31+
:label="$t('User Playlists.Playlists with Matching Videos')"
32+
:compact="true"
33+
:default-value="doSearchPlaylistsWithMatchingVideos"
34+
@change="doSearchPlaylistsWithMatchingVideos = !doSearchPlaylistsWithMatchingVideos"
35+
/>
36+
<ft-select
37+
v-if="allPlaylists.length > 1"
38+
class="sortSelect"
39+
:value="sortBy"
40+
:select-names="sortBySelectNames"
41+
:select-values="sortBySelectValues"
42+
:placeholder="$t('User Playlists.Sort By.Sort By')"
43+
@change="sortBy = $event"
44+
/>
45+
</div>
3246
<div class="playlists-container">
3347
<ft-flex-box>
3448
<div

src/renderer/components/playlist-info/playlist-info.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ export default defineComponent({
8383
type: Boolean,
8484
required: true,
8585
},
86+
searchVideoModeAllowed: {
87+
type: Boolean,
88+
required: true,
89+
},
90+
searchVideoModeEnabled: {
91+
type: Boolean,
92+
required: true,
93+
},
94+
searchQueryText: {
95+
type: String,
96+
required: true,
97+
},
8698
},
8799
data: function () {
88100
return {
@@ -239,6 +251,12 @@ export default defineComponent({
239251
this.newTitle = this.title
240252
this.newDescription = this.description
241253

254+
if (this.videoCount > 0) {
255+
// Only enable search video mode when viewing non empty playlists
256+
this.searchVideoMode = this.searchVideoModeEnabled
257+
this.query = this.searchQueryText
258+
}
259+
242260
this.updateQueryDebounce = debounce(this.updateQuery, 500)
243261
},
244262
methods: {

src/renderer/components/playlist-info/playlist-info.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108

109109
<div class="playlistOptions">
110110
<ft-icon-button
111-
v-if="isUserPlaylist && videoCount > 0 && !editMode"
111+
v-if="searchVideoModeAllowed && videoCount > 0 && !editMode"
112112
ref="enableSearchModeButton"
113113
:title="$t('User Playlists.SinglePlaylistView.Search for Videos')"
114114
:icon="['fas', 'search']"
@@ -198,7 +198,7 @@
198198
</div>
199199

200200
<div
201-
v-if="isUserPlaylist && searchVideoMode"
201+
v-if="searchVideoModeAllowed && searchVideoMode"
202202
class="searchInputsRow"
203203
>
204204
<ft-input
@@ -207,11 +207,11 @@
207207
:placeholder="$t('User Playlists.SinglePlaylistView.Search for Videos')"
208208
:show-clear-text-button="true"
209209
:show-action-button="false"
210+
:value="query"
210211
@input="(input) => updateQueryDebounce(input)"
211212
@clear="updateQueryDebounce('')"
212213
/>
213214
<ft-icon-button
214-
v-if="isUserPlaylist && searchVideoMode"
215215
:title="$t('User Playlists.Cancel')"
216216
:icon="['fas', 'times']"
217217
theme="secondary"

src/renderer/views/Playlist/Playlist.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,17 @@ export default defineComponent({
115115
}
116116
},
117117

118+
searchVideoModeAllowed() {
119+
return this.isUserPlaylistRequested
120+
},
121+
searchQueryTextRequested() {
122+
return this.$route.query.searchQueryText
123+
},
124+
searchQueryTextPresent() {
125+
const searchQueryText = this.searchQueryTextRequested
126+
return typeof searchQueryText === 'string' && searchQueryText !== ''
127+
},
128+
118129
isUserPlaylistRequested: function () {
119130
return this.$route.query.playlistType === 'user'
120131
},
@@ -183,6 +194,11 @@ export default defineComponent({
183194
},
184195
created: function () {
185196
this.getPlaylistInfoDebounce = debounce(this.getPlaylistInfo, 100)
197+
198+
if (this.searchVideoModeAllowed && this.searchQueryTextPresent) {
199+
this.playlistInVideoSearchMode = true
200+
this.videoSearchQuery = this.searchQueryTextRequested
201+
}
186202
},
187203
mounted: function () {
188204
this.getPlaylistInfoDebounce()

src/renderer/views/Playlist/Playlist.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
:view-count="viewCount"
2323
:info-source="infoSource"
2424
:more-video-data-available="moreVideoDataAvailable"
25+
:search-video-mode-allowed="searchVideoModeAllowed"
26+
:search-video-mode-enabled="playlistInVideoSearchMode"
27+
:search-query-text="searchQueryTextRequested"
2528
class="playlistInfo"
2629
:class="{
2730
promptOpen,

src/renderer/views/UserPlaylists/UserPlaylists.css

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,36 @@
1616
vertical-align: middle;
1717
}
1818

19+
.searchInputsRow {
20+
display: grid;
21+
22+
/* 2 columns */
23+
grid-template-columns: 1fr auto;
24+
column-gap: 16px;
25+
}
26+
@media only screen and (max-width: 800px) {
27+
.searchInputsRow {
28+
/* Switch to 2 rows from 2 columns */
29+
grid-template-columns: auto;
30+
grid-template-rows: auto auto;
31+
}
32+
}
33+
34+
.optionsRow {
35+
display: grid;
36+
grid-template-columns: repeat(2, 1fr);
37+
grid-template-rows: 1fr;
38+
align-items: center;
39+
}
40+
@media only screen and (max-width: 800px) {
41+
.optionsRow {
42+
/* Switch to 2 rows from 2 columns */
43+
grid-template-columns: auto;
44+
grid-template-rows: auto auto;
45+
align-items: stretch;
46+
}
47+
}
48+
1949
.sortSelect {
2050
/* Put it on the right */
2151
margin-inline-start: auto;

src/renderer/views/UserPlaylists/UserPlaylists.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import FtSelect from '../../components/ft-select/ft-select.vue'
1010
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
1111
import FtInput from '../../components/ft-input/ft-input.vue'
1212
import FtIconButton from '../../components/ft-icon-button/ft-icon-button.vue'
13+
import FtToggleSwitch from '../../components/ft-toggle-switch/ft-toggle-switch.vue'
1314
import FtAutoLoadNextPageWrapper from '../../components/ft-auto-load-next-page-wrapper/ft-auto-load-next-page-wrapper.vue'
1415

1516
const SORT_BY_VALUES = {
@@ -38,6 +39,7 @@ export default defineComponent({
3839
'ft-element-list': FtElementList,
3940
'ft-icon-button': FtIconButton,
4041
'ft-input': FtInput,
42+
'ft-toggle-switch': FtToggleSwitch,
4143
'ft-auto-load-next-page-wrapper': FtAutoLoadNextPageWrapper,
4244
},
4345
data: function () {
@@ -47,6 +49,7 @@ export default defineComponent({
4749
searchDataLimit: 100,
4850
showLoadMoreButton: false,
4951
query: '',
52+
doSearchPlaylistsWithMatchingVideos: false,
5053
activeData: [],
5154
sortBy: SORT_BY_VALUES.LatestPlayedFirst,
5255
}
@@ -167,6 +170,10 @@ export default defineComponent({
167170
this.searchDataLimit = 100
168171
this.filterPlaylistAsync()
169172
},
173+
doSearchPlaylistsWithMatchingVideos() {
174+
this.searchDataLimit = 100
175+
this.filterPlaylistAsync()
176+
},
170177
fullData() {
171178
this.activeData = this.fullData
172179
this.filterPlaylist()
@@ -211,15 +218,22 @@ export default defineComponent({
211218
if (this.lowerCaseQuery === '') {
212219
this.activeData = this.fullData
213220
this.showLoadMoreButton = this.allPlaylists.length > this.activeData.length
214-
} else {
215-
const filteredPlaylists = this.allPlaylists.filter((playlist) => {
216-
if (typeof (playlist.playlistName) !== 'string') { return false }
217-
218-
return playlist.playlistName.toLowerCase().includes(this.lowerCaseQuery)
219-
})
220-
this.showLoadMoreButton = filteredPlaylists.length > this.searchDataLimit
221-
this.activeData = filteredPlaylists.length < this.searchDataLimit ? filteredPlaylists : filteredPlaylists.slice(0, this.searchDataLimit)
221+
return
222222
}
223+
224+
const filteredPlaylists = this.allPlaylists.filter((playlist) => {
225+
if (typeof (playlist.playlistName) !== 'string') { return false }
226+
227+
if (this.doSearchPlaylistsWithMatchingVideos) {
228+
if (playlist.videos.some((v) => v.title.toLowerCase().includes(this.lowerCaseQuery))) {
229+
return true
230+
}
231+
}
232+
233+
return playlist.playlistName.toLowerCase().includes(this.lowerCaseQuery)
234+
})
235+
this.showLoadMoreButton = filteredPlaylists.length > this.searchDataLimit
236+
this.activeData = filteredPlaylists.length < this.searchDataLimit ? filteredPlaylists : filteredPlaylists.slice(0, this.searchDataLimit)
223237
},
224238

225239
createNewPlaylist: function () {

0 commit comments

Comments
 (0)