diff --git a/src/Applications/UI.elm b/src/Applications/UI.elm index 15879672..7c574ef9 100644 --- a/src/Applications/UI.elm +++ b/src/Applications/UI.elm @@ -21,7 +21,7 @@ import Svg.Elements import Tachyons.Classes as T import UI.Authentication import UI.Backdrop -import UI.Core exposing (Flags, Model, Msg(..), Switch(..)) +import UI.Core as Core exposing (Flags, Model, Msg(..), Switch(..)) import UI.Kit import UI.Navigation import UI.Page as Page @@ -29,6 +29,7 @@ import UI.Ports as Ports import UI.Reply as Reply exposing (Reply(..)) import UI.Settings import UI.Sources +import UI.UserData import Url exposing (Url) @@ -93,6 +94,7 @@ update msg model = LoadHypaethralUserData json -> ( { model | isAuthenticated = True, isLoading = False } + |> UI.UserData.importHypaethral json , Cmd.none ) @@ -132,6 +134,24 @@ update msg model = ----------------------------------------- -- Brain ----------------------------------------- + NotifyBrain alienEvent -> + ( model + , Ports.toBrain alienEvent + ) + + Core.SaveEnclosedUserData -> + ( model + , Cmd.none + ) + + Core.SaveHypaethralUserData -> + ( model + , model + |> UI.UserData.exportHypaethral + |> Alien.broadcast Alien.SaveHypaethralUserData + |> Ports.toBrain + ) + SignIn method -> ( model , method @@ -193,6 +213,12 @@ translateReply reply = GoToPage page -> ChangeUrlUsingPage page + Reply.SaveEnclosedUserData -> + Core.SaveEnclosedUserData + + Reply.SaveHypaethralUserData -> + Core.SaveHypaethralUserData + updateChild = Replying.updateChild update translateReply diff --git a/src/Applications/UI/Core.elm b/src/Applications/UI/Core.elm index 19ec8e5d..2233fcfe 100644 --- a/src/Applications/UI/Core.elm +++ b/src/Applications/UI/Core.elm @@ -55,6 +55,9 @@ type Msg ----------------------------------------- -- Brain ----------------------------------------- + | NotifyBrain Alien.Event + | SaveEnclosedUserData + | SaveHypaethralUserData | SignIn Authentication.Method | SignOut ----------------------------------------- diff --git a/src/Applications/UI/Reply.elm b/src/Applications/UI/Reply.elm index db4bb16a..47554f14 100644 --- a/src/Applications/UI/Reply.elm +++ b/src/Applications/UI/Reply.elm @@ -12,3 +12,5 @@ type Reply = AddSourceToCollection Source | Chill | GoToPage Page + | SaveEnclosedUserData + | SaveHypaethralUserData diff --git a/src/Applications/UI/Sources.elm b/src/Applications/UI/Sources.elm index 14a42a8b..36aaebca 100644 --- a/src/Applications/UI/Sources.elm +++ b/src/Applications/UI/Sources.elm @@ -7,6 +7,7 @@ import Material.Icons.Content as Icons import Material.Icons.Navigation as Icons import Material.Icons.Notification as Icons import Replying exposing (R3D3) +import Return2 import Return3 import Sources exposing (..) import Sources.Services as Services @@ -67,7 +68,8 @@ update msg model = |> List.singleton |> List.append model.collection |> (\c -> { model | collection = c }) - |> Return3.withNothing + |> Return2.withNoCmd + |> Return3.withReply [ UI.Reply.SaveHypaethralUserData ] ----------------------------------------- -- Children diff --git a/src/Applications/UI/UserData.elm b/src/Applications/UI/UserData.elm new file mode 100644 index 00000000..dae099ce --- /dev/null +++ b/src/Applications/UI/UserData.elm @@ -0,0 +1,90 @@ +module UI.UserData exposing (HypaethralBundle, exportHypaethral, importHypaethral) + +{-| Import user data into or export user data from the UI.Core.Model +-} + +import Authentication exposing (..) +import Json.Decode as Decode +import Json.Encode as Encode +import Sources.Encoding as Sources +import UI.Core +import UI.Sources + + + +----------------------------------------- +-- 📭 +----------------------------------------- + + +type alias HypaethralBundle = + ( HypaethralUserData, Decode.Value ) + + +importHypaethral : Decode.Value -> UI.Core.Model -> UI.Core.Model +importHypaethral value model = + let + data = + Result.withDefault emptyHypaethralUserData (decode value) + + bundle = + ( data + , Encode.null + ) + in + { model | sources = importSources model.sources bundle } + + + +-- 📭 | Importing Hypaethral + + +importSources : UI.Sources.Model -> HypaethralBundle -> UI.Sources.Model +importSources model ( data, _ ) = + { model | collection = Maybe.withDefault [] data.sources } + + + +-- 📭 | Decoding + + +decode : Decode.Value -> Result Decode.Error HypaethralUserData +decode = + Decode.decodeValue decoder + + +decoder : Decode.Decoder HypaethralUserData +decoder = + Decode.map + HypaethralUserData + (Decode.maybe <| Decode.field "sources" <| Decode.list Sources.decoder) + + + +-- 📭 | Fallbacks + + +emptyHypaethralUserData : HypaethralUserData +emptyHypaethralUserData = + { sources = Nothing } + + + +----------------------------------------- +-- 📮 +----------------------------------------- + + +exportHypaethral : UI.Core.Model -> Encode.Value +exportHypaethral = + encode + + + +-- 📮 | Encoding + + +encode : UI.Core.Model -> Encode.Value +encode model = + Encode.object + [ ( "sources", Encode.list Sources.encode model.sources.collection ) ] diff --git a/src/Library/Authentication.elm b/src/Library/Authentication.elm index ae08020c..755c3162 100644 --- a/src/Library/Authentication.elm +++ b/src/Library/Authentication.elm @@ -1,4 +1,8 @@ -module Authentication exposing (Method(..), methodFromString, methodToString) +module Authentication exposing (EnclosedUserData, HypaethralUserData, Method(..), methodFromString, methodToString) + +import Sources + + -- 🌳 @@ -7,6 +11,15 @@ type Method = Local +type alias EnclosedUserData = + {} + + +type alias HypaethralUserData = + { sources : Maybe (List Sources.Source) + } + + -- 🔱 diff --git a/src/Library/Sources/Encoding.elm b/src/Library/Sources/Encoding.elm new file mode 100644 index 00000000..a8a8bb12 --- /dev/null +++ b/src/Library/Sources/Encoding.elm @@ -0,0 +1,73 @@ +module Sources.Encoding exposing (decode, decoder, encode, encodeData, serviceDecoder) + +{-| Encoding. +-} + +import Dict +import Json.Decode as Decode +import Json.Encode as Encode +import Sources exposing (..) +import Sources.Services as Services + + + +-- ENCODE + + +encode : Source -> Encode.Value +encode source = + Encode.object + [ ( "id", Encode.string source.id ) + , ( "data", encodeData source.data ) + , ( "directoryPlaylists", Encode.bool source.directoryPlaylists ) + , ( "enabled", Encode.bool source.enabled ) + , ( "service", Encode.string (Services.typeToKey source.service) ) + ] + + +encodeData : SourceData -> Encode.Value +encodeData data = + data + |> Dict.toList + |> List.map (Tuple.mapSecond Encode.string) + |> Encode.object + + + +-- DECODE + + +decode : Decode.Value -> Maybe Source +decode value = + Decode.decodeValue decoder value + |> Result.toMaybe + + +decoder : Decode.Decoder Source +decoder = + Decode.map5 Source + (Decode.field "id" Decode.string) + (Decode.field "data" (Decode.dict Decode.string)) + (Decode.field "directoryPlaylists" Decode.bool + |> Decode.maybe + |> Decode.map (Maybe.withDefault True) + ) + (Decode.field "enabled" Decode.bool + |> Decode.maybe + |> Decode.map (Maybe.withDefault True) + ) + (Decode.field "service" serviceDecoder) + + +serviceDecoder : Decode.Decoder Service +serviceDecoder = + Decode.andThen + (\key -> + case Services.keyToType key of + Just service -> + Decode.succeed service + + Nothing -> + Decode.fail "Unrecognizable source service" + ) + Decode.string