diff --git a/samples/Playground/App.fs b/samples/Playground/App.fs index fad3c5b..89f81c9 100644 --- a/samples/Playground/App.fs +++ b/samples/Playground/App.fs @@ -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}") ) ) diff --git a/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj b/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj index 3020042..e6a83ff 100644 --- a/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj +++ b/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj @@ -57,6 +57,7 @@ + diff --git a/src/Fabulous.MauiControls/Views/Pages/NavigationStack.fs b/src/Fabulous.MauiControls/Views/Pages/NavigationStack.fs new file mode 100644 index 0000000..6a242ac --- /dev/null +++ b/src/Fabulous.MauiControls/Views/Pages/NavigationStack.fs @@ -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, EventArgs>() + let mutable stack: IEnumerable = [||] + + [] + 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() + + let Stack = Attributes.defineSimpleScalarWithEquality> "NavigationStack_Stack" (fun prevOpt currOpt node -> + () + ) + +[] +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 = (uint16 pages.Length, pages) + + WidgetBuilder<'msg, IFabNavigationStack>( + NavigationStack.WidgetKey, + AttributesBundle( + StackList.empty(), + ValueNone, + ValueSome [| + NavigationPage.Pages.WithValue(pages) + |] + ) + ) \ No newline at end of file