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.

Fixes #150

+63 -24
+35 -17
src/Applications/Brain.elm
··· 12 12 import Json.Decode as Json 13 13 import Json.Encode 14 14 import List.Extra as List 15 + import List.Zipper as Zipper exposing (Zipper) 15 16 import Maybe.Extra as Maybe 16 17 import Playlists.Encoding as Playlists 17 18 import Return2 exposing (..) ··· 49 50 50 51 type alias Model = 51 52 { hypaethralDebouncer : Debouncer HypaethralBit (List HypaethralBit) 53 + , hypaethralStorage : List HypaethralBit 52 54 , hypaethralUserData : User.HypaethralData 53 55 54 56 -- Children ··· 83 85 -- Initial model 84 86 ----------------------------------------- 85 87 { hypaethralDebouncer = hypDebouncer 88 + , hypaethralStorage = [] 86 89 , hypaethralUserData = User.emptyHypaethralData 87 90 88 91 -- Children ··· 136 139 ----------------------------------------- 137 140 | RemoveEncryptionKey 138 141 | SaveHypaethralDataSlowly (Debouncer.Msg HypaethralBit) 139 - | SaveHypaethralData HypaethralBit 142 + | SaveHypaethralData (List HypaethralBit) 143 + | SaveNextHypaethralBit 140 144 141 145 142 146 update : Msg -> Model -> ( Model, Cmd Msg ) ··· 272 276 |> Maybe.withDefault [] 273 277 |> EverySet.fromList 274 278 |> EverySet.toList 275 - |> List.map SaveHypaethralData 279 + |> SaveHypaethralData 280 + |> List.singleton 276 281 ) 277 282 } 278 283 { model = model.hypaethralDebouncer 279 284 , msg = debouncerMsg 280 285 } 281 286 282 - SaveHypaethralData bit -> 283 - model.hypaethralUserData 284 - |> User.encodeHypaethralBit bit 285 - |> User.SaveHypaethralData bit 286 - |> UserLayerMsg 287 - |> updateWithModel model 287 + SaveHypaethralData bits -> 288 + case model.hypaethralStorage ++ bits of 289 + bit :: rest -> 290 + model.hypaethralUserData 291 + |> User.encodeHypaethralBit bit 292 + |> User.SaveHypaethralData bit 293 + |> UserLayerMsg 294 + |> updateWithModel { model | hypaethralStorage = rest } 295 + 296 + _ -> 297 + return model 298 + 299 + SaveNextHypaethralBit -> 300 + case model.hypaethralStorage of 301 + bit :: rest -> 302 + model.hypaethralUserData 303 + |> User.encodeHypaethralBit bit 304 + |> User.SaveHypaethralData bit 305 + |> UserLayerMsg 306 + |> updateWithModel { model | hypaethralStorage = rest } 307 + 308 + _ -> 309 + return model 288 310 289 311 290 312 saveTracks : Model -> List Tracks.Track -> Return Model Msg ··· 445 467 446 468 saveAllHypaethralData : Model -> ( Model, Cmd Msg ) 447 469 saveAllHypaethralData model = 448 - List.foldl 449 - (\bit -> 450 - bit 451 - |> SaveHypaethralData 452 - |> update 453 - |> andThen 454 - ) 455 - (return model) 456 - (List.map Tuple.second User.hypaethralBit.list) 470 + User.hypaethralBit.list 471 + |> List.map Tuple.second 472 + |> SaveHypaethralData 473 + |> updateWithModel model 457 474 458 475 459 476 saveHypaethralDataBitWithDelay : User.HypaethralBit -> Model -> ( Model, Cmd Msg ) ··· 472 489 subscriptions model = 473 490 Sub.batch 474 491 [ Brain.Ports.fromAlien alien 492 + , Brain.Ports.savedHypaethralBit (always SaveNextHypaethralBit) 475 493 476 494 ----------------------------------------- 477 495 -- Children
+4 -1
src/Applications/Brain/Ports.elm
··· 1 - port module Brain.Ports exposing (deconstructBlockstack, deconstructRemoteStorage, fabricateSecretKey, fromAlien, handlePendingBlockstackSignIn, receiveSearchResults, receiveTags, redirectToBlockstackSignIn, removeCache, removeTracksFromCache, requestBlockstack, requestCache, requestDropbox, requestIpfs, requestLegacyLocalData, requestRemoteStorage, requestSearch, requestTags, requestTextile, storeTracksInCache, toBlockstack, toCache, toDropbox, toIpfs, toRemoteStorage, toTextile, toUI, updateSearchIndex) 1 + port module Brain.Ports exposing (deconstructBlockstack, deconstructRemoteStorage, fabricateSecretKey, fromAlien, handlePendingBlockstackSignIn, receiveSearchResults, receiveTags, redirectToBlockstackSignIn, removeCache, removeTracksFromCache, requestBlockstack, requestCache, requestDropbox, requestIpfs, requestLegacyLocalData, requestRemoteStorage, requestSearch, requestTags, requestTextile, savedHypaethralBit, storeTracksInCache, toBlockstack, toCache, toDropbox, toIpfs, toRemoteStorage, toTextile, toUI, updateSearchIndex) 2 2 3 3 import Alien 4 4 import Json.Encode as Json ··· 99 99 100 100 101 101 port receiveTags : (ContextForTags -> msg) -> Sub msg 102 + 103 + 104 + port savedHypaethralBit : (Json.Value -> msg) -> Sub msg
+1 -1
src/Applications/UI.elm
··· 1321 1321 |> returnWithModel (updateTracksModel (\m -> { m | cached = [] }) model) 1322 1322 |> andThen (update <| TracksMsg Tracks.Harvest) 1323 1323 |> andThen (translateReply SaveEnclosedUserData) 1324 - |> andThen (translateReply <| ShowSuccessNotification "Tracks cache was cleared") 1324 + |> andThen (translateReply <| ShowWarningNotification "Tracks cache was cleared") 1325 1325 1326 1326 DisableTracksGrouping -> 1327 1327 Tracks.DisableGrouping
+16 -5
src/Javascript/Workers/Brain/user.js
··· 121 121 122 122 bl 123 123 .putFile(event.data.file, json) 124 + .then( storageCallback(event) ) 124 125 .catch( reportError(event) ) 125 126 }) 126 127 ··· 175 176 body: data 176 177 }) 177 178 }) 179 + .then( storageCallback(event) ) 178 180 .catch(reporter) 179 181 180 182 toCache(event.tag + "_" + event.data.file, event.data.data) 183 + .then( !navigator.onLine ? storageCallback(event) : identity ) 181 184 .catch(reporter) 182 185 }) 183 186 ··· 223 226 apiOrigin + "/api/v0/files/write?" + params, 224 227 { method: "POST", body: formData } 225 228 ) 226 - 227 - }).catch( 228 - reportError(event) 229 - 230 - ) 229 + }) 230 + .then( storageCallback(event) ) 231 + .catch( reportError(event) ) 231 232 }) 232 233 233 234 ··· 319 320 !isOffline && remoteStorage(event) 320 321 .then(doEncryption) 321 322 .then(data => rsClient.storeFile("application/json", event.data.file, data)) 323 + .then( storageCallback(event) ) 322 324 .catch( reportError(event) ) 323 325 324 326 toCache(event.tag + "_" + event.data.file, event.data.data) 327 + .then( isOffline ? storageCallback(event) : identity ) 325 328 .catch( reportError(event) ) 326 329 }) 327 330 ··· 371 374 .then(_ => Textile.useMill(apiOrigin, event.data.file, json)) 372 375 .then(m => Textile.addFileToThread(apiOrigin, m)) 373 376 377 + .then( storageCallback(event) ) 374 378 .catch( reportError(event) ) 375 379 }) 376 380 ··· 448 452 function sendJsonData(event) { 449 453 return sendData(event, { parseJSON: true }) 450 454 } 455 + 456 + 457 + function storageCallback(event) { 458 + return _ => { 459 + app.ports.savedHypaethralBit.send() 460 + } 461 + }
+2
src/Javascript/Workers/brain.js
··· 8 8 importScripts("../vendor/subworkers-polyfill.min.js") 9 9 10 10 importScripts("../brain.js") 11 + importScripts("../common.js") 11 12 importScripts("../crypto.js") 12 13 importScripts("../indexed-db.js") 13 14 importScripts("../processing.js") ··· 81 82 : event.tag 82 83 83 84 toCache(key, event.data.data || event.data) 85 + .then( storageCallback(event) ) 84 86 .catch( reportError(event) ) 85 87 }) 86 88
+5
src/Javascript/common.js
··· 16 16 if (wasCalledBefore) { return } else { wasCalledBefore = true } 17 17 setTimeout(() => { callback(...lastestArgs); wasCalledBefore = false }, time) 18 18 } 19 + 20 + 21 + function identity(a) { 22 + return a 23 + }