1module UI.Commands.Alfred exposing (commands, palette)
2
3import Alfred exposing (..)
4import Conditional exposing (ifThenElse)
5import List.Extra as List
6import Material.Icons.Round as Icons
7import Playlists.Matching
8import Tracks exposing (Grouping(..), SortBy(..))
9import UI.Page as Page
10import UI.Queue.Types as Queue
11import UI.Sources.Page as Sources
12import UI.Sources.Types as Sources
13import UI.Tracks.Types as Tracks
14import UI.Types as UI
15
16
17palette : UI.Model -> Alfred UI.Msg
18palette model =
19 Alfred.create
20 { action = action
21 , index = commands model
22 , message = "Run a command."
23 , operation = Query
24 }
25
26
27
28-- ⛰
29
30
31commands : UI.Model -> List (Alfred.Group UI.Msg)
32commands model =
33 [ { name = Just "Currently playing", items = nowPlayingCommands model }
34 , { name = Just "Track selection", items = selectionCommands model }
35 , { name = Just "Collection / Playlist", items = playlistCommands model }
36 , { name = Just "Tracks", items = tracksCommands model }
37 , { name = Just "View", items = viewCommands model }
38 , { name = Just "Playback", items = playbackCommands model }
39 , { name = Just "Sources", items = sourcesCommands model }
40 , { name = Just "Data", items = dataCommands model }
41 , { name = Just "Misc", items = miscCommands model }
42 ]
43
44
45
46--
47
48
49dataCommands model =
50 [ { icon = Just (Icons.offline_bolt 16)
51 , title = "Clear tracks cache"
52 , value = Command (UI.TracksMsg Tracks.ClearCache)
53 }
54 , { icon = Just (Icons.save 16)
55 , title = "Download data snapshot"
56 , value = Command UI.Export
57 }
58 , { icon = Just (Icons.save 16)
59 , title = "Import data snapshot (⚠️ will override current data)"
60 , value = Command UI.RequestImport
61 }
62 ]
63
64
65miscCommands model =
66 [ { icon = Just (Icons.help 16)
67 , title = "Open help"
68 , value = Command (UI.OpenUrlOnNewPage "./about/#UI")
69 }
70 ]
71
72
73nowPlayingCommands : UI.Model -> List (Item UI.Msg)
74nowPlayingCommands model =
75 case model.nowPlaying of
76 Just { item } ->
77 let
78 ( queueItemIdentifiers, _ ) =
79 item.identifiedTrack
80
81 identifiedTrack =
82 model.tracks.harvested
83 |> List.getAt queueItemIdentifiers.indexInList
84 |> Maybe.withDefault item.identifiedTrack
85
86 ( identifiers, track ) =
87 identifiedTrack
88 in
89 [ { icon = Just (Icons.search 16)
90 , title = "Show current track in list"
91 , value = Command (UI.TracksMsg Tracks.ScrollToNowPlaying)
92 }
93
94 --
95 , { icon = Just (Icons.favorite 14)
96 , title = ifThenElse identifiers.isFavourite "Remove favourite" "Mark as favourite"
97 , value = Command (UI.TracksMsg <| Tracks.ToggleFavourite identifiers.indexInList)
98 }
99
100 --
101 , { icon = Just (Icons.queue_music 16)
102 , title = "Add current track to collection"
103 , value = Command (UI.AssistWithAddingTracksToCollection <| [ identifiedTrack ])
104 }
105
106 --
107 , { icon = Just (Icons.queue_music 16)
108 , title = "Add current track to playlist"
109 , value = Command (UI.AssistWithAddingTracksToPlaylist <| [ identifiedTrack ])
110 }
111
112 --
113 , { icon = Just (Icons.offline_bolt 16)
114 , title = "Add current track to cache"
115 , value =
116 [ track ]
117 |> Tracks.StoreInCache
118 |> UI.TracksMsg
119 |> Command
120 }
121 ]
122
123 Nothing ->
124 []
125
126
127playbackCommands model =
128 [ if Maybe.map .isPlaying model.nowPlaying == Just True then
129 { icon = Just (Icons.pause 16)
130 , title = "Pause"
131 , value = Command UI.TogglePlay
132 }
133
134 else
135 { icon = Just (Icons.play_arrow 16)
136 , title = "Play"
137 , value = Command UI.TogglePlay
138 }
139
140 --
141 , { icon = Just (Icons.fast_rewind 18)
142 , title = "Previous track"
143 , value = Command (UI.QueueMsg Queue.Rewind)
144 }
145 , { icon = Just (Icons.fast_forward 18)
146 , title = "Next track"
147 , value = Command (UI.QueueMsg Queue.Shift)
148 }
149 , { icon = Just (Icons.repeat 16)
150 , title = toggle model.repeat "repeat"
151 , value = Command (UI.QueueMsg Queue.ToggleRepeat)
152 }
153 , { icon = Just (Icons.shuffle 16)
154 , title = toggle model.shuffle "shuffle"
155 , value = Command (UI.QueueMsg Queue.ToggleShuffle)
156 }
157 ]
158
159
160playlistCommands model =
161 let
162 selection =
163 case model.selectedPlaylist of
164 Just playlist ->
165 let
166 identifiedTracksFromPlaylist =
167 model.tracks.identified
168 |> Playlists.Matching.match playlist
169 |> Tuple.first
170
171 tracksFromPlaylist =
172 identifiedTracksFromPlaylist
173 |> (if playlist.collection then
174 identity
175
176 else
177 Tracks.sortByIndexInPlaylist
178 )
179 |> List.map Tuple.second
180 in
181 [ { icon = Just (Icons.waves 16)
182 , title = "Deactivate " ++ ifThenElse playlist.collection "collection" "playlist"
183 , value = Command UI.DeselectPlaylist
184 }
185
186 --
187 , { icon = Just (Icons.update 16)
188 , title = "Add to queue"
189 , value =
190 { inFront = False, tracks = identifiedTracksFromPlaylist }
191 |> Queue.AddTracks
192 |> UI.QueueMsg
193 |> Command
194 }
195
196 --
197 , { icon = Just (Icons.offline_bolt 16)
198 , title = "Store in cache"
199 , value =
200 tracksFromPlaylist
201 |> Tracks.StoreInCache
202 |> UI.TracksMsg
203 |> Command
204 }
205
206 --
207 , { icon = Just (Icons.archive 16)
208 , title = "Download as zip file"
209 , value =
210 tracksFromPlaylist
211 |> Tracks.Download
212 { prefixTrackNumber = not playlist.collection
213 , zipName = playlist.name
214 }
215 |> UI.TracksMsg
216 |> Command
217 }
218
219 --
220 , { icon = Just (Icons.waves 16)
221 , title =
222 if playlist.collection then
223 "Convert to playlist"
224
225 else
226 "Convert to collection"
227 , value =
228 if playlist.collection then
229 { name = playlist.name }
230 |> UI.ConvertCollectionToPlaylist
231 |> Command
232
233 else
234 { name = playlist.name }
235 |> UI.ConvertPlaylistToCollection
236 |> Command
237 }
238 ]
239
240 Nothing ->
241 []
242 in
243 [ { icon = Just (Icons.waves 16)
244 , title =
245 case model.selectedPlaylist of
246 Just _ ->
247 "Select other collection or playlist"
248
249 Nothing ->
250 "Select collection or playlist"
251 , value = Command UI.AssistWithSelectingPlaylist
252 }
253 ]
254 ++ selection
255
256
257selectionCommands model =
258 let
259 ( selection, _, amountOfFavs ) =
260 List.foldr
261 (\( i, t ) ( acc, selected, favouriteCounter ) ->
262 case List.findIndex ((==) i.indexInList) selected of
263 Just s ->
264 ( ( i, t ) :: acc
265 , List.removeAt s selected
266 , ifThenElse i.isFavourite (favouriteCounter + 1) favouriteCounter
267 )
268
269 Nothing ->
270 ( acc, selected, favouriteCounter )
271 )
272 ( []
273 , model.selectedTrackIndexes
274 , 0
275 )
276 model.tracks.harvested
277 in
278 case selection of
279 [] ->
280 []
281
282 tracks ->
283 List.concat
284 [ [ { icon = Just (Icons.queue_music 16)
285 , title = "Add current selection to collection"
286 , value = Command (UI.AssistWithAddingTracksToCollection tracks)
287 }
288 , { icon = Just (Icons.queue_music 16)
289 , title = "Add current selection to playlist"
290 , value = Command (UI.AssistWithAddingTracksToPlaylist tracks)
291 }
292 ]
293
294 --
295 , if amountOfFavs > 0 then
296 [ { icon = Just (Icons.favorite 14)
297 , title = "Remove current selection from favourites"
298 , value = Command (UI.TracksMsg <| Tracks.RemoveFavourites tracks)
299 }
300 ]
301
302 else
303 []
304
305 --
306 , if amountOfFavs < List.length selection then
307 [ { icon = Just (Icons.favorite 14)
308 , title = "Add current selection to favourites"
309 , value = Command (UI.TracksMsg <| Tracks.AddFavourites tracks)
310 }
311 ]
312
313 else
314 []
315 ]
316
317
318sourcesCommands model =
319 [ { icon = Just (Icons.sync 16)
320 , title = "Process sources"
321 , value = Command (UI.SourcesMsg Sources.Process)
322 }
323
324 --
325 , { icon = Just (Icons.add 16)
326 , title = "Add new source"
327 , value = Command (UI.ChangeUrlUsingPage <| Page.Sources Sources.New)
328 }
329 ]
330
331
332tracksCommands model =
333 let
334 groupCommands =
335 [ AddedOn, Directory, FirstAlphaCharacter, TrackYear ]
336 |> (case model.grouping of
337 Just group ->
338 List.remove group
339
340 Nothing ->
341 identity
342 )
343 |> List.map
344 (\group ->
345 { icon =
346 Just (Icons.library_music 16)
347 , title =
348 case group of
349 AddedOn ->
350 "Group by processing date"
351
352 Directory ->
353 "Group by directory"
354
355 FirstAlphaCharacter ->
356 "Group by first letter"
357
358 TrackYear ->
359 "Group by track year"
360 , value =
361 Command (UI.TracksMsg <| Tracks.GroupBy group)
362 }
363 )
364 |> (\list ->
365 case model.grouping of
366 Just _ ->
367 { icon = Just (Icons.library_music 16)
368 , title = "Disable grouping"
369 , value = Command (UI.TracksMsg Tracks.DisableGrouping)
370 }
371 :: list
372
373 Nothing ->
374 list
375 )
376 in
377 [ { icon = Just (Icons.favorite 14)
378 , title = toggle model.favouritesOnly "favourites-only mode"
379 , value = Command (UI.TracksMsg Tracks.ToggleFavouritesOnly)
380 }
381
382 --
383 , { icon = Just (Icons.filter_list 16)
384 , title = toggle model.cachedTracksOnly "cached-tracks-only mode"
385 , value = Command (UI.TracksMsg Tracks.ToggleCachedOnly)
386 }
387 ]
388 ++ groupCommands
389 ++ [ { icon = Just (Icons.filter_list 16)
390 , title =
391 if model.hideDuplicates then
392 "Allow duplicates"
393
394 else
395 "Remove duplicates"
396 , value = Command (UI.TracksMsg Tracks.ToggleHideDuplicates)
397 }
398
399 --
400 , { icon = Just (Icons.photo 16)
401 , title =
402 if model.coverSelectionReducesPool then
403 "Track pool is limited to selected cover (Select to disable)"
404
405 else
406 "Track pool is not restricted by selected cover (Select to enable)"
407 , value = Command (UI.TracksMsg Tracks.ToggleCoverSelectionReducesPool)
408 }
409 ]
410
411
412viewCommands model =
413 let
414 sortCommands =
415 (case Maybe.andThen .autoGenerated model.selectedPlaylist of
416 Nothing ->
417 []
418
419 _ ->
420 case model.scene of
421 Tracks.Covers ->
422 [ Album, Artist ]
423
424 Tracks.List ->
425 [ Album, Artist, Title ]
426 )
427 |> List.remove
428 model.sortBy
429 |> List.map
430 (\sortBy ->
431 { icon =
432 Just (Icons.sort 16)
433 , title =
434 case sortBy of
435 Artist ->
436 "Sort tracks by artist"
437
438 Album ->
439 "Sort tracks by album"
440
441 PlaylistIndex ->
442 "Sort tracks by playlist index"
443
444 Title ->
445 "Sort tracks by title"
446 , value =
447 Command (UI.TracksMsg <| Tracks.SortBy sortBy)
448 }
449 )
450 in
451 [ case model.scene of
452 Tracks.Covers ->
453 { icon = Just (Icons.notes 16)
454 , title = "Switch to list view"
455 , value = Command (UI.TracksMsg <| Tracks.ChangeScene Tracks.List)
456 }
457
458 Tracks.List ->
459 { icon = Just (Icons.burst_mode 18)
460 , title = "Switch to cover view"
461 , value = Command (UI.TracksMsg <| Tracks.ChangeScene Tracks.Covers)
462 }
463
464 --
465 , { icon = Just (Icons.sort 16)
466 , title = "Change sort direction"
467 , value = Command (UI.TracksMsg <| Tracks.SortBy model.sortBy)
468 }
469 ]
470 ++ sortCommands
471 ++ [ { icon = Just (Icons.brush 14)
472 , title = "Change application theme"
473 , value = Command UI.AssistWithChangingTheme
474 }
475 ]
476
477
478
479-- ㊙️
480
481
482action { result } =
483 case Maybe.andThen (.value >> Alfred.command) result of
484 Just msg ->
485 [ msg ]
486
487 Nothing ->
488 []
489
490
491toggle bool suffix =
492 ifThenElse bool "Disable" "Enable" ++ " " ++ suffix