on master help sign in
Got navigation stack working
176ebc3iko
elm.json+3−1
@@ -11,9 +11,11 @@
11 "elm/core": "1.0.5",
11 "elm/core": "1.0.5",
12 "elm/html": "1.0.0",
12 "elm/html": "1.0.0",
13 "elm/json": "1.1.3",
13 "elm/json": "1.1.3",
14− "elm/time": "1.0.0"
14+ "elm/time": "1.0.0",
15+ "mgold/elm-nonempty-list": "4.2.0"
15 },
16 },
16 "indirect": {
17 "indirect": {
18+ "elm/random": "1.0.0",
17 "elm/url": "1.0.0",
19 "elm/url": "1.0.0",
18 "elm/virtual-dom": "1.0.3"
20 "elm/virtual-dom": "1.0.3"
19 }
21 }
frontend/Main.elm+61−24
@@ -4,6 +4,7 @@ import Bridge
4import Browser
4import Browser
5import FFI exposing (getBridge, sendBridge)
5import FFI exposing (getBridge, sendBridge)
6import Html exposing (..)
6import Html exposing (..)
7+import List.Nonempty as Nonempty exposing (Nonempty(..))
7import Notification
8import Notification
8import Pages.Cipher as Cipher
9import Pages.Cipher as Cipher
9import Pages.Ciphers as Ciphers
10import Pages.Ciphers as Ciphers
@@ -32,6 +33,7 @@ type Msg
32 | CipherMsg Cipher.Msg
33 | CipherMsg Cipher.Msg
33 | ShowCipherPage Bridge.Sub_LoadCipher
34 | ShowCipherPage Bridge.Sub_LoadCipher
34 | RequestCipher CipherId
35 | RequestCipher CipherId
36+ | PopView
35
37
36
38
37type alias CipherId =
39type alias CipherId =
@@ -40,7 +42,7 @@ type alias CipherId =
40
42
41type alias Model =
43type alias Model =
42 { notifications : List Notification.Config
44 { notifications : List Notification.Config
43− , page : PageModel
45+ , pageStack : Navigation.PageStack PageModel
44 }
46 }
45
47
46
48
@@ -134,7 +136,7 @@ init : ( Model, Cmd Msg )
134init =
136init =
135 -- Cipher.init |> Tuple.mapBoth (\p -> { notifications = [], page = CipherModel p }) (Cmd.map CipherMsg)
137 -- Cipher.init |> Tuple.mapBoth (\p -> { notifications = [], page = CipherModel p }) (Cmd.map CipherMsg)
136 ( { notifications = []
138 ( { notifications = []
137− , page = LoadingPage
139+ , pageStack = Nonempty.singleton LoadingPage
138 }
140 }
139 , FFI.sendBridge Bridge.Init
141 , FFI.sendBridge Bridge.Init
140 )
142 )
@@ -142,15 +144,38 @@ init =
142
144
143view : Model -> Html Msg
145view : Model -> Html Msg
144view model =
146view model =
145− let
147+ Navigation.showNavigationView { popStack = PopView }
146− ( title, body ) =
148+ model.pageStack
147− showPage model.page
149+ (\page ->
148− in
150+ let
149− div []
151+ ( title, body ) =
150− [ Navigation.navigation { back = False, title = title }
152+ showPage page
151− , main_ []
153+ in
154+ ( title
152− (maybeList (List.head model.notifications) (Notification.notification CloseNotification) ++ body)
155+ , maybeList (List.head model.notifications) (Notification.notification CloseNotification) ++ body
153− ]
156+ )
157+ )
158+
159+
160+mapHead : (a -> a) -> Nonempty a -> Nonempty a
161+mapHead f (Nonempty x xx) =
162+ Nonempty (f x) xx
163+
164+
165+doNotStoreInHistory : PageModel -> Bool
166+doNotStoreInHistory page =
167+ case page of
168+ LoginModel _ ->
169+ True
170+
171+ MasterPasswordModel _ ->
172+ True
173+
174+ LoadingPage ->
175+ True
176+
177+ _ ->
178+ False
154
179
155
180
156update : Msg -> Model -> ( Model, Cmd Msg )
181update : Msg -> Model -> ( Model, Cmd Msg )
@@ -160,7 +185,7 @@ update msg model =
160 processPage liftModel ( resultModel, cmd ) =
185 processPage liftModel ( resultModel, cmd ) =
161 case resultModel of
186 case resultModel of
162 Ok mdl ->
187 Ok mdl ->
163− ( { model | page = liftModel mdl }, cmd )
188+ ( { model | pageStack = mapHead (always (liftModel mdl)) model.pageStack }, cmd )
164
189
165 Err err ->
190 Err err ->
166 ( appendNotification
191 ( appendNotification
@@ -171,6 +196,13 @@ update msg model =
171 model
196 model
172 , cmd
197 , cmd
173 )
198 )
199+
200+ appendPageStack : PageModel -> Model
201+ appendPageStack mdl =
202+ { model | pageStack = model.pageStack |> Nonempty.toList |> List.filter (doNotStoreInHistory >> not) |> Nonempty mdl }
203+
204+ currentPage =
205+ model.pageStack |> Nonempty.head
174 in
206 in
175 case msg of
207 case msg of
176 RecieveMessage x ->
208 RecieveMessage x ->
@@ -204,7 +236,7 @@ update msg model =
204 )
236 )
205
237
206 LoginMsg imsg ->
238 LoginMsg imsg ->
207− case model.page of
239+ case currentPage of
208 LoginModel page ->
240 LoginModel page ->
209 (Login.page loginCallbacks LoginMsg).update imsg page |> processPage LoginModel
241 (Login.page loginCallbacks LoginMsg).update imsg page |> processPage LoginModel
210
242
@@ -212,7 +244,7 @@ update msg model =
212 ( model, Cmd.none )
244 ( model, Cmd.none )
213
245
214 CiphersMsg imsg ->
246 CiphersMsg imsg ->
215− case model.page of
247+ case currentPage of
216 CiphersModel page ->
248 CiphersModel page ->
217 (Ciphers.page ciphersCallbacks CiphersMsg).update imsg page |> processPage CiphersModel
249 (Ciphers.page ciphersCallbacks CiphersMsg).update imsg page |> processPage CiphersModel
218
250
@@ -221,30 +253,30 @@ update msg model =
221
253
222 ShowLoginPage ->
254 ShowLoginPage ->
223 (Login.page loginCallbacks LoginMsg).init ()
255 (Login.page loginCallbacks LoginMsg).init ()
224− |> Tuple.mapFirst (\pageModel -> { model | page = LoginModel pageModel })
256+ |> Tuple.mapFirst (\pageModel -> appendPageStack <| LoginModel pageModel)
225
257
226 LoadCiphers ciphers ->
258 LoadCiphers ciphers ->
227 (Ciphers.page ciphersCallbacks CiphersMsg).init ciphers
259 (Ciphers.page ciphersCallbacks CiphersMsg).init ciphers
228− |> Tuple.mapFirst (\pageModel -> { model | page = CiphersModel pageModel })
260+ |> Tuple.mapFirst (\pageModel -> appendPageStack <| CiphersModel pageModel)
229
261
230 OpenCiphersScreen ->
262 OpenCiphersScreen ->
231− ( { model | page = LoadingPage }, sendBridge Bridge.NeedCiphersList )
263+ ( appendPageStack <| LoadingPage, sendBridge Bridge.NeedCiphersList )
232
264
233 Reset ->
265 Reset ->
234 init
266 init
235
267
236 ShowMasterPasswordPage { server, login } ->
268 ShowMasterPasswordPage { server, login } ->
237 (MasterPassword.page masterPasswordCallbacks MasterPasswordMsg).init { server = server, login = login }
269 (MasterPassword.page masterPasswordCallbacks MasterPasswordMsg).init { server = server, login = login }
238− |> Tuple.mapFirst (\pageModel -> { model | page = MasterPasswordModel pageModel })
270+ |> Tuple.mapFirst (\pageModel -> appendPageStack <| MasterPasswordModel pageModel)
239
271
240 NeedsReset ->
272 NeedsReset ->
241− ( { model | page = LoadingPage }, sendBridge Bridge.NeedsReset )
273+ ( appendPageStack <| LoadingPage, sendBridge Bridge.NeedsReset )
242
274
243 SendMasterPassword { password } ->
275 SendMasterPassword { password } ->
244− ( { model | page = LoadingPage }, sendBridge (Bridge.SendMasterPassword password) )
276+ ( appendPageStack <| LoadingPage, sendBridge (Bridge.SendMasterPassword password) )
245
277
246 MasterPasswordMsg imsg ->
278 MasterPasswordMsg imsg ->
247− case model.page of
279+ case currentPage of
248 MasterPasswordModel page ->
280 MasterPasswordModel page ->
249 (MasterPassword.page masterPasswordCallbacks MasterPasswordMsg).update imsg page |> processPage MasterPasswordModel
281 (MasterPassword.page masterPasswordCallbacks MasterPasswordMsg).update imsg page |> processPage MasterPasswordModel
250
282
@@ -252,7 +284,7 @@ update msg model =
252 ( model, Cmd.none )
284 ( model, Cmd.none )
253
285
254 CipherMsg imsg ->
286 CipherMsg imsg ->
255− case model.page of
287+ case currentPage of
256 CipherModel page ->
288 CipherModel page ->
257 (Cipher.page cipherCallbacks CipherMsg).update imsg page |> processPage CipherModel
289 (Cipher.page cipherCallbacks CipherMsg).update imsg page |> processPage CipherModel
258
290
@@ -261,10 +293,15 @@ update msg model =
261
293
262 ShowCipherPage cipher ->
294 ShowCipherPage cipher ->
263 (Cipher.page cipherCallbacks CipherMsg).init cipher
295 (Cipher.page cipherCallbacks CipherMsg).init cipher
264− |> Tuple.mapFirst (\pageModel -> { model | page = CipherModel pageModel })
296+ |> Tuple.mapFirst (\pageModel -> appendPageStack <| CipherModel pageModel)
265
297
266 RequestCipher id ->
298 RequestCipher id ->
267− ( { model | page = LoadingPage }, sendBridge (Bridge.RequestCipher id) )
299+ ( appendPageStack <| LoadingPage, sendBridge (Bridge.RequestCipher id) )
300+
301+ PopView ->
302+ ( { model | pageStack = Navigation.popView model.pageStack }
303+ , Cmd.none
304+ )
268
305
269
306
270loginCallbacks : Login.Callbacks Msg
307loginCallbacks : Login.Callbacks Msg
frontend/Pages/Navigation.elm+40−5
@@ -1,24 +1,33 @@
1−module Pages.Navigation exposing (Config, menu, navigation)
1+module Pages.Navigation exposing
2+ ( Config
3+ , PageStack
4+ , menu
5+ , popView
6+ , pushView
7+ , showNavigationView
8+ )
2
9
3import Html exposing (..)
10import Html exposing (..)
4import Html.Attributes as Attr
11import Html.Attributes as Attr
5import Html.Events as Ev
12import Html.Events as Ev
13+import List.Nonempty as Nonempty exposing (Nonempty)
6import Utils exposing (..)
14import Utils exposing (..)
7
15
8
16
9−type alias Config =
17+type alias Config msg =
10 { back : Bool
18 { back : Bool
11 , title : String
19 , title : String
20+ , pop : msg
12 }
21 }
13
22
14
23
15−navigation : Config -> Html msg
24+navigation : Config msg -> Html msg
16−navigation { back, title } =
25+navigation { back, title, pop } =
17 nav [ Attr.class "p-tabs p-tabs__list" ]
26 nav [ Attr.class "p-tabs p-tabs__list" ]
18 [ h3 [ Attr.class "u-no-margin u-no-padding" ]
27 [ h3 [ Attr.class "u-no-margin u-no-padding" ]
19 [ button
28 [ button
20 (Attr.class "p-button--base is-inline u-no-margin" :: optional (not back) (Attr.style "visibility" "hidden"))
29 (Attr.class "p-button--base is-inline u-no-margin" :: optional (not back) (Attr.style "visibility" "hidden"))
21− [ i [ Attr.class "p-icon--chevron-up ninety-counter" ] []
30+ [ i [ Attr.class "p-icon--chevron-up ninety-counter", Ev.onClick pop ] []
22 ]
31 ]
23 , text title
32 , text title
24 ]
33 ]
@@ -54,3 +63,29 @@ menu { title, items, close } =
54 )
63 )
55 ]
64 ]
56 ]
65 ]
66+
67+
68+type alias PageStack model =
69+ Nonempty model
70+
71+
72+pushView : model -> PageStack model -> PageStack model
73+pushView model stack =
74+ Nonempty.cons model stack
75+
76+
77+popView : PageStack model -> PageStack model
78+popView stack =
79+ Nonempty.tail stack |> Nonempty.fromList |> Maybe.withDefault stack
80+
81+
82+showNavigationView : { popStack : msg } -> PageStack model -> (model -> ( String, List (Html msg) )) -> Html msg
83+showNavigationView { popStack } stack render =
84+ let
85+ ( title, body ) =
86+ render (Nonempty.head stack)
87+ in
88+ div []
89+ [ navigation { back = Nonempty.length stack > 1, title = title, pop = popStack }
90+ , main_ [] body
91+ ]