A music player that connects to your cloud/distributed storage.
at main 492 lines 16 kB view raw
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