A music player that connects to your cloud/distributed storage.
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add basic queue screen

+266 -39
+1 -1
elm.json
··· 51 51 "direct": {}, 52 52 "indirect": {} 53 53 } 54 - } 54 + }
+6 -2
src/Applications/UI.elm
··· 55 55 import UI.Ports as Ports 56 56 import UI.Queue as Queue 57 57 import UI.Queue.Common 58 + import UI.Queue.ContextMenu as Queue 58 59 import UI.Queue.Core as Queue 59 60 import UI.Reply as Reply exposing (Reply(..)) 60 61 import UI.Settings as Settings ··· 531 532 ----------------------------------------- 532 533 -- Context Menu 533 534 ----------------------------------------- 535 + ShowFutureQueueItemMenu coordinates queueItem -> 536 + return { model | contextMenu = Just (Queue.futureItemMenu queueItem coordinates) } 537 + 534 538 ShowMoreAuthenticationOptions coordinates -> 535 539 return { model | contextMenu = Just (Authentication.moreOptionsMenu coordinates) } 536 540 ··· 935 939 Page.Index -> 936 940 nothing 937 941 938 - Page.Queue _ -> 939 - nothing 942 + Page.Queue subPage -> 943 + Html.map QueueMsg (Queue.view subPage model.queue) 940 944 941 945 Page.Settings subPage -> 942 946 Settings.view subPage model
+4 -4
src/Applications/UI/Equalizer.elm
··· 19 19 import UI.Navigation exposing (..) 20 20 import UI.Page 21 21 import UI.Ports as Ports 22 - import UI.Reply exposing (Reply) 22 + import UI.Reply exposing (Reply(..)) 23 23 24 24 25 25 ··· 151 151 DeactivateKnob _ -> 152 152 Return.replyWithModel 153 153 { model | activeKnob = Nothing } 154 - UI.Reply.SaveEnclosedUserData 154 + SaveEnclosedUserData 155 155 156 156 ----------------------------------------- 157 157 -- Reset ··· 207 207 reset newModel knobType value = 208 208 ( newModel 209 209 , adjustKnob knobType value 210 - , [ UI.Reply.SaveEnclosedUserData ] 210 + , [ SaveEnclosedUserData ] 211 211 ) 212 212 213 213 ··· 224 224 UI.Navigation.local 225 225 [ ( Icon Icons.arrow_back 226 226 , Label "Back to list" Hidden 227 - , GoToPage UI.Page.Index 227 + , NavigateToPage UI.Page.Index 228 228 ) 229 229 ] 230 230
+1 -3
src/Applications/UI/Kit.elm
··· 246 246 canister : List (Html msg) -> Html msg 247 247 canister children = 248 248 chunk 249 - [ T.mh1, T.ph3, T.pb3 ] 249 + [ T.mh1, T.ph3, T.pb4 ] 250 250 children 251 251 252 252 ··· 497 497 [ css vesselStyles ] 498 498 [ borderRadius 499 499 , T.bg_white 500 - , T.flex 501 - , T.flex_column 502 500 , T.flex_grow_1 503 501 , T.overflow_scroll 504 502 , T.relative
+11 -5
src/Applications/UI/List.elm
··· 1 1 module UI.List exposing (Action, Item, view) 2 2 3 3 import Chunky exposing (..) 4 + import Classes as C 4 5 import Color exposing (Color) 5 6 import Color.Ext as Color 6 7 import Css exposing (px, solid) ··· 24 25 25 26 26 27 type alias Item msg = 27 - { label : String 28 + { label : Html msg 28 29 , actions : List (Action msg) 29 30 } 30 31 ··· 49 50 brick 50 51 [ css itemStyles ] 51 52 [ T.flex, T.fw6, T.items_center, T.pv3 ] 52 - [ chunk 53 + [ -- Label 54 + -------- 55 + chunk 53 56 [ T.flex_grow_1 ] 54 - [ Html.text label ] 57 + [ label ] 58 + 59 + -- Actions 60 + ---------- 55 61 , chunk 56 62 [ T.flex, T.items_center ] 57 63 (List.map 58 64 (\action -> 59 65 brick 60 66 [ Attributes.fromUnstyled (onClick action.msg) 61 - , style "line-height" "0" 62 67 , title action.title 63 68 ] 64 - [ T.ml2 69 + [ C.lh_0 70 + , T.ml2 65 71 , T.pointer 66 72 ] 67 73 [ fromUnstyled (action.icon UI.Kit.colors.text 16) ]
+3 -3
src/Applications/UI/Navigation.elm
··· 21 21 22 22 23 23 type Action msg 24 - = GoToPage Page 24 + = NavigateToPage Page 25 25 | PerformMsg msg 26 26 27 27 ··· 134 134 localItem tabindex_ ( Icon icon, Label labelText labelType, action ) = 135 135 slab 136 136 (case action of 137 - GoToPage page -> 137 + NavigateToPage page -> 138 138 Html.a 139 139 140 140 PerformMsg msg -> 141 141 Html.button 142 142 ) 143 143 [ case action of 144 - GoToPage page -> 144 + NavigateToPage page -> 145 145 href (Page.toString page) 146 146 147 147 PerformMsg msg ->
+3
src/Applications/UI/Page.elm
··· 98 98 ( Index, Equalizer ) -> 99 99 True 100 100 101 + ( Index, Queue _ ) -> 102 + True 103 + 101 104 _ -> 102 105 a == b 103 106
+189 -1
src/Applications/UI/Queue.elm
··· 1 - module UI.Queue exposing (initialModel, update) 1 + module UI.Queue exposing (initialModel, update, view) 2 2 3 + import Chunky exposing (..) 3 4 import Conditional exposing (..) 5 + import Html.Styled as Html exposing (Html, fromUnstyled, text) 4 6 import List.Extra as List 7 + import Material.Icons.Action as Icons 8 + import Material.Icons.Image as Icons 9 + import Material.Icons.Navigation as Icons 5 10 import Queue exposing (..) 6 11 import Return3 as Return exposing (..) 12 + import Tachyons.Classes as T 7 13 import Time 8 14 import Tracks exposing (IdentifiedTrack) 15 + import UI.Kit 16 + import UI.List 17 + import UI.Navigation exposing (..) 18 + import UI.Page as Page 9 19 import UI.Ports as Ports 10 20 import UI.Queue.Common exposing (makeItem) 11 21 import UI.Queue.Core exposing (..) 12 22 import UI.Queue.Fill as Fill 23 + import UI.Queue.Page as Queue exposing (Page(..)) 13 24 import UI.Reply exposing (Reply(..)) 14 25 15 26 ··· 37 48 update : Msg -> Model -> Return Model Msg Reply 38 49 update msg model = 39 50 case msg of 51 + ShowFutureItemMenu item mouseEvent -> 52 + let 53 + coordinates = 54 + ( mouseEvent.clientPos 55 + , mouseEvent.offsetPos 56 + ) 57 + |> (\( ( a, b ), ( c, d ) ) -> 58 + { x = a - c + 8 59 + , y = b - d + 8 60 + } 61 + ) 62 + in 63 + item 64 + |> ShowFutureQueueItemMenu coordinates 65 + |> returnReplyWithModel model 66 + 40 67 ------------------------------------ 41 68 -- Combos 42 69 ------------------------------------ ··· 169 196 ------------------------------------ 170 197 -- Contents 171 198 ------------------------------------ 199 + -- # Clear 200 + -- 201 + Clear -> 202 + returnRepliesWithModel 203 + { model | future = [], ignored = [] } 204 + [ FillQueue ] 205 + 172 206 -- # Fill 173 207 -- > Fill the queue with items. 174 208 -- ··· 247 281 True -> 248 282 { m | future = Fill.shuffled timestamp nonMissingTracks m } 249 283 ) 284 + 285 + 286 + 287 + -- 🗺 288 + 289 + 290 + view : Queue.Page -> Model -> Html Msg 291 + view page model = 292 + UI.Kit.receptacle 293 + (case page of 294 + History -> 295 + historyView model 296 + 297 + Index -> 298 + futureView model 299 + ) 300 + 301 + 302 + 303 + -- 🗺 ░░ FUTURE 304 + 305 + 306 + futureView : Model -> List (Html Msg) 307 + futureView model = 308 + [ ----------------------------------------- 309 + -- Navigation 310 + ----------------------------------------- 311 + UI.Navigation.local 312 + [ ( Icon Icons.arrow_back 313 + , Label "Back to list" Hidden 314 + , NavigateToPage Page.Index 315 + ) 316 + , ( Icon Icons.event_seat 317 + , Label "History" Shown 318 + , NavigateToPage (Page.Queue History) 319 + ) 320 + , ( Icon Icons.cancel 321 + , Label "Clear all" Shown 322 + , PerformMsg Clear 323 + ) 324 + , ( Icon Icons.restore 325 + , Label "Clear ignored" Shown 326 + , PerformMsg Reset 327 + ) 328 + ] 329 + 330 + ----------------------------------------- 331 + -- Content 332 + ----------------------------------------- 333 + , UI.Kit.canister 334 + [ UI.Kit.h1 "Up next" 335 + , model.future 336 + |> List.indexedMap futureItem 337 + |> UI.List.view 338 + |> chunky [ T.mt3 ] 339 + ] 340 + ] 341 + 342 + 343 + futureItem : Int -> Queue.Item -> UI.List.Item Msg 344 + futureItem idx item = 345 + let 346 + ( _, track ) = 347 + item.identifiedTrack 348 + in 349 + { label = 350 + inline 351 + [ ifThenElse item.manualEntry T.o_100 T.o_50 ] 352 + [ inline 353 + [ T.dib, T.f7, T.mr2 ] 354 + [ text (String.fromInt <| idx + 1), text "." ] 355 + , text (track.tags.artist ++ " - " ++ track.tags.title) 356 + ] 357 + , actions = 358 + [] 359 + } 360 + 361 + 362 + 363 + -- 🗺 ░░ HISTORY 364 + 365 + 366 + historyView : Model -> List (Html Msg) 367 + historyView model = 368 + [ ----------------------------------------- 369 + -- Navigation 370 + ----------------------------------------- 371 + UI.Navigation.local 372 + [ ( Icon Icons.arrow_back 373 + , Label "Back to list" Hidden 374 + , NavigateToPage Page.Index 375 + ) 376 + , ( Icon Icons.event_seat 377 + , Label "Up next" Shown 378 + , NavigateToPage (Page.Queue Index) 379 + ) 380 + ] 381 + 382 + ----------------------------------------- 383 + -- Content 384 + ----------------------------------------- 385 + , if List.isEmpty model.past then 386 + chunk 387 + [ T.relative ] 388 + [ chunk 389 + [ T.absolute, T.left_0, T.top_0 ] 390 + [ UI.Kit.canister [ UI.Kit.h1 "History" ] ] 391 + ] 392 + 393 + else 394 + UI.Kit.canister 395 + [ UI.Kit.h1 "History" 396 + , model.past 397 + |> List.reverse 398 + |> List.indexedMap historyItem 399 + |> UI.List.view 400 + |> chunky [ T.mt3 ] 401 + ] 402 + 403 + -- 404 + , if List.isEmpty model.past then 405 + UI.Kit.centeredContent 406 + [ chunk 407 + [ T.o_30 ] 408 + [ fromUnstyled (Icons.music_note UI.Kit.colors.text 64) ] 409 + , chunk 410 + [ T.lh_copy, T.mt2, T.o_40, T.tc ] 411 + [ text "Nothing here yet," 412 + , lineBreak 413 + , text "play some music first." 414 + ] 415 + ] 416 + 417 + else 418 + nothing 419 + ] 420 + 421 + 422 + historyItem : Int -> Queue.Item -> UI.List.Item Msg 423 + historyItem idx { identifiedTrack, manualEntry } = 424 + let 425 + ( _, track ) = 426 + identifiedTrack 427 + in 428 + { label = 429 + inline 430 + [ ifThenElse manualEntry T.o_100 T.o_50 ] 431 + [ inline 432 + [ T.dib, T.f7, T.mr2 ] 433 + [ text (String.fromInt <| idx + 1), text "." ] 434 + , text (track.tags.artist ++ " - " ++ track.tags.title) 435 + ] 436 + , actions = [] 437 + }
+18
src/Applications/UI/Queue/ContextMenu.elm
··· 1 + module UI.Queue.ContextMenu exposing (futureItemMenu) 2 + 3 + import ContextMenu exposing (..) 4 + import Coordinates exposing (Coordinates) 5 + import Material.Icons.Action as Icons 6 + import Queue 7 + import Sources exposing (Source) 8 + import UI.Core exposing (Msg(..)) 9 + 10 + 11 + 12 + -- 🔱 13 + 14 + 15 + futureItemMenu : Queue.Item -> Coordinates -> ContextMenu Msg 16 + futureItemMenu item = 17 + ContextMenu 18 + []
+5 -2
src/Applications/UI/Queue/Core.elm
··· 1 1 module UI.Queue.Core exposing (Model, Msg(..)) 2 2 3 + import Html.Events.Extra.Mouse as Mouse 3 4 import Queue exposing (..) 4 5 import Time 5 6 import Tracks exposing (IdentifiedTrack) ··· 26 27 27 28 28 29 type Msg 29 - = ------------------------------------ 30 + = ShowFutureItemMenu Item Mouse.Event 31 + ------------------------------------ 30 32 -- Combos 31 33 ------------------------------------ 32 - InjectFirstAndPlay IdentifiedTrack 34 + | InjectFirstAndPlay IdentifiedTrack 33 35 ------------------------------------ 34 36 -- Future 35 37 ------------------------------------ ··· 43 45 ------------------------------------ 44 46 -- Contents 45 47 ------------------------------------ 48 + | Clear 46 49 | Reset 47 50 | Fill Time.Posix (List IdentifiedTrack) 48 51 ------------------------------------
+1
src/Applications/UI/Reply.elm
··· 20 20 ----------------------------------------- 21 21 -- Context Menu 22 22 ----------------------------------------- 23 + | ShowFutureQueueItemMenu Coordinates Queue.Item 23 24 | ShowMoreAuthenticationOptions Coordinates 24 25 | ShowSourceContextMenu Coordinates Source 25 26 | ShowTracksContextMenu Coordinates (List IdentifiedTrack)
+1 -1
src/Applications/UI/Settings.elm
··· 44 44 UI.Navigation.local 45 45 [ ( Icon Icons.import_export 46 46 , Label "Import / Export" Shown 47 - , GoToPage (UI.Page.Settings ImportExport) 47 + , NavigateToPage (UI.Page.Settings ImportExport) 48 48 ) 49 49 , ( Icon Icons.exit_to_app 50 50 , Label "Sign out" Shown
+1 -1
src/Applications/UI/Settings/ImportExport.elm
··· 25 25 UI.Navigation.local 26 26 [ ( Icon Icons.arrow_back 27 27 , Label "Settings" Hidden 28 - , GoToPage (UI.Page.Settings UI.Settings.Page.Index) 28 + , NavigateToPage (UI.Page.Settings UI.Settings.Page.Index) 29 29 ) 30 30 ] 31 31
+8 -3
src/Applications/UI/Sources.elm
··· 221 221 UI.Navigation.local 222 222 [ ( Icon Icons.add 223 223 , Label "Add a new source" Shown 224 - , UI.Navigation.GoToPage (UI.Page.Sources New) 224 + , NavigateToPage (UI.Page.Sources New) 225 225 ) 226 226 227 227 -- Process ··· 259 259 -- List 260 260 ------- 261 261 , model.collection 262 - |> List.map (\s -> { label = Dict.fetch "name" "" s.data, actions = sourceActions s }) 262 + |> List.map 263 + (\source -> 264 + { label = Html.text (Dict.fetch "name" "" source.data) 265 + , actions = sourceActions source 266 + } 267 + ) 263 268 |> UI.List.view 264 269 ] 265 270 ] ··· 283 288 } 284 289 285 290 -- 286 - , { icon = Icons.settings 291 + , { icon = Icons.more_vert 287 292 , msg = SourceContextMenu source 288 293 , title = "Menu" 289 294 }
+10 -10
src/Applications/UI/Sources/Form.elm
··· 20 20 import UI.Kit exposing (ButtonType(..), select) 21 21 import UI.Navigation exposing (..) 22 22 import UI.Page as Page 23 - import UI.Reply as Reply exposing (Reply) 23 + import UI.Reply as Reply exposing (Reply(..)) 24 24 import UI.Sources.Page as Sources 25 25 26 26 ··· 90 90 in 91 91 returnRepliesWithModel 92 92 { model | step = Where, context = defaultContext } 93 - [ Reply.GoToPage (Page.Sources Sources.Index) 94 - , Reply.AddSourceToCollection cleanContext 93 + [ GoToPage (Page.Sources Sources.Index) 94 + , AddSourceToCollection cleanContext 95 95 ] 96 96 97 97 Bypass -> ··· 100 100 EditSource -> 101 101 returnRepliesWithModel 102 102 { model | step = Where, context = defaultContext } 103 - [ Reply.ReplaceSourceInCollection model.context 104 - , Reply.ProcessSources 105 - , Reply.GoToPage (Page.Sources Sources.Index) 103 + [ ReplaceSourceInCollection model.context 104 + , ProcessSources 105 + , GoToPage (Page.Sources Sources.Index) 106 106 ] 107 107 108 108 ReturnToIndex -> 109 109 returnRepliesWithModel 110 110 model 111 - [ Reply.GoToPage (Page.Sources Sources.Index) ] 111 + [ GoToPage (Page.Sources Sources.Index) ] 112 112 113 113 SelectService serviceKey -> 114 114 case Services.keyToType serviceKey of ··· 145 145 ( Where, Dropbox ) -> 146 146 model.context.data 147 147 |> Sources.Services.Dropbox.authorizationUrl 148 - |> Reply.ExternalSourceAuthorization 148 + |> ExternalSourceAuthorization 149 149 |> returnReplyWithModel model 150 150 151 151 ( Where, Google ) -> 152 152 model.context.data 153 153 |> Sources.Services.Google.authorizationUrl 154 - |> Reply.ExternalSourceAuthorization 154 + |> ExternalSourceAuthorization 155 155 |> returnReplyWithModel model 156 156 157 157 _ -> ··· 206 206 UI.Navigation.local 207 207 [ ( Icon Icons.arrow_back 208 208 , Label "Back to list" Hidden 209 - , GoToPage (Page.Sources Sources.Index) 209 + , NavigateToPage (Page.Sources Sources.Index) 210 210 ) 211 211 ] 212 212
+4 -3
src/Applications/UI/Tracks.elm
··· 33 33 import UI.Navigation exposing (..) 34 34 import UI.Page exposing (Page) 35 35 import UI.Ports 36 + import UI.Queue.Page 36 37 import UI.Reply exposing (Reply(..)) 37 38 import UI.Tracks.Core exposing (..) 38 39 import UI.Tracks.Scene.List ··· 349 350 chunk 350 351 [ T.flex 351 352 , T.flex_column 352 - , T.flex_grow_1 353 + , T.h_100 353 354 ] 354 355 [ lazy3 355 356 navigation ··· 488 489 ) 489 490 , ( Icon Icons.event_seat 490 491 , Label "Queue" Hidden 491 - , PerformMsg Bypass 492 + , NavigateToPage (UI.Page.Queue UI.Queue.Page.Index) 492 493 ) 493 494 , ( Icon Icons.equalizer 494 495 , Label "Equalizer" Hidden 495 - , UI.Navigation.GoToPage UI.Page.Equalizer 496 + , NavigateToPage UI.Page.Equalizer 496 497 ) 497 498 ] 498 499 ]