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

Configure Feed

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

Authentication & EtCetera state

+428 -369
+226 -174
src/Applications/UI.elm
··· 3 3 import Alfred 4 4 import Alien 5 5 import Browser 6 + import Browser.Events 6 7 import Browser.Navigation as Nav 7 8 import Chunky exposing (..) 8 9 import Common exposing (Switch(..)) ··· 10 11 import Css exposing (url) 11 12 import Debouncer.Basic as Debouncer 12 13 import Json.Decode 14 + import Keyboard 13 15 import LastFm 14 16 import Maybe.Extra as Maybe 15 17 import Notifications ··· 28 30 import UI.Audio.Types as Audio 29 31 import UI.Authentication as Authentication 30 32 import UI.Authentication.ContextMenu as Authentication 33 + import UI.Authentication.State as Authentication 31 34 import UI.Backdrop as Backdrop 32 - import UI.Common.State exposing (showNotification, showNotificationWithModel) 35 + import UI.Common.State as Common 33 36 import UI.Equalizer as Equalizer 37 + import UI.EtCetera.State as EtCetera 34 38 import UI.Interface.State as Interface 35 - import UI.Interface.Types as Interface 36 39 import UI.Page as Page 37 40 import UI.Playlists as Playlists 38 41 import UI.Playlists.ContextMenu as Playlists ··· 48 51 import UI.Tracks as Tracks 49 52 import UI.Tracks.ContextMenu as Tracks 50 53 import UI.Tracks.State as Tracks 51 - import UI.Types exposing (..) 54 + import UI.Types as UI exposing (..) 52 55 import UI.User.State as User 53 56 import UI.View exposing (view) 54 57 import Url exposing (Protocol(..), Url) 55 58 import User.Layer exposing (..) 56 - import User.Layer.Methods.RemoteStorage as RemoteStorage 57 59 58 60 59 61 ··· 141 143 Cmd.none 142 144 ) 143 145 |> addCommand 144 - (Task.perform 145 - (Interface.SetCurrentTime >> Interface) 146 - Time.now 147 - ) 146 + (Task.perform SetCurrentTime Time.now) 148 147 149 148 150 149 ··· 152 151 153 152 154 153 update : Msg -> Model -> Return Model Msg 155 - update msg model = 154 + update msg = 156 155 case msg of 157 156 Bypass -> 158 - return model 157 + return 159 158 160 159 Reply reply -> 161 - Reply.translate reply model 160 + Reply.translate reply 162 161 163 162 -- 164 163 Audio a -> 165 - Audio.update a model 166 - 167 - Interface a -> 168 - Interface.update a model 164 + Audio.update a 169 165 170 166 ----------------------------------------- 171 167 -- Authentication 172 168 ----------------------------------------- 173 - AuthenticationBootFailure err -> 174 - model 175 - |> showNotification (Notifications.error err) 176 - |> andThen (Reply.translate LoadDefaultBackdrop) 169 + AuthenticationBootFailure a -> 170 + Authentication.authenticationBootFailure a 177 171 178 - MissingSecretKey json -> 179 - "There seems to be existing data that's encrypted, I will need the passphrase (ie. encryption key) to continue." 180 - |> Notifications.error 181 - |> showNotificationWithModel model 182 - |> andThen (Reply.translate <| Reply.LoadDefaultBackdrop) 183 - |> andThen (Reply.translate <| Reply.ToggleLoadingScreen Off) 172 + MissingSecretKey a -> 173 + Authentication.missingSecretKey a 184 174 185 175 NotAuthenticated -> 186 - -- This is the message we get when the app initially 187 - -- finds out we're not authenticated. 188 - andThen 189 - (update <| BackdropMsg Backdrop.Default) 190 - (if model.isUpgrading then 191 - """ 192 - Thank you for using Diffuse V1! 193 - If you want to import your old data, 194 - please pick the storage method you used before and 195 - go to the [import page](#/settings/import-export). 196 - """ 197 - |> Notifications.stickySuccess 198 - |> showNotificationWithModel { model | isUpgrading = False } 176 + Authentication.notAuthenticated 199 177 200 - else 201 - return model 202 - ) 203 - 204 - RemoteStorageWebfinger remoteStorage (Ok oauthOrigin) -> 205 - let 206 - origin = 207 - Common.urlOrigin model.url 208 - in 209 - remoteStorage 210 - |> RemoteStorage.oauthAddress 211 - { oauthOrigin = oauthOrigin 212 - , origin = origin 213 - } 214 - |> Nav.load 215 - |> returnWithModel model 216 - 217 - RemoteStorageWebfinger _ (Err _) -> 218 - RemoteStorage.webfingerError 219 - |> Notifications.error 220 - |> showNotificationWithModel model 178 + RemoteStorageWebfinger a b -> 179 + Authentication.remoteStorageWebfinger a b 221 180 222 181 ----------------------------------------- 223 182 -- Children 224 183 ----------------------------------------- 225 184 AlfredMsg sub -> 226 - Return3.wieldNested 227 - Reply.translate 228 - { mapCmd = AlfredMsg 229 - , mapModel = \child -> { model | alfred = child } 230 - , update = Alfred.update 231 - } 232 - { model = model.alfred 233 - , msg = sub 234 - } 185 + \model -> 186 + Return3.wieldNested 187 + Reply.translate 188 + { mapCmd = AlfredMsg 189 + , mapModel = \child -> { model | alfred = child } 190 + , update = Alfred.update 191 + } 192 + { model = model.alfred 193 + , msg = sub 194 + } 235 195 236 196 AuthenticationMsg sub -> 237 - Return3.wieldNested 238 - Reply.translate 239 - { mapCmd = AuthenticationMsg 240 - , mapModel = \child -> { model | authentication = child } 241 - , update = Authentication.update 242 - } 243 - { model = model.authentication 244 - , msg = sub 245 - } 197 + \model -> 198 + Return3.wieldNested 199 + Reply.translate 200 + { mapCmd = AuthenticationMsg 201 + , mapModel = \child -> { model | authentication = child } 202 + , update = Authentication.update 203 + } 204 + { model = model.authentication 205 + , msg = sub 206 + } 246 207 247 208 BackdropMsg sub -> 248 - Return3.wieldNested 249 - Reply.translate 250 - { mapCmd = BackdropMsg 251 - , mapModel = \child -> { model | backdrop = child } 252 - , update = Backdrop.update 253 - } 254 - { model = model.backdrop 255 - , msg = sub 256 - } 209 + \model -> 210 + Return3.wieldNested 211 + Reply.translate 212 + { mapCmd = BackdropMsg 213 + , mapModel = \child -> { model | backdrop = child } 214 + , update = Backdrop.update 215 + } 216 + { model = model.backdrop 217 + , msg = sub 218 + } 257 219 258 220 EqualizerMsg sub -> 259 - Return3.wieldNested 260 - Reply.translate 261 - { mapCmd = EqualizerMsg 262 - , mapModel = \child -> { model | equalizer = child } 263 - , update = Equalizer.update 264 - } 265 - { model = model.equalizer 266 - , msg = sub 267 - } 221 + \model -> 222 + Return3.wieldNested 223 + Reply.translate 224 + { mapCmd = EqualizerMsg 225 + , mapModel = \child -> { model | equalizer = child } 226 + , update = Equalizer.update 227 + } 228 + { model = model.equalizer 229 + , msg = sub 230 + } 268 231 269 232 PlaylistsMsg sub -> 270 - Return3.wieldNested 271 - Reply.translate 272 - { mapCmd = PlaylistsMsg 273 - , mapModel = \child -> { model | playlists = child } 274 - , update = Playlists.update 275 - } 276 - { model = model.playlists 277 - , msg = sub 278 - } 233 + \model -> 234 + Return3.wieldNested 235 + Reply.translate 236 + { mapCmd = PlaylistsMsg 237 + , mapModel = \child -> { model | playlists = child } 238 + , update = Playlists.update 239 + } 240 + { model = model.playlists 241 + , msg = sub 242 + } 279 243 280 244 QueueMsg sub -> 281 - Return3.wieldNested 282 - Reply.translate 283 - { mapCmd = QueueMsg 284 - , mapModel = \child -> { model | queue = child } 285 - , update = Queue.update 286 - } 287 - { model = model.queue 288 - , msg = sub 289 - } 245 + \model -> 246 + Return3.wieldNested 247 + Reply.translate 248 + { mapCmd = QueueMsg 249 + , mapModel = \child -> { model | queue = child } 250 + , update = Queue.update 251 + } 252 + { model = model.queue 253 + , msg = sub 254 + } 290 255 291 256 SourcesMsg sub -> 292 - Return3.wieldNested 293 - Reply.translate 294 - { mapCmd = SourcesMsg 295 - , mapModel = \child -> { model | sources = child } 296 - , update = Sources.update 297 - } 298 - { model = model.sources 299 - , msg = sub 300 - } 257 + \model -> 258 + Return3.wieldNested 259 + Reply.translate 260 + { mapCmd = SourcesMsg 261 + , mapModel = \child -> { model | sources = child } 262 + , update = Sources.update 263 + } 264 + { model = model.sources 265 + , msg = sub 266 + } 301 267 302 268 TracksMsg sub -> 303 - Return3.wieldNested 304 - Reply.translate 305 - { mapCmd = TracksMsg 306 - , mapModel = \child -> { model | tracks = child } 307 - , update = Tracks.update 308 - } 309 - { model = model.tracks 310 - , msg = sub 311 - } 269 + \model -> 270 + Return3.wieldNested 271 + Reply.translate 272 + { mapCmd = TracksMsg 273 + , mapModel = \child -> { model | tracks = child } 274 + , update = Tracks.update 275 + } 276 + { model = model.tracks 277 + , msg = sub 278 + } 279 + 280 + ----------------------------------------- 281 + -- Interface 282 + ----------------------------------------- 283 + Blur -> 284 + Interface.blur 285 + 286 + Debounce a -> 287 + Interface.debounce update a 288 + 289 + FocusedOnInput -> 290 + Interface.focusedOnInput 291 + 292 + HideOverlay -> 293 + Interface.hideOverlay 294 + 295 + KeyboardMsg a -> 296 + Interface.keyboardMsg a 297 + 298 + PreferredColorSchemaChanged a -> 299 + Interface.preferredColorSchemaChanged a 300 + 301 + RemoveQueueSelection -> 302 + Interface.removeQueueSelection 303 + 304 + RemoveTrackSelection -> 305 + Interface.removeTrackSelection 306 + 307 + ResizedWindow a -> 308 + Interface.resizedWindow a 309 + 310 + SetIsTouchDevice a -> 311 + Interface.setIsTouchDevice a 312 + 313 + ShowNotification a -> 314 + Common.showNotification a 315 + 316 + StoppedDragging -> 317 + Interface.stoppedDragging 318 + 319 + UI.ToggleLoadingScreen a -> 320 + Interface.toggleLoadingScreen a 312 321 313 322 ----------------------------------------- 314 323 -- Routing 315 324 ----------------------------------------- 316 325 ChangeUrlUsingPage a -> 317 - Routing.changeUrlUsingPage a model 326 + Routing.changeUrlUsingPage a 318 327 319 328 LinkClicked a -> 320 - Routing.linkClicked a model 329 + Routing.linkClicked a 321 330 322 331 PageChanged a -> 323 - Routing.transition a model 332 + Routing.transition a 324 333 325 334 UrlChanged a -> 326 - Routing.urlChanged a model 335 + Routing.urlChanged a 327 336 328 337 ----------------------------------------- 329 338 -- Services 330 339 ----------------------------------------- 331 340 GotLastFmSession a -> 332 - Services.gotLastFmSession a model 341 + Services.gotLastFmSession a 333 342 334 343 Scrobble a -> 335 - Services.scrobble a model 344 + Services.scrobble a 336 345 337 346 ----------------------------------------- 338 347 -- Tracks 339 348 ----------------------------------------- 340 349 DownloadTracksFinished -> 341 - Tracks.downloadTracksFinished model 350 + Tracks.downloadTracksFinished 342 351 343 352 FailedToStoreTracksInCache a -> 344 - Tracks.failedToStoreTracksInCache a model 353 + Tracks.failedToStoreTracksInCache a 345 354 346 355 FinishedStoringTracksInCache a -> 347 - Tracks.finishedStoringTracksInCache a model 356 + Tracks.finishedStoringTracksInCache a 348 357 349 358 ----------------------------------------- 350 359 -- User 351 360 ----------------------------------------- 352 361 ImportFile a -> 353 - User.importFile a model 362 + User.importFile a 354 363 355 364 ImportJson a -> 356 - User.importJson a model 365 + User.importJson a 357 366 358 367 LoadEnclosedUserData a -> 359 - User.loadEnclosedUserData a model 368 + User.loadEnclosedUserData a 360 369 361 370 LoadHypaethralUserData a -> 362 - User.loadHypaethralUserData a model 371 + User.loadHypaethralUserData a 372 + 373 + ----------------------------------------- 374 + -- 📭 Et Cetera 375 + ----------------------------------------- 376 + SetCurrentTime a -> 377 + EtCetera.setCurrentTime a 378 + 379 + SetIsOnline a -> 380 + EtCetera.setIsOnline a 363 381 364 382 365 383 ··· 369 387 subscriptions : Model -> Sub Msg 370 388 subscriptions model = 371 389 Sub.batch 372 - [ Ports.fromAlien alien 390 + [ Audio.subscriptions model 391 + , Ports.fromAlien alien 392 + 393 + ----------------------------------------- 394 + -- Alfred 395 + ----------------------------------------- 396 + , case model.alfred.instance of 397 + Just _ -> 398 + Sub.map AlfredMsg (Alfred.subscriptions model.alfred) 399 + 400 + Nothing -> 401 + Sub.none 373 402 403 + ----------------------------------------- 404 + -- Backdrop 405 + ----------------------------------------- 406 + , Ports.setAverageBackgroundColor (Backdrop.BackgroundColor >> BackdropMsg) 407 + 408 + ----------------------------------------- 409 + -- Interface 410 + ----------------------------------------- 411 + , Ports.indicateTouchDevice (\_ -> SetIsTouchDevice True) 412 + , Ports.preferredColorSchemaChanged PreferredColorSchemaChanged 413 + , Ports.showErrorNotification (Notifications.error >> ShowNotification) 414 + , Ports.showStickyErrorNotification (Notifications.stickyError >> ShowNotification) 415 + 416 + ----------------------------------------- 374 417 -- Queue 375 - -------- 418 + ----------------------------------------- 376 419 , Ports.activeQueueItemEnded (QueueMsg << always Queue.Shift) 377 420 , Ports.requestNext <| always (QueueMsg Queue.Shift) 378 421 , Ports.requestPrevious <| always (QueueMsg Queue.Rewind) 379 422 380 - -- Children 381 - ----------- 382 - , ifThenElse 383 - (Maybe.isJust model.alfred.instance) 384 - (Sub.map AlfredMsg <| Alfred.subscriptions model.alfred) 385 - Sub.none 423 + ----------------------------------------- 424 + -- Services 425 + ----------------------------------------- 426 + , Ports.scrobble Scrobble 386 427 387 - -- 428 + ----------------------------------------- 429 + -- Tracks 430 + ----------------------------------------- 388 431 , Ports.downloadTracksFinished (\_ -> DownloadTracksFinished) 389 - , Ports.scrobble Scrobble 390 - , Ports.setAverageBackgroundColor (Backdrop.BackgroundColor >> BackdropMsg) 391 432 392 - -- 393 - , Audio.subscriptions model 394 - , Interface.subscriptions model 433 + ----------------------------------------- 434 + -- 📭 Et Cetera 435 + ----------------------------------------- 436 + , Ports.setIsOnline SetIsOnline 437 + , Sub.map KeyboardMsg Keyboard.subscriptions 438 + , Time.every (60 * 1000) SetCurrentTime 439 + 440 + -- Resize 441 + --------- 442 + , Browser.Events.onResize 443 + (\w h -> 444 + ( w, h ) 445 + |> ResizedWindow 446 + |> Debouncer.provideInput 447 + |> Debounce 448 + ) 395 449 ] 396 450 397 451 ··· 433 487 SourcesMsg Sources.FinishedProcessing 434 488 435 489 Just Alien.HideLoadingScreen -> 436 - Interface (Interface.ToggleLoadingScreen Off) 490 + UI.ToggleLoadingScreen Off 437 491 438 492 Just Alien.ImportLegacyData -> 439 493 "Imported data successfully!" 440 494 |> Notifications.success 441 - |> Interface.ShowNotification 442 - |> Interface 495 + |> ShowNotification 443 496 444 497 Just Alien.LoadEnclosedUserData -> 445 498 LoadEnclosedUserData event.data ··· 475 528 FinishedStoringTracksInCache list 476 529 477 530 Err err -> 478 - err 479 - |> Json.Decode.errorToString 480 - |> Notifications.error 481 - |> Interface.ShowNotification 482 - |> Interface 531 + showErrorNotification (Json.Decode.errorToString err) 483 532 484 533 Just Alien.UpdateSourceData -> 485 534 SourcesMsg (Sources.UpdateSourceData event.data) ··· 521 570 FailedToStoreTracksInCache trackIds 522 571 523 572 Err _ -> 524 - err 525 - |> Notifications.error 526 - |> Interface.ShowNotification 527 - |> Interface 573 + showErrorNotification err 528 574 529 575 _ -> 530 - err 531 - |> Notifications.error 532 - |> Interface.ShowNotification 533 - |> Interface 576 + showErrorNotification err 577 + 578 + 579 + 580 + -- ⚗️ 581 + 582 + 583 + showErrorNotification : String -> Msg 584 + showErrorNotification = 585 + Notifications.error >> ShowNotification
+79
src/Applications/UI/Authentication/State.elm
··· 1 + module UI.Authentication.State exposing (..) 2 + 3 + import Browser.Navigation as Nav 4 + import Common exposing (Switch(..)) 5 + import Http 6 + import Json.Decode as Json 7 + import Management 8 + import Monocle.Lens as Lens 9 + import Notifications 10 + import Return exposing (andThen, return) 11 + import Return.Ext as Return exposing (communicate) 12 + import UI.Common.State as Common exposing (showNotification, showNotificationWithModel) 13 + import UI.Reply as Reply exposing (Reply(..)) 14 + import UI.Reply.Translate as Reply 15 + import UI.Types as UI exposing (Manager, Msg(..)) 16 + import User.Layer.Methods.RemoteStorage as RemoteStorage 17 + 18 + 19 + 20 + -- 📣 21 + 22 + 23 + authenticationBootFailure : String -> UI.Manager 24 + authenticationBootFailure err model = 25 + model 26 + |> showNotification (Notifications.error err) 27 + |> andThen (Reply.translate LoadDefaultBackdrop) 28 + 29 + 30 + missingSecretKey : Json.Value -> UI.Manager 31 + missingSecretKey _ model = 32 + "There seems to be existing data that's encrypted, I will need the passphrase (ie. encryption key) to continue." 33 + |> Notifications.error 34 + |> showNotificationWithModel model 35 + |> andThen (Reply.translate <| Reply.LoadDefaultBackdrop) 36 + |> andThen (Reply.translate <| Reply.ToggleLoadingScreen Off) 37 + 38 + 39 + notAuthenticated : UI.Manager 40 + notAuthenticated model = 41 + -- This is the message we get when the app initially 42 + -- finds out we're not authenticated. 43 + andThen 44 + (Reply.translate Reply.LoadDefaultBackdrop) 45 + (if model.isUpgrading then 46 + """ 47 + Thank you for using Diffuse V1! 48 + If you want to import your old data, 49 + please pick the storage method you used before and 50 + go to the [import page](#/settings/import-export). 51 + """ 52 + |> Notifications.stickySuccess 53 + |> showNotificationWithModel { model | isUpgrading = False } 54 + 55 + else 56 + Return.singleton model 57 + ) 58 + 59 + 60 + remoteStorageWebfinger : RemoteStorage.Attributes -> Result Http.Error String -> UI.Manager 61 + remoteStorageWebfinger remoteStorage result model = 62 + case result of 63 + Ok oauthOrigin -> 64 + let 65 + origin = 66 + Common.urlOrigin model.url 67 + in 68 + remoteStorage 69 + |> RemoteStorage.oauthAddress 70 + { oauthOrigin = oauthOrigin 71 + , origin = origin 72 + } 73 + |> Nav.load 74 + |> return model 75 + 76 + Err _ -> 77 + RemoteStorage.webfingerError 78 + |> Notifications.error 79 + |> showNotificationWithModel model
+84
src/Applications/UI/EtCetera/State.elm
··· 1 + module UI.EtCetera.State exposing (..) 2 + 3 + import Alien 4 + import Browser.Events 5 + import Common exposing (Switch(..)) 6 + import Debouncer.Basic as Debouncer 7 + import Keyboard 8 + import Management 9 + import Maybe.Extra as Maybe 10 + import Monocle.Lens as Lens 11 + import Notifications 12 + import Return exposing (return) 13 + import Return.Ext as Return exposing (communicate) 14 + import Time 15 + import UI.Authentication as Authentication 16 + import UI.Common.State as Common exposing (modifySingleton) 17 + import UI.DnD as DnD 18 + import UI.Page as Page 19 + import UI.Ports as Ports 20 + import UI.Queue as Queue 21 + import UI.Queue.State as Queue 22 + import UI.Reply as Reply 23 + import UI.Sources.State as Sources 24 + import UI.Tracks as Tracks 25 + import UI.Tracks.Scene.List 26 + import UI.Tracks.State as Tracks 27 + import UI.Types as UI exposing (..) 28 + import User.Layer exposing (..) 29 + 30 + 31 + 32 + -- 📣 33 + 34 + 35 + setIsOnline : Bool -> UI.Manager 36 + setIsOnline bool model = 37 + if bool then 38 + -- We're caching the user's data in the browser while offline. 39 + -- If we're back online again, sync all the user's data. 40 + (case model.authentication of 41 + Authentication.Authenticated (Dropbox _) -> 42 + syncHypaethralData 43 + 44 + Authentication.Authenticated (RemoteStorage _) -> 45 + syncHypaethralData 46 + 47 + _ -> 48 + Return.singleton 49 + ) 50 + { model | isOnline = True } 51 + 52 + else 53 + -- The app went offline, cache everything 54 + -- (if caching is supported). 55 + ( { model | isOnline = False } 56 + , case model.authentication of 57 + Authentication.Authenticated (Dropbox _) -> 58 + Ports.toBrain (Alien.trigger Alien.SyncHypaethralData) 59 + 60 + Authentication.Authenticated (RemoteStorage _) -> 61 + Ports.toBrain (Alien.trigger Alien.SyncHypaethralData) 62 + 63 + _ -> 64 + Cmd.none 65 + ) 66 + 67 + 68 + setCurrentTime : Time.Posix -> UI.Manager 69 + setCurrentTime time model = 70 + model 71 + |> (\m -> { m | currentTime = time }) 72 + |> Lens.modify Sources.lens (\s -> { s | currentTime = time }) 73 + |> Return.singleton 74 + 75 + 76 + 77 + -- ⚗️ 78 + 79 + 80 + syncHypaethralData : UI.Manager 81 + syncHypaethralData model = 82 + model 83 + |> Common.showNotification (Notifications.warning "Syncing") 84 + |> Return.command (Ports.toBrain <| Alien.trigger Alien.SyncHypaethralData)
+3 -139
src/Applications/UI/Interface/State.elm
··· 15 15 import UI.Authentication as Authentication 16 16 import UI.Common.State as Common exposing (modifySingleton) 17 17 import UI.DnD as DnD 18 - import UI.Interface.Types as Interface exposing (Msg(..)) 19 18 import UI.Page as Page 20 19 import UI.Ports as Ports 21 20 import UI.Queue as Queue ··· 33 32 -- 📣 34 33 35 34 36 - update : Interface.Msg -> Manager 37 - update msg = 38 - case msg of 39 - Blur -> 40 - blur 41 - 42 - Debounce a -> 43 - debounce a 44 - 45 - FocusedOnInput -> 46 - focusedOnInput 47 - 48 - HideOverlay -> 49 - hideOverlay 50 - 51 - KeyboardMsg a -> 52 - keyboardMsg a 53 - 54 - PreferredColorSchemaChanged a -> 55 - preferredColorSchemaChanged a 56 - 57 - RemoveQueueSelection -> 58 - removeQueueSelection 59 - 60 - RemoveTrackSelection -> 61 - removeTrackSelection 62 - 63 - ResizedWindow a -> 64 - resizedWindow a 65 - 66 - SetCurrentTime a -> 67 - setCurrentTime a 68 - 69 - SetIsOnline a -> 70 - setIsOnline a 71 - 72 - SetIsTouchDevice a -> 73 - setIsTouchDevice a 74 - 75 - ShowNotification a -> 76 - Common.showNotification a 77 - 78 - StoppedDragging -> 79 - stoppedDragging 80 - 81 - ToggleLoadingScreen a -> 82 - toggleLoadingScreen a 83 - 84 - 85 - 86 - -- 📰 87 - 88 - 89 - subscriptions : UI.Model -> Sub UI.Msg 90 - subscriptions _ = 91 - [ Ports.indicateTouchDevice (\_ -> SetIsTouchDevice True) 92 - , Ports.preferredColorSchemaChanged PreferredColorSchemaChanged 93 - , Ports.setIsOnline SetIsOnline 94 - , Ports.showErrorNotification (Notifications.error >> ShowNotification) 95 - , Ports.showStickyErrorNotification (Notifications.stickyError >> ShowNotification) 96 - 97 - -- Resize 98 - --------- 99 - , Browser.Events.onResize 100 - (\w h -> 101 - ( w, h ) 102 - |> ResizedWindow 103 - |> Debouncer.provideInput 104 - |> Debounce 105 - ) 106 - 107 - -- 108 - , Sub.map KeyboardMsg Keyboard.subscriptions 109 - , Time.every (60 * 1000) SetCurrentTime 110 - ] 111 - |> Sub.batch 112 - |> Sub.map UI.Interface 113 - 114 - 115 - 116 - -- 🔱 117 - 118 - 119 35 blur : UI.Manager 120 36 blur model = 121 37 Return.singleton { model | focusedOnInput = False } 122 38 123 39 124 - debounce : Debouncer.Msg Interface.Msg -> UI.Manager 125 - debounce debouncerMsg model = 40 + debounce : (Msg -> Model -> ( Model, Cmd Msg )) -> Debouncer.Msg Msg -> UI.Manager 41 + debounce update debouncerMsg model = 126 42 let 127 43 ( subModel, subCmd, emittedMsg ) = 128 44 Debouncer.update debouncerMsg model.debounce 129 45 130 46 mappedCmd = 131 - Cmd.map (Debounce >> UI.Interface) subCmd 47 + Cmd.map Debounce subCmd 132 48 133 49 updatedModel = 134 50 { model | debounce = subModel } ··· 236 152 } 237 153 238 154 239 - setIsOnline : Bool -> UI.Manager 240 - setIsOnline bool model = 241 - if bool then 242 - -- We're caching the user's data in the browser while offline. 243 - -- If we're back online again, sync all the user's data. 244 - (case model.authentication of 245 - Authentication.Authenticated (Dropbox _) -> 246 - syncHypaethralData 247 - 248 - Authentication.Authenticated (RemoteStorage _) -> 249 - syncHypaethralData 250 - 251 - _ -> 252 - Return.singleton 253 - ) 254 - { model | isOnline = True } 255 - 256 - else 257 - -- The app went offline, cache everything 258 - -- (if caching is supported). 259 - ( { model | isOnline = False } 260 - , case model.authentication of 261 - Authentication.Authenticated (Dropbox _) -> 262 - Ports.toBrain (Alien.trigger Alien.SyncHypaethralData) 263 - 264 - Authentication.Authenticated (RemoteStorage _) -> 265 - Ports.toBrain (Alien.trigger Alien.SyncHypaethralData) 266 - 267 - _ -> 268 - Cmd.none 269 - ) 270 - 271 - 272 - setCurrentTime : Time.Posix -> UI.Manager 273 - setCurrentTime time model = 274 - model 275 - |> (\m -> { m | currentTime = time }) 276 - |> Lens.modify Sources.lens (\s -> { s | currentTime = time }) 277 - |> Return.singleton 278 - 279 - 280 155 setIsTouchDevice : Bool -> UI.Manager 281 156 setIsTouchDevice bool model = 282 157 Return.singleton { model | isTouchDevice = bool } ··· 320 195 321 196 Off -> 322 197 Return.singleton { model | isLoading = False } 323 - 324 - 325 - 326 - -- ⚗️ 327 - 328 - 329 - syncHypaethralData : UI.Manager 330 - syncHypaethralData model = 331 - model 332 - |> Common.showNotification (Notifications.warning "Syncing") 333 - |> Return.command (Ports.toBrain <| Alien.trigger Alien.SyncHypaethralData)
-30
src/Applications/UI/Interface/Types.elm
··· 1 - module UI.Interface.Types exposing (..) 2 - 3 - import Common exposing (Switch) 4 - import Debouncer.Basic as Debouncer exposing (Debouncer) 5 - import Keyboard 6 - import Notifications exposing (Notification) 7 - import Time 8 - import UI.Reply exposing (Reply) 9 - 10 - 11 - 12 - -- 📣 13 - 14 - 15 - type Msg 16 - = Blur 17 - | Debounce (Debouncer.Msg Msg) 18 - | FocusedOnInput 19 - | HideOverlay 20 - | KeyboardMsg Keyboard.Msg 21 - | PreferredColorSchemaChanged { dark : Bool } 22 - | RemoveQueueSelection 23 - | RemoveTrackSelection 24 - | ResizedWindow ( Int, Int ) 25 - | ShowNotification (Notification Reply) 26 - | SetCurrentTime Time.Posix 27 - | SetIsOnline Bool 28 - | SetIsTouchDevice Bool 29 - | StoppedDragging 30 - | ToggleLoadingScreen Switch
+1 -2
src/Applications/UI/Reply/Translate.elm
··· 58 58 import UI.Demo as Demo 59 59 import UI.Equalizer as Equalizer 60 60 import UI.Interface.State as Interface 61 - import UI.Interface.Types as Interface 62 61 import UI.Navigation as Navigation 63 62 import UI.Notifications 64 63 import UI.Page as Page ··· 111 110 StartedDragging -> 112 111 Return.singleton { model | isDragging = True } 113 112 114 - ToggleLoadingScreen a -> 113 + Reply.ToggleLoadingScreen a -> 115 114 Interface.toggleLoadingScreen a model 116 115 117 116 -----------------------------------------
+24 -5
src/Applications/UI/Types.elm
··· 7 7 import Browser.Events 8 8 import Browser.Navigation as Nav 9 9 import Chunky exposing (..) 10 - import Common exposing (Switch(..)) 10 + import Common exposing (Switch) 11 11 import Conditional exposing (..) 12 12 import ContextMenu exposing (ContextMenu) 13 13 import Coordinates exposing (Viewport) 14 14 import Css exposing (url) 15 15 import Css.Classes as C 16 - import Debouncer.Basic exposing (Debouncer) 16 + import Debouncer.Basic as Debouncer exposing (Debouncer) 17 17 import Dict exposing (Dict) 18 18 import Dict.Ext as Dict 19 19 import File exposing (File) ··· 59 59 import UI.Demo as Demo 60 60 import UI.DnD as DnD 61 61 import UI.Equalizer as Equalizer 62 - import UI.Interface.Types as Interface 63 62 import UI.Navigation as Navigation 64 63 import UI.Notifications 65 64 import UI.Page as Page exposing (Page) ··· 109 108 , confirmation : Maybe String 110 109 , currentTime : Time.Posix 111 110 , darkMode : Bool 112 - , debounce : Debouncer Interface.Msg Interface.Msg 111 + , debounce : Debouncer Msg Msg 113 112 , downloading : Maybe { notificationId : Int } 114 113 , focusedOnInput : Bool 115 114 , isDragging : Bool ··· 154 153 | Reply Reply 155 154 -- 156 155 | Audio Audio.Msg 157 - | Interface Interface.Msg 158 156 ----------------------------------------- 159 157 -- Authentication 160 158 ----------------------------------------- ··· 174 172 | SourcesMsg Sources.Msg 175 173 | TracksMsg Tracks.Msg 176 174 ----------------------------------------- 175 + -- Interface 176 + ----------------------------------------- 177 + | Blur 178 + | Debounce (Debouncer.Msg Msg) 179 + | FocusedOnInput 180 + | HideOverlay 181 + | KeyboardMsg Keyboard.Msg 182 + | PreferredColorSchemaChanged { dark : Bool } 183 + | RemoveQueueSelection 184 + | RemoveTrackSelection 185 + | ResizedWindow ( Int, Int ) 186 + | ShowNotification (Notification Reply) 187 + | SetIsTouchDevice Bool 188 + | StoppedDragging 189 + | ToggleLoadingScreen Switch 190 + ----------------------------------------- 177 191 -- Routing 178 192 ----------------------------------------- 179 193 | ChangeUrlUsingPage Page ··· 198 212 | ImportJson String 199 213 | LoadEnclosedUserData Json.Decode.Value 200 214 | LoadHypaethralUserData Json.Decode.Value 215 + ----------------------------------------- 216 + -- 📭 Et Cetera 217 + ----------------------------------------- 218 + | SetCurrentTime Time.Posix 219 + | SetIsOnline Bool 201 220 202 221 203 222 type alias Organizer model =
+11 -19
src/Applications/UI/View.elm
··· 31 31 import UI.Console 32 32 import UI.ContextMenu 33 33 import UI.Equalizer as Equalizer 34 - import UI.Interface.State as Interface 35 - import UI.Interface.Types as Interface 36 34 import UI.Navigation as Navigation 37 35 import UI.Notifications 38 36 import UI.Page as Page ··· 49 47 import UI.Svg.Elements 50 48 import UI.Tracks as Tracks 51 49 import UI.Tracks.ContextMenu as Tracks 52 - import UI.Tracks.State as Tracks 53 - import UI.Types as UI exposing (..) 50 + import UI.Types exposing (..) 54 51 import Url exposing (Protocol(..)) 55 52 import User.Layer exposing (..) 56 53 ··· 70 67 body model = 71 68 section 72 69 (if Maybe.isJust model.contextMenu || Maybe.isJust model.alfred.instance then 73 - [ on "tap" (interfaceEventHandler Interface.HideOverlay) ] 70 + [ on "tap" (Json.Decode.succeed HideOverlay) ] 74 71 75 72 else if Maybe.isJust model.equalizer.activeKnob then 76 73 [ Pointer.onMove (EqualizerMsg << Equalizer.AdjustKnob) ··· 80 77 81 78 else if model.isDragging then 82 79 [ class C.dragging_something 83 - , on "mouseup" (interfaceEventHandler Interface.StoppedDragging) 84 - , on "touchcancel" (interfaceEventHandler Interface.StoppedDragging) 85 - , on "touchend" (interfaceEventHandler Interface.StoppedDragging) 80 + , on "mouseup" (Json.Decode.succeed StoppedDragging) 81 + , on "touchcancel" (Json.Decode.succeed StoppedDragging) 82 + , on "touchend" (Json.Decode.succeed StoppedDragging) 86 83 ] 87 84 88 85 else if Maybe.isJust model.queue.selection then 89 - [ on "tap" (interfaceEventHandler Interface.RemoveQueueSelection) ] 86 + [ on "tap" (Json.Decode.succeed RemoveQueueSelection) ] 90 87 91 88 else if not (List.isEmpty model.tracks.selectedTrackIndexes) then 92 - [ on "tap" (interfaceEventHandler Interface.RemoveTrackSelection) ] 89 + [ on "tap" (Json.Decode.succeed RemoveTrackSelection) ] 93 90 94 91 else 95 92 [] ··· 252 249 content : { justifyCenter : Bool, scrolling : Bool } -> List (Html Msg) -> Html Msg 253 250 content { justifyCenter, scrolling } nodes = 254 251 brick 255 - [ on "focusout" (interfaceEventHandler Interface.Blur) 252 + [ on "focusout" (Json.Decode.succeed Blur) 256 253 , on "focusin" inputFocusDecoder 257 254 , style "height" "calc(var(--vh, 1vh) * 100)" 258 255 ] ··· 292 289 (\targetTagName -> 293 290 case targetTagName of 294 291 "INPUT" -> 295 - interfaceEventHandler Interface.FocusedOnInput 292 + Json.Decode.succeed FocusedOnInput 296 293 297 294 "TEXTAREA" -> 298 - interfaceEventHandler Interface.FocusedOnInput 295 + Json.Decode.succeed FocusedOnInput 299 296 300 297 _ -> 301 298 Json.Decode.fail "NOT_INPUT" 302 299 ) 303 - 304 - 305 - interfaceEventHandler : Interface.Msg -> Json.Decode.Decoder UI.Msg 306 - interfaceEventHandler = 307 - Interface >> Json.Decode.succeed 308 300 309 301 310 302 loadingAnimation : Html msg ··· 319 311 Maybe.isJust maybeAlfred || Maybe.isJust maybeContextMenu 320 312 in 321 313 brick 322 - [ onClick (Interface Interface.HideOverlay) ] 314 + [ onClick HideOverlay ] 323 315 [ C.inset_0 324 316 , C.bg_black 325 317 , C.fixed