Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - Implement a new NavigationStack widget #23

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 53 additions & 47 deletions samples/Playground/App.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,59 +10,65 @@ open Microsoft.Maui.Primitives
open type Fabulous.Maui.View

module App =
type FieldFocused =
| Entry1
| Entry2
| Entry3

type Model = { Focus: FieldFocused option }

type Path =
| Home
| Details
| Subdetails of int

type Model =
{ Stack: Path list }

type Msg =
| TextChanged of string
| FocusChanged of FieldFocused * bool
| SetFocus of FieldFocused option

let init () = { Focus = None }

| StackUpdated of Path list
| GoTo of Path
| GoBack
| GoToRoot

let init() =
{ Stack = [ Home ] }

let update msg model =
match msg with
| TextChanged _ -> model
| FocusChanged(field, isFocused) ->
if isFocused then
{ model with Focus = Some field }
else
{ model with Focus = None }

| SetFocus field -> { model with Focus = field }

let focusChanged field args = FocusChanged(field, args)
| StackUpdated stack ->
{ model with Stack = stack }
| GoTo path ->
{ model with Stack = path :: model.Stack }
| GoBack ->
{ model with Stack = model.Stack |> List.tail }
| GoToRoot ->
{ model with Stack = [model.Stack |> List.last] }

let view model =
Application(
ContentPage(
(VStack(spacing = 20.) {
let text =
match model.Focus with
| None -> "None"
| Some f -> f.ToString()

Label($"Field currently selected: {text}")

Entry("Entry1", TextChanged)
.focus(model.Focus = Some Entry1, focusChanged Entry1)

Entry("Entry2", TextChanged)
.focus(model.Focus = Some Entry2, focusChanged Entry2)

Entry("Entry3", TextChanged)
.focus(model.Focus = Some Entry3, focusChanged Entry3)

Button("Set focus on Entry1", SetFocus(Some Entry1))
Button("Set focus on Entry2", SetFocus(Some Entry2))
Button("Set focus on Entry3", SetFocus(Some Entry3))
Button("Unfocus", SetFocus None)
})
.margin(20.)
NavigationStack(List.rev model.Stack, StackUpdated, fun path ->
match path with
| Home ->
ContentPage(
VStack(spacing = 15.) {
Label("Home")
Button("Go to Details", GoTo Details)
}
)
.title("Home")
| Details ->
ContentPage(
VStack(spacing = 15.) {
Label("Details")
for i in 1..3 do
Button($"Go to Subdetails {i}", GoTo (Subdetails i))
Button("Go back", GoBack)
}
)
.title("Details")
| Subdetails i ->
ContentPage(
VStack(spacing = 15.) {
Label($"Subdetails {i}")
Button("Go back", GoBack)
Button("Go to root", GoToRoot)
}
)
.title($"Subdetails {i}")
)
)

Expand Down
1 change: 1 addition & 0 deletions src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
<Compile Include="Views\Pages\_Page.fs" />
<Compile Include="Views\Pages\ContentPage.fs" />
<Compile Include="Views\Pages\NavigationPage.fs" />
<Compile Include="Views\Pages\NavigationStack.fs" />
<Compile Include="Views\Pages\_MultiPageOfPage.fs" />
<Compile Include="Views\Pages\TabbedPage.fs" />
<Compile Include="Views\Pages\FlyoutPage.fs" />
Expand Down
70 changes: 70 additions & 0 deletions src/Fabulous.MauiControls/Views/Pages/NavigationStack.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
namespace Fabulous.Maui

open System
open System.Collections.Generic
open Fabulous
open Fabulous.Maui
open Fabulous.StackAllocatedCollections.StackList
open Microsoft.Maui.Controls

type IFabNavigationStack =
inherit IFabNavigationPage




type FabNavigationStack() =
inherit NavigationPage()

let stackUpdated = Event<EventHandler<EventArgs>, EventArgs>()
let mutable stack: IEnumerable<Page> = [||]

[<CLIEvent>]
member _.StackUpdated = stackUpdated.Publish

member this.Stack
with get () = stack
and set value =
if stack <> value then
stack <- value
this.ApplyStack()

member private this.ApplyStack() =
// TODO: Diff the stack and only update the pages that changed
stackUpdated.Trigger(this, EventArgs())












module NavigationStack =
let WidgetKey = Widgets.register<FabNavigationStack>()

let Stack = Attributes.defineSimpleScalarWithEquality<ArraySlice<Widget>> "NavigationStack_Stack" (fun prevOpt currOpt node ->
()
)

[<AutoOpen>]
module NavigationStackBuilders =
type Fabulous.Maui.View with
static member inline NavigationStack(stack: 'path list, onStackUpdated: 'path list -> 'msg, router: 'path -> WidgetBuilder<'msg, #IFabPage>) =
let pages = [| for path in stack do (router path).Compile() |]
let pages: ArraySlice<Widget> = (uint16 pages.Length, pages)

WidgetBuilder<'msg, IFabNavigationStack>(
NavigationStack.WidgetKey,
AttributesBundle(
StackList.empty(),
ValueNone,
ValueSome [|
NavigationPage.Pages.WithValue(pages)
|]
)
)