Refactor spike

This commit makes it easier to transfer information across screens
main
Bram 2024-11-03 20:58:15 +01:00
parent 3b370138aa
commit 85790d4e7b
11 changed files with 488 additions and 554 deletions

View File

@ -14,6 +14,7 @@
"icidasset/elm-material-icons": "11.0.0",
"kudzu-forest/elm-constant-time-queue": "1.4.0",
"mdgriffith/elm-ui": "1.1.8",
"micahhahn/elm-safe-recursion": "2.0.0",
"noordstar/elm-iddict": "1.0.1",
"noordstar/elm-matrix-sdk-beta": "3.6.0",
"noordstar/elm-palette": "1.0.0"
@ -31,7 +32,6 @@
"elm/virtual-dom": "1.0.3",
"elm-community/intdict": "3.1.0",
"fredcy/elm-parseint": "2.0.1",
"micahhahn/elm-safe-recursion": "2.0.0",
"miniBill/elm-fast-dict": "1.2.1",
"noahzgordon/elm-color-extra": "1.0.2",
"turboMaCk/queue": "1.1.0"

95
src/Items/ItemPicker.elm Normal file
View File

@ -0,0 +1,95 @@
module Items.ItemPicker exposing (..)
import Iddict exposing (Iddict)
import Element exposing (Element)
import Layout
import Material.Icons
import Color exposing (Color)
-- MODEL
type alias Model a =
{ hover : Maybe Int
, items : Iddict a
}
type Msg = OnHover Int | OnHoverOut Int
init : Iddict a -> Model a
init iddict =
{ hover = Nothing, items = iddict }
-- UPDATE
update : Msg -> Model a -> Model a
update msg model =
case msg of
OnHover i ->
{ model | hover = Just i }
OnHoverOut i ->
if model.hover == Just i then
{ model | hover = Nothing }
else
model
updateContent : (Iddict a -> Iddict a) -> Model a -> Model a
updateContent f model =
{ model | items = f model.items }
-- VIEW
{-| Extract the original data set out of the item picker.
-}
extract : Model a -> Iddict a
extract = .items
{-| Display the item picker. Note that the item should not be wider than 360px.
-}
view :
{ colorMenu : Color
, colorText : Color
, height : Int
, model : Model a
, toText : Int -> a -> String
, toTitle : Int -> a -> String
, onAddNew : Maybe msg
, onClick : Int -> msg
, width : Int
} -> Element msg
view data =
Layout.sideList
{ color = data.colorMenu
, items =
data.model.items
|> Iddict.toList
|> List.map
(\( iid, item ) ->
Layout.itemWithSubtext
{ color = data.colorText
, leftIcon = always Element.none
, onPress = Just (data.onClick iid)
, rightIcon = Layout.iconAsIcon Material.Icons.launch
, text = data.toText iid item
, title = data.toTitle iid item
}
)
|> (\items ->
case data.onAddNew of
Nothing ->
items
Just onAddNew ->
List.append items
[ Layout.itemWithSubtext
{ color = data.colorText
, leftIcon = Layout.iconAsIcon Material.Icons.add_circle
, onPress = Just onAddNew
, rightIcon = always Element.none
, text = "Click here"
, title = "Add new"
}
]
)
, width = data.width
}

View File

@ -1,4 +1,4 @@
module Items.LoginScreen exposing (..)
module Items.LoginView exposing (..)
{-| The Login screen allows the user to log in, as well as view a short display
of what to expect from the Matrix client.
-}

63
src/Items/VaultList.elm Normal file
View File

@ -0,0 +1,63 @@
module Items.VaultList exposing (..)
{-| # Vault list
The vault list contains a list of stored vaults that can be picked from.
-}
import Iddict exposing (Iddict)
import Matrix
-- MODEL
type alias Model = Iddict VaultBlock
type Msg
= AddVault { name : String, vault : Matrix.Vault }
| OnVaultUpdate Int Matrix.VaultUpdate
type alias VaultBlock =
{ logs : List { channel : String, content : String }
, name : String
, vault : Matrix.Vault
}
init : Model
init = Iddict.empty
-- UPDATE
addVault : { name : String, vault : Matrix.Vault } -> Model -> Model
addVault =
AddVault >> update
insertVaultUpdate : Int -> Matrix.VaultUpdate -> Model -> Model
insertVaultUpdate i vu =
update (OnVaultUpdate i vu)
update : Msg -> Model -> Model
update msg model =
case msg of
AddVault { name, vault } ->
Iddict.insert { name = name, logs = [], vault = vault } model
|> Tuple.second
OnVaultUpdate i vu ->
Iddict.update i
(Maybe.map
(\block ->
{ block
| logs =
List.append (Matrix.logs vu) block.logs
|> List.take 500
, vault = Matrix.update vu block.vault
}
)
)
model
-- VIEW
getVault : Int -> Model -> Maybe Matrix.Vault
getVault i model =
Iddict.get i model |> Maybe.map .vault

View File

@ -1,112 +0,0 @@
module Items.VaultPicker exposing (..)
import Color exposing (Color)
import Element exposing (Element)
import Iddict exposing (Iddict)
import Material.Icons
import Matrix
import Layout
-- MODEL
type alias Model =
{ hover : Maybe Int, vaults : Iddict NamedVault }
type alias NamedVault = { name : String, vault : Matrix.Vault }
type Msg
= AddVault String Matrix.Vault
| OnHover Int
| OnHoverOut Int
| OnRemoveVault Int
init : List NamedVault -> Model
init items =
{ hover = Nothing
, vaults =
items
|> List.indexedMap Tuple.pair
|> Iddict.fromList
}
-- UPDATE
addVault : NamedVault -> Model -> Model
addVault data =
AddVault data.name data.vault |> update
update : Msg -> Model -> Model
update msg model =
case msg of
AddVault name vault ->
{ model
| vaults =
model.vaults
|> Iddict.insert { name = name, vault = vault }
|> Tuple.second
}
OnHover i ->
{ model | hover = Just i }
OnHoverOut i ->
case model.hover of
Just h ->
if i == h then
{ model | hover = Nothing }
else
model
Nothing ->
model
OnRemoveVault i ->
{ model | vaults = Iddict.remove i model.vaults }
-- VIEW
getVault : Int -> Model -> Maybe Matrix.Vault
getVault i model =
Iddict.get i model.vaults |> Maybe.map .vault
view :
{ colorItem : Color
, colorList : Color
, model : Model
, onAddVault : msg
, onSelectVault : Int -> msg
, width : Int
} -> Element msg
view data =
Layout.sideList
{ color = data.colorList
, items =
data.model.vaults
|> Iddict.toList
|> List.map
(\(vid, { name, vault }) ->
Layout.itemWithSubtext
{ color = data.colorItem
, leftIcon = always Element.none
, onPress = Just (data.onSelectVault vid)
, rightIcon = Layout.iconAsIcon Material.Icons.launch
, text = name
, title = "Vault #" ++ String.fromInt vid
}
)
|> (\items ->
[ Layout.itemWithSubtext
{ color = data.colorItem
, leftIcon = Layout.iconAsIcon Material.Icons.add_circle
, onPress = Just data.onAddVault
, rightIcon = always Element.none
, text = "Click here"
, title = "Add new"
}
]
|> List.append items
)
}
|> Element.el
[ Element.width (Element.px data.width) ]

View File

@ -1,170 +0,0 @@
module Items.VaultScreen exposing (..)
import Color exposing (Color)
import Element exposing (Element)
import Layout
import Matrix
import Matrix.Room
import Queue exposing (Queue)
-- MODEL
type alias Model =
{ recentLogs : Queue { channel : String, content : String }
, screen : Screen
}
type Msg
= OnSwitchScreen Screen
| OnVaultUpdate Matrix.VaultUpdate
type Screen
= LandingScreen
| Room String
init : Model
init =
{ recentLogs = Queue.empty
, screen = LandingScreen
}
maxItemsInRecentLogsQueue : Int
maxItemsInRecentLogsQueue = 100
-- UPDATE
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
OnSwitchScreen screen ->
( { model | screen = screen }, Cmd.none )
OnVaultUpdate vu ->
( { model
| recentLogs =
model.recentLogs
|> addItemsToQueue (Matrix.logs vu)
|> stripQueueToSize maxItemsInRecentLogsQueue
}
, Cmd.none
)
addItemsToQueue : List a -> Queue a -> Queue a
addItemsToQueue items queue =
List.foldl Queue.enqueue queue items
stripQueueToSize : Int -> Queue a -> Queue a
stripQueueToSize i queue =
if Queue.length queue > i then
stripQueueToSize i (Queue.dequeue queue)
else
queue
-- VIEW
view :
{ colorSelectedRoom : Color
, colorText : Color
, height : Int
, model : Model
, onVaultUpdate : Matrix.VaultUpdate -> msg
, vault : Matrix.Vault
, toMsg : Msg -> msg
, width : Int
} -> Element msg
view data =
viewScreen
{ colorSelectedRoom = data.colorSelectedRoom
, colorText = data.colorText
, height = data.height
, model = data.model
, onVaultUpdate = data.onVaultUpdate
, vault = data.vault
, screen = data.model.screen
, toMsg = data.toMsg
, width = data.width
}
viewScreen :
{ colorSelectedRoom : Color
, colorText : Color
, height : Int
, model : Model
, onVaultUpdate : Matrix.VaultUpdate -> msg
, vault : Matrix.Vault
, screen : Screen
, toMsg : Msg -> msg
, width : Int
} -> Element msg
viewScreen data =
case data.screen of
LandingScreen ->
Element.wrappedRow
[ Element.height (Element.px data.height)
, Element.width (Element.px data.width)
]
[ viewRoomList
{ colorSelected = data.colorSelectedRoom
, colorText = data.colorText
, rooms = Matrix.rooms data.vault
, toMsg = data.toMsg
}
]
Room roomId ->
case Matrix.fromRoomId roomId data.vault of
Just room ->
viewRoom
{ height = data.height
, model = room
, toMsg = data.toMsg
, width = data.width
}
Nothing ->
viewScreen { data | screen = LandingScreen }
viewRoom :
{ height : Int
, model : Matrix.Room.Room
, toMsg : Msg -> msg
, width : Int
} -> Element msg
viewRoom data =
[ Matrix.Room.name data.model
|> Maybe.withDefault "Nameless room"
|> Element.text
]
|> Element.column []
viewRoomList :
{ colorSelected : Color
, colorText : Color
, rooms : List Matrix.Room.Room
, toMsg : Msg -> msg
} -> Element msg
viewRoomList data =
Layout.sideList
{ color = data.colorSelected
, items =
data.rooms
|> List.map
(\room ->
Layout.itemWithSubtext
{ color = data.colorText
, leftIcon = always Element.none -- TODO: Add room image
, onPress =
Matrix.Room.roomId room
|> Room
|> OnSwitchScreen
|> data.toMsg
|> Just
, rightIcon = always Element.none -- TODO: Choose icon?
, text = Matrix.Room.roomId room
, title =
Matrix.Room.name room
|> Maybe.withDefault "Nameless room"
}
)
}

View File

@ -1,178 +0,0 @@
module Items.WelcomeScreen exposing (..)
import Color exposing (Color)
import Element exposing (Element)
import Element.Background
import Items.FlavorPicker as FlavorPicker
import Items.Introduction as Intro
import Items.LoginScreen as Login
import Items.VaultPicker as VaultPicker
import Matrix
import Theme
-- MODEL
type alias Model =
{ loginView : Maybe Login.Model
, vaultView : VaultPicker.Model
}
type Msg
= OnAddVault
| OnLoginView Login.Msg
| OnSubmitVault { name : String, vault : Matrix.Vault }
| OnVaultView VaultPicker.Msg
init : List { name : String, vault : Matrix.Vault } -> Model
init vaults =
{ loginView = Nothing
, vaultView = VaultPicker.init vaults
}
-- UPDATE
update : Msg -> Model -> Model
update msg model =
case msg of
OnAddVault ->
case model.loginView of
Just _ ->
model
Nothing ->
{ model | loginView = Just Login.init }
OnLoginView m ->
{ model
| loginView = Maybe.map (Login.update m) model.loginView
}
OnSubmitVault vault ->
{ model
| loginView = Nothing
, vaultView = VaultPicker.addVault vault model.vaultView
}
OnVaultView m ->
{ model
| vaultView = VaultPicker.update m model.vaultView
}
-- VIEW
getVault : Int -> Model -> Maybe Matrix.Vault
getVault i model =
VaultPicker.getVault i model.vaultView
view :
{ colorBackground : Color
, colorBackground2 : Color
, colorMain : Color
, colorMenu : Color
, colorText : Color
, colorTextField : Color
, height : Int
, flavor : Theme.Flavor
, model : Model
, onFlavorPick : Theme.Flavor -> msg
, onSelectVault : Int -> msg
, toMsg : Msg -> msg
, width : Int
} -> Element msg
view data =
let
goesVertical = 2 * data.width <= 3 * data.height
direction = if goesVertical then Element.column else Element.row
width = if goesVertical then data.width else data.width // 2
height = if goesVertical then data.height // 2 else data.height
in
case data.model.loginView of
Just m ->
direction
[ Element.height (Element.px data.height)
, Element.width (Element.px data.width)
]
[ viewIntroduction
{ colorBackground = data.colorBackground
, colorItem = data.colorText
, colorList = data.colorMenu
, height = height
, model = data.model.vaultView
, onSelectVault = data.onSelectVault
, toMsg = data.toMsg
, width = width
}
, Login.view
{ colorBackground = data.colorBackground2
, colorMain = data.colorMain
, colorMenu = data.colorMenu
, colorText = data.colorText
, colorTextField = data.colorTextField
, height = height
, flavor = data.flavor
, model = m
, onFlavorPick = data.onFlavorPick
, onSubmit = \vault -> OnSubmitVault { name = "New Vault", vault = vault } |> data.toMsg
, toMsg = OnLoginView >> data.toMsg
, width = width
}
]
Nothing ->
viewIntroduction
{ colorBackground = data.colorBackground
, colorItem = data.colorText
, colorList = data.colorMenu
, height = data.height
, model = data.model.vaultView
, onSelectVault = data.onSelectVault
, toMsg = data.toMsg
, width = data.width
}
|> Element.el
[ Element.Background.color (Theme.toElmUiColor data.colorBackground)
, Element.inFront
( FlavorPicker.view
{ height = 30
, flavor = data.flavor
, onClick = data.onFlavorPick
, themeIcon = always data.colorText
, width = 30
}
|> Element.el [ Element.alignRight ]
|> Element.el [ Element.padding 10, Element.width Element.fill ]
)
]
viewIntroduction :
{ colorBackground : Color
, colorItem : Color
, colorList : Color
, height : Int
, model : VaultPicker.Model
, onSelectVault : Int -> msg
, toMsg : Msg -> msg
, width : Int
} -> Element msg
viewIntroduction data =
[ Intro.view
{ colorBackground = data.colorBackground
, width = data.width
}
, VaultPicker.view
{ colorItem = data.colorItem
, colorList = data.colorList
, onAddVault = data.toMsg OnAddVault
, onSelectVault = data.onSelectVault
, model = data.model
, width = Basics.min 360 (4 * data.width // 5)
}
|> Element.el
[ Element.centerX
]
]
|> Element.column
[ Element.height (Element.px data.height)
, Element.scrollbarY
, Element.width (Element.px data.width)
]

View File

@ -1,5 +1,5 @@
module Layout exposing
( tab
( tab, twoBlocks
, iconAsElement, iconAsIcon
, containedButton, outlinedButton, textButton, sideList
, textInput, passwordInput
@ -15,6 +15,10 @@ The layout module exposes some boilerplate functions that have produce a
beautiful Material design Elm webpage.
## Screen layout
@docs twoBlocks
## Elements
@docs tab
@ -197,14 +201,19 @@ singlePalette { primary, onPrimary } =
}
}
sideList : { color : Color, items : List (Widget.Item msg) }-> Element msg
sideList : { color : Color, items : List (Widget.Item msg), width : Int }-> Element msg
sideList data =
let
width px = Element.width (Element.px px)
in
Widget.itemList
( { primary = data.color, onPrimary = data.color }
|> singlePalette
|> Material.sideSheet
)
data.items
|> Element.el [ Element.centerX, width (Basics.min 360 data.width) ]
|> Element.el [ width data.width ]
{-| A tab selector that always has an item selected.
-}
@ -275,3 +284,27 @@ textInput data =
, label = data.label
, onChange = data.onChange
}
{-| Two blocks either next to each other or below each other, depending on the
screen shape.
-}
twoBlocks :
{ height : Int
, el1 : { height : Int, width : Int } -> Element msg
, el2 : { height : Int, width : Int } -> Element msg
, width : Int
} -> Element msg
twoBlocks data =
let
goesVertical = 2 * data.width <= 3 * data.height
direction = if goesVertical then Element.column else Element.row
width = if goesVertical then data.width else data.width // 2
height = if goesVertical then data.height // 2 else data.height
in
direction
[ Element.height (Element.px data.height)
, Element.width (Element.px data.width)
]
[ data.el1 { height = height, width = width }
, data.el2 { height = height, width = width }
]

View File

@ -7,11 +7,12 @@ import Element exposing (Element)
import Element.Background
import Task
import Theme
import Items.LoginScreen as LoginScreen
import Items.VaultScreen as VaultScreen
import Items.WelcomeScreen as WelcomeScreen
import Items.VaultList as VaultList
import Screen.Welcome as WelcomeScreen
import Screen.Vault as VaultScreen
import Element.Font
import Items.VaultScreen as VaultScreen
import Recursion
import Matrix
main : Program () Model Msg
@ -36,25 +37,26 @@ type alias Model =
}
type Screen
= ScreenLogin LoginScreen.Model
| ScreenWelcome WelcomeScreen.Model
| ScreenVault WelcomeScreen.Model Int VaultScreen.Model
= ScreenWelcome WelcomeScreen.Model
| ScreenVault Vaults Int VaultScreen.Model
type Msg
= OnScreenLogin LoginScreen.Msg
| OnScreenVault Int VaultScreen.Msg
= OnScreenVault Int VaultScreen.Msg
| OnScreenWelcome WelcomeScreen.Msg
| OnSelectVault Int
| OnSelectVault Vaults Int
| OnVaultUpdate Int Matrix.VaultUpdate
| Pass
| ScreenSize { height : Int, width : Int }
| SetFlavor Theme.Flavor
type alias Vaults = VaultList.Model
init : () -> ( Model, Cmd Msg )
init () =
( { flavor = Theme.Latte
, height = 480
, screen = ScreenWelcome (WelcomeScreen.init [])
, screen = ScreenWelcome WelcomeScreen.init
, width = 720
}
, Browser.Dom.getViewport
@ -75,26 +77,14 @@ init () =
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
OnScreenLogin m ->
case model.screen of
ScreenLogin mdl ->
case LoginScreen.update m mdl of
newMdl ->
( { model | screen = ScreenLogin newMdl }
, Cmd.none
)
_ ->
( model, Cmd.none )
OnScreenVault i m ->
case model.screen of
ScreenVault welcomeMdl j mdl ->
if i == j then
case VaultScreen.update m mdl of
( newMdl, cmd ) ->
newMdl ->
( { model | screen = ScreenVault welcomeMdl i newMdl }
, Cmd.map (OnScreenVault i) cmd
, Cmd.none
)
else
( model, Cmd.none )
@ -114,23 +104,35 @@ update msg model =
_ ->
( model, Cmd.none )
OnSelectVault i ->
case model.screen of
ScreenVault welcomeMdl j _ ->
if i == j then
( model, Cmd.none )
else
( { model | screen = ScreenVault welcomeMdl i VaultScreen.init }
, Cmd.none
)
ScreenWelcome mdl ->
( { model | screen = ScreenVault mdl i VaultScreen.init }
, Cmd.none
)
_ ->
( model, Cmd.none )
OnSelectVault vaults i ->
( { model
| screen =
case model.screen of
ScreenWelcome _ ->
ScreenVault vaults i VaultScreen.init
ScreenVault _ j old ->
if i == j then
ScreenVault vaults j old
else
ScreenVault vaults i VaultScreen.init
}
, Cmd.none
)
OnVaultUpdate i vu ->
( { model
| screen =
case model.screen of
ScreenWelcome mdl ->
WelcomeScreen.updateVault i vu mdl
|> ScreenWelcome
ScreenVault vaults j mdl ->
ScreenVault (VaultList.insertVaultUpdate i vu vaults) j mdl
}
, Cmd.none
)
Pass ->
( model, Cmd.none )
@ -174,54 +176,54 @@ view model =
viewScreen : Model -> Element Msg
viewScreen model =
case model.screen of
ScreenLogin mdl ->
LoginScreen.view
{ colorBackground = Theme.base model.flavor
, colorMain = Theme.mauve model.flavor
, colorMenu = Theme.mantle model.flavor
, colorText = Theme.text model.flavor
, colorTextField = Theme.surface0 model.flavor
, flavor = model.flavor
, height = model.height
, model = mdl
, onFlavorPick = SetFlavor
, onSubmit = always Pass
, toMsg = OnScreenLogin
, width = model.width
}
ScreenVault welcomeMdl i mdl ->
case WelcomeScreen.getVault i welcomeMdl of
Just vault ->
VaultScreen.view
{ colorSelectedRoom = Theme.mantle model.flavor
, colorText = Theme.text model.flavor
, height = model.height
, model = mdl
, onVaultUpdate = always Pass
, toMsg = OnScreenVault i
, vault = vault
, width = model.width
}
let
colorBackground = Theme.base model.flavor
colorBackground2 = Theme.mantle model.flavor
colorMain = Theme.mauve model.flavor
colorSurface0 = Theme.surface0 model.flavor
colorSurface1 = Theme.surface1 model.flavor
colorText = Theme.text model.flavor
in
Recursion.runRecursion
(\screen ->
case screen of
ScreenVault vaults i mdl ->
case VaultList.getVault i vaults of
Just vault ->
VaultScreen.view
{ colorBackground = colorBackground
, colorText = colorText
, height = model.height
, model = mdl
, onVaultUpdate = OnVaultUpdate i
, toMsg = OnScreenVault i
, vault = vault
, width = model.width
}
|> Recursion.base
Nothing ->
viewScreen { model | screen = ScreenWelcome welcomeMdl }
Nothing ->
WelcomeScreen.fromVaults vaults
|> ScreenWelcome
|> Recursion.recurse
ScreenWelcome mdl ->
WelcomeScreen.view
{ colorBackground = Theme.base model.flavor
, colorBackground2 = Theme.mantle model.flavor
, colorMain = Theme.mauve model.flavor
, colorMenu = Theme.surface0 model.flavor
, colorText = Theme.text model.flavor
, colorTextField = Theme.surface1 model.flavor
, flavor = model.flavor
, height = model.height
, model = mdl
, onFlavorPick = SetFlavor
, onSelectVault = OnSelectVault
, toMsg = OnScreenWelcome
, width = model.width
}
ScreenWelcome mdl ->
WelcomeScreen.view
{ colorBackground = colorBackground
, colorBackground2 = colorBackground2
, colorMain = colorMain
, colorMenu = colorSurface0
, colorText = colorText
, colorTextField = colorSurface1
, flavor = model.flavor
, height = model.height
, model = mdl
, onFlavorPick = SetFlavor
, onSelectVault = OnSelectVault
, toMsg = OnScreenWelcome
, width = model.width
}
|> Recursion.base
)
model.screen

38
src/Screen/Vault.elm Normal file
View File

@ -0,0 +1,38 @@
module Screen.Vault exposing (..)
import Color exposing (Color)
import Element exposing (Element)
import Matrix
-- MODEL
type alias Model = ()
type alias Msg = ()
init : Model
init = ()
-- UPDATE
update : Msg -> Model -> Model
update msg model =
case msg of
() ->
model
-- VIEW
view :
{ colorBackground : Color
, colorText : Color
, height : Int
, model : Model
, onVaultUpdate : Matrix.VaultUpdate -> msg
, toMsg : Msg -> msg
, vault : Matrix.Vault
, width : Int
} -> Element msg
view data =
Element.none

163
src/Screen/Welcome.elm Normal file
View File

@ -0,0 +1,163 @@
module Screen.Welcome exposing (..)
import Color exposing (Color)
import Items.Introduction as Introduction
import Items.ItemPicker as ItemPicker
import Items.VaultList as VaultList
import Matrix
import Items.LoginView as LoginView
import Element exposing (Element)
import Layout
import Matrix.Settings
import Theme
-- MODEL
type alias Model =
{ login : Maybe LoginView.Model
, vaults : ItemPicker.Model VaultList.VaultBlock
}
type Msg
= OnAddNew
| OnLogin LoginView.Msg
| OnSubmitVault { name : String, vault : Matrix.Vault }
| OnVaultUpdate Int Matrix.VaultUpdate
| OnVaults ItemPicker.Msg
init : Model
init =
{ login = Nothing -- Just LoginView.init
, vaults = ItemPicker.init VaultList.init
}
fromVaults : VaultList.Model -> Model
fromVaults items =
{ login = Nothing
, vaults = ItemPicker.init items
}
-- UPDATE
update : Msg -> Model -> Model
update msg model =
case msg of
OnAddNew ->
{ model | login = Just LoginView.init }
OnLogin m ->
{ model | login = Maybe.map (LoginView.update m) model.login }
OnSubmitVault block ->
{ login = Nothing
, vaults = ItemPicker.updateContent (VaultList.addVault block) model.vaults
}
OnVaultUpdate i vu ->
{ model | vaults = ItemPicker.updateContent (VaultList.insertVaultUpdate i vu) model.vaults }
OnVaults m ->
{ model | vaults = ItemPicker.update m model.vaults }
updateVault : Int -> Matrix.VaultUpdate -> Model -> Model
updateVault i vu =
update (OnVaultUpdate i vu)
-- VIEW
view :
{ colorBackground : Color
, colorBackground2 : Color
, colorMain : Color
, colorMenu : Color
, colorText : Color
, colorTextField : Color
, flavor : Theme.Flavor
, height : Int
, model : Model
, onFlavorPick : Theme.Flavor -> msg
, onSelectVault : VaultList.Model -> Int -> msg
, toMsg : Msg -> msg
, width : Int
} -> Element msg
view data =
let
onSelectVault = data.onSelectVault (ItemPicker.extract data.model.vaults)
in
case data.model.login of
Just login ->
Layout.twoBlocks
{ height = data.height
, el1 =
\{ height, width } ->
viewIntroduction
{ colorBackground = data.colorBackground
, colorMenu = data.colorMenu
, colorText = data.colorText
, height = height
, model = data.model.vaults
, onAddNew = Nothing
, onSelectVault = onSelectVault
, width = width
}
, el2 =
\{ height, width } ->
LoginView.view
{ colorBackground = data.colorBackground2
, colorMain = data.colorMain
, colorMenu = data.colorMenu
, colorText = data.colorText
, colorTextField = data.colorTextField
, height = height
, flavor = data.flavor
, model = login
, onFlavorPick = data.onFlavorPick
, onSubmit = \vault -> OnSubmitVault { name = "New Vault", vault = vault } |> data.toMsg
, toMsg = OnLogin >> data.toMsg
, width = width
}
, width = data.width
}
Nothing ->
viewIntroduction
{ colorBackground = data.colorBackground
, colorMenu = data.colorMenu
, colorText = data.colorText
, height = data.height
, model = data.model.vaults
, onAddNew = Just (data.toMsg OnAddNew)
, onSelectVault = onSelectVault
, width = data.width
}
viewIntroduction :
{ colorBackground : Color
, colorMenu : Color
, colorText : Color
, height : Int
, model : ItemPicker.Model VaultList.VaultBlock
, onAddNew : Maybe msg
, onSelectVault : Int -> msg
, width : Int
} -> Element msg
viewIntroduction data =
[ Introduction.view { colorBackground = data.colorBackground, width = data.width }
, ItemPicker.view
{ colorMenu = data.colorMenu
, colorText = data.colorText
, height = data.height
, model = data.model
, toText = \_ vb -> Matrix.Settings.getDeviceName vb.vault
, toTitle = \vid vb -> vb.name ++ " #" ++ String.fromInt (vid + 1)
, onAddNew = data.onAddNew
, onClick = data.onSelectVault
, width = data.width
}
]
|> Element.column
[ Element.height (Element.px data.height)
, Element.scrollbarY
, Element.width (Element.px data.width)
]