Compare commits
14 Commits
7c7e05d42a
...
3b927dc460
Author | SHA1 | Date |
---|---|---|
|
3b927dc460 | |
|
ce0f96a74e | |
|
603057568d | |
|
2fd2eb4e5a | |
|
ee1012f783 | |
|
29f9482b74 | |
|
8b7b2aa312 | |
|
5293eb4003 | |
|
f910c0225b | |
|
848d83a18e | |
|
1b0be9bffa | |
|
70d44c2cb6 | |
|
31d176d110 | |
|
037e598b36 |
|
@ -2,3 +2,5 @@
|
||||||
elm-stuff
|
elm-stuff
|
||||||
# elm-repl generated files
|
# elm-repl generated files
|
||||||
repl-temp-*
|
repl-temp-*
|
||||||
|
# VScode settings
|
||||||
|
.vscode/
|
||||||
|
|
|
@ -32,3 +32,8 @@ elm install noordstar/elm-matrix-sdk-beta
|
||||||
Keep in mind that the beta versions are intended to develop rapidly. You should
|
Keep in mind that the beta versions are intended to develop rapidly. You should
|
||||||
not expect the versions to remain reliable for years! If you need a stable
|
not expect the versions to remain reliable for years! If you need a stable
|
||||||
version, please wait around for a full version.
|
version, please wait around for a full version.
|
||||||
|
|
||||||
|
## Contribute
|
||||||
|
|
||||||
|
If you wish to contribute, please read the
|
||||||
|
[contribution guide](docs/CONTRIBUTING.md).
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
# Contributing to elm-matrix-sdk-beta
|
||||||
|
|
||||||
|
Welcome to the elm-matrix-sdk-beta repository! We appreciate your interest in
|
||||||
|
contributing. Please take a moment to review the following guidelines.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [How to Contribute](#how-to-contribute)
|
||||||
|
2. [Bug Reports](#bug-reports)
|
||||||
|
3. [Code Contributions](#code-contributions)
|
||||||
|
4. [Documentation Improvements](#documentation-improvements)
|
||||||
|
5. [Feedback and Tips](#feedback-and-tips)
|
||||||
|
6. [Development Environment](#development-environment)
|
||||||
|
7. [Pull Requests](#pull-requests)
|
||||||
|
8. [Communication](#communication)
|
||||||
|
9. [License](#license)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Contribute
|
||||||
|
|
||||||
|
We welcome various forms of contributions, including bug reports, code
|
||||||
|
contributions through pull requests from forks, suggestions for documentation
|
||||||
|
improvement, and helpful tips and feedback based on user experience.
|
||||||
|
|
||||||
|
## Bug Reports
|
||||||
|
|
||||||
|
When reporting bugs, please provide as much detail as possible, including steps
|
||||||
|
to reproduce, expected behavior, actual behavior, and details about your
|
||||||
|
environment.
|
||||||
|
|
||||||
|
## Code Contributions
|
||||||
|
|
||||||
|
1. Fork the repository.
|
||||||
|
2. Create a new branch from the `develop` branch.
|
||||||
|
3. Write your code and commit changes.
|
||||||
|
4. Push your branch to your fork.
|
||||||
|
5. Submit a pull request to the `develop` branch.
|
||||||
|
|
||||||
|
## Documentation Improvements
|
||||||
|
|
||||||
|
Feel free to suggest improvements to the documentation. Ensure that your
|
||||||
|
suggestions are clear and concise.
|
||||||
|
|
||||||
|
## Feedback and Tips
|
||||||
|
|
||||||
|
We appreciate feedback, tips, and suggestions based on user experience. Share
|
||||||
|
your thoughts to help us enhance the project.
|
||||||
|
|
||||||
|
## Development Environment
|
||||||
|
|
||||||
|
To set up your development environment:
|
||||||
|
|
||||||
|
1. Install Elm.
|
||||||
|
2. Use `elm-format` to format your Elm code.
|
||||||
|
3. Run `elm make --docs=docs.json` to generate documentation.
|
||||||
|
4. View documentation using an Elm documentation viewer (e.g., [elm-doc-preview](https://elm-doc-preview.netlify.app/)).
|
||||||
|
5. Expose modules in `elm.json` for documentation.
|
||||||
|
|
||||||
|
## Pull Requests
|
||||||
|
|
||||||
|
Create a fork, write your code, and submit a pull request to the `develop` branch.
|
||||||
|
|
||||||
|
## Communication
|
||||||
|
|
||||||
|
- Mastodon: [@elm_matrix_sdk@social.noordstar.me](https://social.noordstar.me/@elm_matrix_sdk)
|
||||||
|
- Matrix: [#elm-sdk:matrix.org](https://matrix.to/#/#elm-sdk:matrix.org)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the [EUPL-v1.2](LICENSE). Please review the license file for more details.
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Before merging to main
|
||||||
|
|
||||||
|
⚠️ **Hold up!** Before you merge that pull request, make sure to follow this checklist!
|
||||||
|
|
||||||
|
## Any branch to `develop`
|
||||||
|
|
||||||
|
If you wish to merge your branch to the `develop` branch, make sure to follow this checklist:
|
||||||
|
|
||||||
|
- [ ] Run `elm-format` to ensure the correct formatting of the Elm files.
|
||||||
|
- [ ] Use `elm-doc-preview` to verify whether the documentation is up to standards.
|
||||||
|
|
||||||
|
## The `develop` branch to `main`
|
||||||
|
|
||||||
|
The `develop` branch is the only branch that's allowed to merge to `main`. Once the branch merges to `main`, that indicates a new release on the Elm registry.
|
||||||
|
|
||||||
|
Before that is being done, however, the following tasks should be done:
|
||||||
|
|
||||||
|
- [ ] Run `elm-format` to ensure the correct formatting of the Elm files.
|
||||||
|
- [ ] Use `elm-doc-preview` to verify whether the documentation is up to standards.
|
||||||
|
- [ ] Remove exposed modules from `elm.json` that do not need to be exposed modules in the release.
|
||||||
|
- [ ] Run `elm bump` to update the library's version number
|
||||||
|
- [ ] Update the version name in the [default values config file](../src/Internal/Config/Default.elm).
|
||||||
|
|
||||||
|
## Any branch to any other branch
|
||||||
|
|
||||||
|
There are no limitations to merging other branches towards one another, although it is important to keep in mind that:
|
||||||
|
|
||||||
|
- Contributors are advised to merge the `develop` branch into their branches regularly to avoid any merge conflicts.
|
||||||
|
- Merging with branches that haven't been accepted (yet) might result in your branch ending up with code that will not be accepted.
|
8
elm.json
8
elm.json
|
@ -6,12 +6,18 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"exposed-modules": [
|
"exposed-modules": [
|
||||||
"Matrix",
|
"Matrix",
|
||||||
|
"Matrix.Settings",
|
||||||
"Internal.Config.Default",
|
"Internal.Config.Default",
|
||||||
"Internal.Config.Text",
|
"Internal.Config.Text",
|
||||||
|
"Internal.Tools.Decode",
|
||||||
|
"Internal.Tools.Encode",
|
||||||
"Internal.Tools.Hashdict",
|
"Internal.Tools.Hashdict",
|
||||||
"Internal.Tools.Iddict",
|
"Internal.Tools.Iddict",
|
||||||
"Internal.Tools.Timestamp",
|
"Internal.Tools.Timestamp",
|
||||||
"Internal.Tools.VersionControl"
|
"Internal.Tools.VersionControl",
|
||||||
|
"Internal.Values.Envelope",
|
||||||
|
"Internal.Values.Vault",
|
||||||
|
"Types"
|
||||||
],
|
],
|
||||||
"elm-version": "0.19.0 <= v < 0.20.0",
|
"elm-version": "0.19.0 <= v < 0.20.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -42,7 +42,7 @@ the Elm SDK tolerates being held on hold.
|
||||||
|
|
||||||
- ↗️ A high value is good because it significantly reduces traffic between the
|
- ↗️ A high value is good because it significantly reduces traffic between the
|
||||||
user and the homeserver.
|
user and the homeserver.
|
||||||
- ↘️ A low value is good because it refuces the risk of
|
- ↘️ A low value is good because it reduces the risk of
|
||||||
the connection ending abruptly or unexpectedly.
|
the connection ending abruptly or unexpectedly.
|
||||||
|
|
||||||
Nowadays, most libraries use 30 seconds as the standard, as does the Elm SDK.
|
Nowadays, most libraries use 30 seconds as the standard, as does the Elm SDK.
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
module Internal.Tools.Decode exposing
|
||||||
|
( opField, opFieldWithDefault
|
||||||
|
, map9, map10, map11
|
||||||
|
)
|
||||||
|
|
||||||
|
{-|
|
||||||
|
|
||||||
|
|
||||||
|
# Decode module
|
||||||
|
|
||||||
|
This module contains helper functions that help decode JSON.
|
||||||
|
|
||||||
|
|
||||||
|
## Optional field decoders
|
||||||
|
|
||||||
|
@docs opField, opFieldWithDefault
|
||||||
|
|
||||||
|
|
||||||
|
## Extended map functions
|
||||||
|
|
||||||
|
@docs map9, map10, map11
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Json.Decode as D
|
||||||
|
|
||||||
|
|
||||||
|
{-| Add an optional field decoder. If the field exists, the decoder will fail
|
||||||
|
if the field doesn't decode properly.
|
||||||
|
|
||||||
|
This decoder standard out from `D.maybe <| D.field fieldName decoder` because
|
||||||
|
that will decode into a `Nothing` if the `decoder` fails. This function will
|
||||||
|
only decode into a `Nothing` if the field doesn't exist, and will fail if
|
||||||
|
`decoder` fails.
|
||||||
|
|
||||||
|
The function also returns Nothing if the field exists but it is null.
|
||||||
|
|
||||||
|
-}
|
||||||
|
opField : String -> D.Decoder a -> D.Decoder (Maybe a)
|
||||||
|
opField fieldName decoder =
|
||||||
|
D.value
|
||||||
|
|> D.field fieldName
|
||||||
|
|> D.maybe
|
||||||
|
|> D.andThen
|
||||||
|
(\v ->
|
||||||
|
case v of
|
||||||
|
Just _ ->
|
||||||
|
D.oneOf
|
||||||
|
[ D.null Nothing
|
||||||
|
, D.map Just decoder
|
||||||
|
]
|
||||||
|
|> D.field fieldName
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
D.succeed Nothing
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Add an optional field decoder. If the field is not given, the decoder will
|
||||||
|
return a default value. If the field exists, the decoder will fail if the field
|
||||||
|
doesn't decode properly.
|
||||||
|
-}
|
||||||
|
opFieldWithDefault : String -> a -> D.Decoder a -> D.Decoder a
|
||||||
|
opFieldWithDefault fieldName default decoder =
|
||||||
|
opField fieldName decoder |> D.map (Maybe.withDefault default)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Try 9 decoders and combine the result.
|
||||||
|
-}
|
||||||
|
map9 :
|
||||||
|
(a -> b -> c -> d -> e -> f -> g -> h -> i -> value)
|
||||||
|
-> D.Decoder a
|
||||||
|
-> D.Decoder b
|
||||||
|
-> D.Decoder c
|
||||||
|
-> D.Decoder d
|
||||||
|
-> D.Decoder e
|
||||||
|
-> D.Decoder f
|
||||||
|
-> D.Decoder g
|
||||||
|
-> D.Decoder h
|
||||||
|
-> D.Decoder i
|
||||||
|
-> D.Decoder value
|
||||||
|
map9 func da db dc dd de df dg dh di =
|
||||||
|
D.map8
|
||||||
|
(\a b c d e f g ( h, i ) ->
|
||||||
|
func a b c d e f g h i
|
||||||
|
)
|
||||||
|
da
|
||||||
|
db
|
||||||
|
dc
|
||||||
|
dd
|
||||||
|
de
|
||||||
|
df
|
||||||
|
dg
|
||||||
|
(D.map2 Tuple.pair dh di)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Try 10 decoders and combine the result.
|
||||||
|
-}
|
||||||
|
map10 :
|
||||||
|
(a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> value)
|
||||||
|
-> D.Decoder a
|
||||||
|
-> D.Decoder b
|
||||||
|
-> D.Decoder c
|
||||||
|
-> D.Decoder d
|
||||||
|
-> D.Decoder e
|
||||||
|
-> D.Decoder f
|
||||||
|
-> D.Decoder g
|
||||||
|
-> D.Decoder h
|
||||||
|
-> D.Decoder i
|
||||||
|
-> D.Decoder j
|
||||||
|
-> D.Decoder value
|
||||||
|
map10 func da db dc dd de df dg dh di dj =
|
||||||
|
D.map8
|
||||||
|
(\a b c d e f ( g, h ) ( i, j ) ->
|
||||||
|
func a b c d e f g h i j
|
||||||
|
)
|
||||||
|
da
|
||||||
|
db
|
||||||
|
dc
|
||||||
|
dd
|
||||||
|
de
|
||||||
|
df
|
||||||
|
(D.map2 Tuple.pair dg dh)
|
||||||
|
(D.map2 Tuple.pair di dj)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Try 11 decoders and combine the result.
|
||||||
|
-}
|
||||||
|
map11 :
|
||||||
|
(a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> value)
|
||||||
|
-> D.Decoder a
|
||||||
|
-> D.Decoder b
|
||||||
|
-> D.Decoder c
|
||||||
|
-> D.Decoder d
|
||||||
|
-> D.Decoder e
|
||||||
|
-> D.Decoder f
|
||||||
|
-> D.Decoder g
|
||||||
|
-> D.Decoder h
|
||||||
|
-> D.Decoder i
|
||||||
|
-> D.Decoder j
|
||||||
|
-> D.Decoder k
|
||||||
|
-> D.Decoder value
|
||||||
|
map11 func da db dc dd de df dg dh di dj dk =
|
||||||
|
D.map8
|
||||||
|
(\a b c d e ( f, g ) ( h, i ) ( j, k ) ->
|
||||||
|
func a b c d e f g h i j k
|
||||||
|
)
|
||||||
|
da
|
||||||
|
db
|
||||||
|
dc
|
||||||
|
dd
|
||||||
|
de
|
||||||
|
(D.map2 Tuple.pair df dg)
|
||||||
|
(D.map2 Tuple.pair dh di)
|
||||||
|
(D.map2 Tuple.pair dj dk)
|
|
@ -0,0 +1,52 @@
|
||||||
|
module Internal.Tools.Encode exposing (maybeObject)
|
||||||
|
|
||||||
|
{-|
|
||||||
|
|
||||||
|
|
||||||
|
# Encode module
|
||||||
|
|
||||||
|
This module contains helper functions that help decode JSON.
|
||||||
|
|
||||||
|
|
||||||
|
# Optional body object
|
||||||
|
|
||||||
|
@docs maybeObject
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Json.Encode as E
|
||||||
|
|
||||||
|
|
||||||
|
{-| Create a body object based on optionally provided values.
|
||||||
|
|
||||||
|
In other words, the following two variables create the same JSON value:
|
||||||
|
|
||||||
|
value1 : Json.Encode.Value
|
||||||
|
value1 =
|
||||||
|
maybeObject
|
||||||
|
[ ( "name", Just (Json.Encode.string "Alice") )
|
||||||
|
, ( "age", Nothing )
|
||||||
|
, ( "height", Just (Json.Encode.float 1.61) )
|
||||||
|
, ( "weight", Nothing )
|
||||||
|
]
|
||||||
|
|
||||||
|
value2 : Json.Encode.Value
|
||||||
|
value2 =
|
||||||
|
Json.Encode.object
|
||||||
|
[ ( "name", Json.Encode.string "Alice" )
|
||||||
|
, ( "height", Json.Encode.float 1.61 )
|
||||||
|
]
|
||||||
|
|
||||||
|
-}
|
||||||
|
maybeObject : List ( String, Maybe E.Value ) -> E.Value
|
||||||
|
maybeObject =
|
||||||
|
List.filterMap
|
||||||
|
(\( name, value ) ->
|
||||||
|
case value of
|
||||||
|
Just v ->
|
||||||
|
Just ( name, v )
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
Nothing
|
||||||
|
)
|
||||||
|
>> E.object
|
|
@ -0,0 +1,250 @@
|
||||||
|
module Internal.Values.Envelope exposing
|
||||||
|
( Envelope, init
|
||||||
|
, map, mapMaybe
|
||||||
|
, Settings, mapSettings, extractSettings
|
||||||
|
, getContent, extract
|
||||||
|
, encode, decoder
|
||||||
|
)
|
||||||
|
|
||||||
|
{-| The Envelope module wraps existing data types with lots of values and
|
||||||
|
settings that can be adjusted manually.
|
||||||
|
|
||||||
|
|
||||||
|
## Create
|
||||||
|
|
||||||
|
@docs Envelope, init
|
||||||
|
|
||||||
|
|
||||||
|
## Manipulate
|
||||||
|
|
||||||
|
@docs map, mapMaybe
|
||||||
|
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
@docs Settings, mapSettings, extractSettings
|
||||||
|
|
||||||
|
|
||||||
|
## Extract
|
||||||
|
|
||||||
|
@docs getContent, extract
|
||||||
|
|
||||||
|
|
||||||
|
## JSON coders
|
||||||
|
|
||||||
|
@docs encode, decoder
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Internal.Config.Default as Default
|
||||||
|
import Internal.Tools.Decode as D
|
||||||
|
import Internal.Tools.Encode as E
|
||||||
|
import Json.Decode as D
|
||||||
|
import Json.Encode as E
|
||||||
|
|
||||||
|
|
||||||
|
{-| There are lots of different data types in the Elm SDK, and many of them
|
||||||
|
need the same values. The Envelope type wraps settings, tokens and values around
|
||||||
|
each data type so they can all enjoy those values without needing to explicitly
|
||||||
|
define them in their type.
|
||||||
|
-}
|
||||||
|
type Envelope a
|
||||||
|
= Envelope
|
||||||
|
{ content : a
|
||||||
|
, settings : Settings
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Custom settings that can be manipulated by the user. These serve as a
|
||||||
|
configuration for how the Elm SDK should behave.
|
||||||
|
|
||||||
|
Custom settings are always part of the Envelope, allowing all functions to
|
||||||
|
behave under the user's preferred settings.
|
||||||
|
|
||||||
|
-}
|
||||||
|
type alias Settings =
|
||||||
|
{ currentVersion : String
|
||||||
|
, deviceName : String
|
||||||
|
, syncTime : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Decode an enveloped type from a JSON value. The decoder also imports any
|
||||||
|
potential tokens, values and settings included in the JSON.
|
||||||
|
-}
|
||||||
|
decoder : D.Decoder a -> D.Decoder (Envelope a)
|
||||||
|
decoder xDecoder =
|
||||||
|
D.map2 (\a b -> Envelope { content = a, settings = b })
|
||||||
|
(D.field "content" xDecoder)
|
||||||
|
(D.field "settings" decoderSettings)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Decode settings from a JSON value.
|
||||||
|
-}
|
||||||
|
decoderSettings : D.Decoder Settings
|
||||||
|
decoderSettings =
|
||||||
|
D.map3 Settings
|
||||||
|
(D.opFieldWithDefault "currentVersion" Default.currentVersion D.string)
|
||||||
|
(D.opFieldWithDefault "deviceName" Default.deviceName D.string)
|
||||||
|
(D.opFieldWithDefault "syncTime" Default.syncTime D.int)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Encode an enveloped type into a JSON value. The function encodes all
|
||||||
|
non-standard settings, tokens and values.
|
||||||
|
-}
|
||||||
|
encode : (a -> E.Value) -> Envelope a -> E.Value
|
||||||
|
encode encodeX (Envelope data) =
|
||||||
|
E.object
|
||||||
|
[ ( "content", encodeX data.content )
|
||||||
|
, ( "settings", encodeSettings data.settings )
|
||||||
|
, ( "version", E.string Default.currentVersion )
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Encode the settings into a JSON value.
|
||||||
|
-}
|
||||||
|
encodeSettings : Settings -> E.Value
|
||||||
|
encodeSettings settings =
|
||||||
|
let
|
||||||
|
differentFrom : b -> b -> Maybe b
|
||||||
|
differentFrom defaultValue currentValue =
|
||||||
|
if currentValue == defaultValue then
|
||||||
|
Nothing
|
||||||
|
|
||||||
|
else
|
||||||
|
Just currentValue
|
||||||
|
in
|
||||||
|
E.maybeObject
|
||||||
|
[ ( "currentVersion"
|
||||||
|
, settings.currentVersion
|
||||||
|
|> differentFrom Default.currentVersion
|
||||||
|
|> Maybe.map E.string
|
||||||
|
)
|
||||||
|
, ( "deviceName"
|
||||||
|
, settings.deviceName
|
||||||
|
|> differentFrom Default.deviceName
|
||||||
|
|> Maybe.map E.string
|
||||||
|
)
|
||||||
|
, ( "syncTime"
|
||||||
|
, settings.syncTime
|
||||||
|
|> differentFrom Default.syncTime
|
||||||
|
|> Maybe.map E.int
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Map a function, then get its content. This is useful for getting information
|
||||||
|
from a data type inside an Envelope.
|
||||||
|
|
||||||
|
type alias User =
|
||||||
|
{ name : String, age : Int }
|
||||||
|
|
||||||
|
getName : Envelope User -> String
|
||||||
|
getName =
|
||||||
|
Envelope.extract .name
|
||||||
|
|
||||||
|
-}
|
||||||
|
extract : (a -> b) -> Envelope a -> b
|
||||||
|
extract f (Envelope data) =
|
||||||
|
f data.content
|
||||||
|
|
||||||
|
|
||||||
|
{-| Map a function on the settings, effectively getting data that way.
|
||||||
|
|
||||||
|
This can be helpful if you have a UI that displays custom settings to a user.
|
||||||
|
|
||||||
|
-}
|
||||||
|
extractSettings : (Settings -> b) -> Envelope a -> b
|
||||||
|
extractSettings f (Envelope data) =
|
||||||
|
f data.settings
|
||||||
|
|
||||||
|
|
||||||
|
{-| Get the original item that is stored inside an Envelope.
|
||||||
|
|
||||||
|
Make sure that you're only using this if you're interested in the actual value!
|
||||||
|
If you'd like to get the content, run a function on it, and put it back in an
|
||||||
|
Envelope, consider using [map](#map) instead.
|
||||||
|
|
||||||
|
-}
|
||||||
|
getContent : Envelope a -> a
|
||||||
|
getContent =
|
||||||
|
extract identity
|
||||||
|
|
||||||
|
|
||||||
|
{-| Create a new enveloped data type. All settings are set to default values
|
||||||
|
from the [Internal.Config.Default](Internal-Config-Default) module.
|
||||||
|
-}
|
||||||
|
init : a -> Envelope a
|
||||||
|
init x =
|
||||||
|
Envelope
|
||||||
|
{ content = x
|
||||||
|
, settings =
|
||||||
|
{ currentVersion = Default.currentVersion
|
||||||
|
, deviceName = Default.deviceName
|
||||||
|
, syncTime = Default.syncTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Map a function on the content of the Envelope.
|
||||||
|
|
||||||
|
type alias User =
|
||||||
|
{ name : String, age : Int }
|
||||||
|
|
||||||
|
getName : Envelope User -> Envelope String
|
||||||
|
getName =
|
||||||
|
Envelope.map .name
|
||||||
|
|
||||||
|
-}
|
||||||
|
map : (a -> b) -> Envelope a -> Envelope b
|
||||||
|
map f (Envelope data) =
|
||||||
|
Envelope
|
||||||
|
{ content = f data.content
|
||||||
|
, settings = data.settings
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Update the settings in the Envelope.
|
||||||
|
|
||||||
|
setDeviceName : String -> Envelope a -> Envelope a
|
||||||
|
setDeviceName name envelope =
|
||||||
|
mapSettings
|
||||||
|
(\settings ->
|
||||||
|
{ settings | deviceName = name }
|
||||||
|
)
|
||||||
|
envelope
|
||||||
|
|
||||||
|
-}
|
||||||
|
mapSettings : (Settings -> Settings) -> Envelope a -> Envelope a
|
||||||
|
mapSettings f (Envelope data) =
|
||||||
|
Envelope
|
||||||
|
{ content = data.content
|
||||||
|
, settings = f data.settings
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Map the contents of a function, where the result is wrapped in a `Maybe`
|
||||||
|
type. This can be useful when you are not guaranteed to find the value you're
|
||||||
|
looking for.
|
||||||
|
|
||||||
|
type alias User =
|
||||||
|
{ name : String, age : Int }
|
||||||
|
|
||||||
|
type alias UserDatabase =
|
||||||
|
List User
|
||||||
|
|
||||||
|
getFirstUser : Envelope UserDatabase -> Maybe (Envelope User)
|
||||||
|
getFirstUser envelope =
|
||||||
|
mapMaybe List.head envelope
|
||||||
|
|
||||||
|
-}
|
||||||
|
mapMaybe : (a -> Maybe b) -> Envelope a -> Maybe (Envelope b)
|
||||||
|
mapMaybe f =
|
||||||
|
map f >> toMaybe
|
||||||
|
|
||||||
|
|
||||||
|
toMaybe : Envelope (Maybe a) -> Maybe (Envelope a)
|
||||||
|
toMaybe (Envelope data) =
|
||||||
|
Maybe.map
|
||||||
|
(\content -> map (always content) (Envelope data))
|
||||||
|
data.content
|
|
@ -0,0 +1,15 @@
|
||||||
|
module Internal.Values.Vault exposing (Vault)
|
||||||
|
|
||||||
|
{-| This module hosts the Vault module.
|
||||||
|
|
||||||
|
@docs Vault
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Internal.Values.Envelope as Envelope
|
||||||
|
|
||||||
|
|
||||||
|
{-| This is the Vault type.
|
||||||
|
-}
|
||||||
|
type alias Vault =
|
||||||
|
Envelope.Envelope {}
|
|
@ -1,5 +1,9 @@
|
||||||
module Matrix exposing (Vault)
|
module Matrix exposing (Vault)
|
||||||
{-| # Matrix SDK
|
|
||||||
|
{-|
|
||||||
|
|
||||||
|
|
||||||
|
# Matrix SDK
|
||||||
|
|
||||||
This first version forms a mere basis from which we will create iterative builds
|
This first version forms a mere basis from which we will create iterative builds
|
||||||
that slowly improve the codebase.
|
that slowly improve the codebase.
|
||||||
|
@ -8,13 +12,20 @@ It is generally quite unusual to regularly publish iterative beta versions on
|
||||||
the public registry, but it is also generally quite unusual to exclusively
|
the public registry, but it is also generally quite unusual to exclusively
|
||||||
support a monolithic public registry. (:
|
support a monolithic public registry. (:
|
||||||
|
|
||||||
|
|
||||||
## Vault
|
## Vault
|
||||||
|
|
||||||
@docs Vault
|
@docs Vault
|
||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
|
import Types
|
||||||
|
|
||||||
|
|
||||||
{-| The Vault type stores all relevant information about the Matrix API.
|
{-| The Vault type stores all relevant information about the Matrix API.
|
||||||
|
|
||||||
It currently supports no functionality and it will just stay here - for fun.
|
It currently supports no functionality and it will just stay here - for fun.
|
||||||
|
|
||||||
-}
|
-}
|
||||||
type Vault = Vault
|
type alias Vault =
|
||||||
|
Types.Vault
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
module Matrix.Settings exposing
|
||||||
|
( getDeviceName, setDeviceName
|
||||||
|
, getSyncTime, setSyncTime
|
||||||
|
)
|
||||||
|
|
||||||
|
{-| The Matrix Vault has lots of configurable variables that you rarely want to
|
||||||
|
interact with. Usually, you configure these variables only when creating a new
|
||||||
|
Vault, or when a user explicitly changes one of their preferred settings.
|
||||||
|
|
||||||
|
|
||||||
|
## Device name
|
||||||
|
|
||||||
|
The default device name that is being communicated with the Matrix API.
|
||||||
|
|
||||||
|
This is mostly useful for users who are logged in with multiple sessions. They
|
||||||
|
will see device names like "Element for Android" or "Element on iOS". For the
|
||||||
|
Elm SDK, they will by default see the Elm SDK with its version included. If you
|
||||||
|
are writing a custom client, however, you are free to change this to something
|
||||||
|
more meaningful to the user.
|
||||||
|
|
||||||
|
@docs getDeviceName, setDeviceName
|
||||||
|
|
||||||
|
|
||||||
|
## Sync time
|
||||||
|
|
||||||
|
Whenever the Matrix API has nothing new to report, the Elm SDK is kept on
|
||||||
|
hold until something new happens. The `syncTime` indicates a timeout to how long
|
||||||
|
the Elm SDK tolerates being held on hold.
|
||||||
|
|
||||||
|
- ↗️ A high value is good because it significantly reduces traffic between the
|
||||||
|
user and the homeserver.
|
||||||
|
- ↘️ A low value is good because it reduces the risk of
|
||||||
|
the connection ending abruptly or unexpectedly.
|
||||||
|
|
||||||
|
Nowadays, most libraries use 30 seconds as the standard, as does the Elm SDK.
|
||||||
|
The value is in miliseconds, so it is set at 30,000.
|
||||||
|
|
||||||
|
@docs getSyncTime, setSyncTime
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Internal.Values.Envelope as Envelope
|
||||||
|
import Types exposing (Vault(..))
|
||||||
|
|
||||||
|
|
||||||
|
{-| Determine the device name.
|
||||||
|
-}
|
||||||
|
getDeviceName : Vault -> String
|
||||||
|
getDeviceName (Vault vault) =
|
||||||
|
Envelope.extractSettings .deviceName vault
|
||||||
|
|
||||||
|
|
||||||
|
{-| Override the device name.
|
||||||
|
-}
|
||||||
|
setDeviceName : String -> Vault -> Vault
|
||||||
|
setDeviceName name (Vault vault) =
|
||||||
|
Vault <| Envelope.mapSettings (\s -> { s | deviceName = name }) vault
|
||||||
|
|
||||||
|
|
||||||
|
{-| Determine the sync timeout value.
|
||||||
|
-}
|
||||||
|
getSyncTime : Vault -> Int
|
||||||
|
getSyncTime (Vault vault) =
|
||||||
|
Envelope.extractSettings .syncTime vault
|
||||||
|
|
||||||
|
|
||||||
|
{-| Override the sync timeout value.
|
||||||
|
-}
|
||||||
|
setSyncTime : Int -> Vault -> Vault
|
||||||
|
setSyncTime time (Vault vault) =
|
||||||
|
Vault <| Envelope.mapSettings (\s -> { s | syncTime = time }) vault
|
|
@ -0,0 +1,25 @@
|
||||||
|
module Types exposing (Vault(..))
|
||||||
|
|
||||||
|
{-| The Elm SDK uses a lot of records and values that are easy to manipulate.
|
||||||
|
Yet, the [Elm design guidelines](https://package.elm-lang.org/help/design-guidelines#keep-tags-and-record-constructors-secret)
|
||||||
|
highly recommend using opaque types in order to avoid breaking everyone's code
|
||||||
|
in a future major release.
|
||||||
|
|
||||||
|
This module forms as a protective layer between the internal modules and the
|
||||||
|
exposed modules, hiding all exposed types behind opaque types so the user cannot
|
||||||
|
access their content directly.
|
||||||
|
|
||||||
|
The opaque types are placed in a central module so all exposed modules can
|
||||||
|
safely access all exposed data types without risking to create circular imports.
|
||||||
|
|
||||||
|
@docs Vault
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Internal.Values.Vault as Vault
|
||||||
|
|
||||||
|
|
||||||
|
{-| Opaque type for Matrix Vault
|
||||||
|
-}
|
||||||
|
type Vault
|
||||||
|
= Vault Vault.Vault
|
Loading…
Reference in New Issue