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

Dispatch function accessible in App projects #240

Merged
merged 4 commits into from
Dec 3, 2018
Merged
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
73 changes: 73 additions & 0 deletions docs/update.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,77 @@ let update msg model =
match msg with
| TakePicture -> model, (Cmd.ofAsyncMsgOption takePictureCmd)
| PictureTaken -> ...
```

Platform-specific dispatch
-----

Some platform-specific features (like deep linking, memory warnings, ...) are not available in Xamarin.Forms, and need you to implement them in the corresponding app projet.
In this case, you might want to dispatch a message from the app project to Fabulous to start a shared logic between platforms (to warn user, ...).

To allow for this kind of use case, the `dispatch` function is exposed as a `Dispatch(msg)` method by the `ProgramRunner`. By default this runner is not accessible, but you can make a read-only property to let apps access it.

```fsharp
type App() as app =
inherit Application()

let runner =
Program.mkProgram init update view
|> Program.runWithDynamicView app

member __.Program = runner // Add this line
```

Once done, you can access it in the app project

- Android
```fsharp
[<Activity>]
type MainActivity() =
inherit FormsApplicationActivity()

// Store the App instance
let mutable _app: App option = None

override this.OnCreate (bundle: Bundle) =
base.OnCreate (bundle)

Forms.Init (this, bundle)

// Initialize the app and store its reference
let app = new App()
this.LoadApplication(app)
_app <- Some app

override this.OnTrimMemory(level) =
// If the app is initialized, dispatch the message
match _app with
| Some app -> app.Program.Dispatch(Msg.ReceivedLowMemoryWarning)
| None -> ()
```

- iOS
```fsharp
[<Register("AppDelegate")>]
type AppDelegate () =
inherit FormsApplicationDelegate ()

// Store the App instance
let mutable _app: App option = None

override this.FinishedLaunching (uiApp, options) =
Forms.Init()

// Initialize the app and store its reference
let app = new AllControls.App()
this.LoadApplication (app)
_app <- Some app

base.FinishedLaunching(uiApp, options)

override this.ReceiveMemoryWarning(uiApp) =
// If the app is initialized, dispatch the message
match _app with
| Some app -> app.Program.Dispatch(Msg.ReceivedLowMemoryWarning)
| None -> ()
```
13 changes: 12 additions & 1 deletion samples/AllControls/AllControls/AllControls.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018 Fabulous contributors. See LICENSE.md for license.
// Copyright 2018 Fabulous contributors. See LICENSE.md for license.
namespace AllControls

open System
Expand Down Expand Up @@ -90,6 +90,7 @@ type Msg =
| AnimationPoked3
| SetCarouselCurrentPage of int
| SetTabbed1CurrentPage of int
| ReceivedLowMemoryWarning

[<AutoOpen>]
module MyExtension =
Expand Down Expand Up @@ -235,6 +236,14 @@ module App =
{ model with CarouselCurrentPageIndex = index }
| SetTabbed1CurrentPage index ->
{ model with Tabbed1CurrentPageIndex = index }
| ReceivedLowMemoryWarning ->
Application.Current.MainPage.DisplayAlert("Low memory!", "Cleaning up data...", "OK") |> ignore
{ model with
EditorText = ""
EntryText = ""
Placeholder = ""
Password = ""
SearchTerm = "" }

let pickerItems =
[| ("Aqua", Color.Aqua); ("Black", Color.Black);
Expand Down Expand Up @@ -761,3 +770,5 @@ type App () as app =
Program.mkSimple App.init App.update App.view
|> Program.withConsoleTrace
|> Program.runWithDynamicView app

member __.Program = runner
14 changes: 12 additions & 2 deletions samples/AllControls/Droid/MainActivity.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018 Fabulous contributors. See LICENSE.md for license.
// Copyright 2018 Fabulous contributors. See LICENSE.md for license.
namespace AllControls.Droid

open System
Expand All @@ -15,10 +15,20 @@ open Xamarin.Forms.Platform.Android
[<Activity (Label = "AllControls.Droid", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = (ConfigChanges.ScreenSize ||| ConfigChanges.Orientation))>]
type MainActivity() =
inherit FormsApplicationActivity()

let mutable _app: AllControls.App option = None

override this.OnCreate (bundle: Bundle) =
base.OnCreate (bundle)

Xamarin.Forms.Forms.Init (this, bundle)

this.LoadApplication (new AllControls.App ())
let app = new AllControls.App()
this.LoadApplication(app)
_app <- Some app

override this.OnTrimMemory(level) =
match _app with
| Some app -> app.Program.Dispatch(AllControls.Msg.ReceivedLowMemoryWarning)
| None -> ()

19 changes: 15 additions & 4 deletions samples/AllControls/iOS/AppDelegate.fs
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
// Copyright 2018 Fabulous contributors. See LICENSE.md for license.
// Copyright 2018 Fabulous contributors. See LICENSE.md for license.
namespace iOS

open System
open UIKit
open Foundation
open Xamarin.Forms
open Xamarin.Forms.Platform.iOS
open AllControls

[<Register ("AppDelegate")>]
type AppDelegate () =
inherit FormsApplicationDelegate ()

override this.FinishedLaunching (app, options) =
let mutable _app: AllControls.App option = None

override this.FinishedLaunching (uiApp, options) =
Forms.Init()
this.LoadApplication (new AllControls.App())
base.FinishedLaunching(app, options)
let app = new AllControls.App()
this.LoadApplication (app)
_app <- Some app

base.FinishedLaunching(uiApp, options)

override this.ReceiveMemoryWarning(uiApp) =
match _app with
| Some app -> app.Program.Dispatch(AllControls.Msg.ReceivedLowMemoryWarning)
| None -> ()

module Main =
[<EntryPoint>]
Expand Down
6 changes: 4 additions & 2 deletions src/Fabulous.Core/ElmishProgram.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018 Elmish and Fabulous contributors. See LICENSE.md for license.
// Copyright 2018 Elmish and Fabulous contributors. See LICENSE.md for license.
namespace Fabulous.Core

open System
Expand Down Expand Up @@ -122,7 +122,9 @@ type ProgramRunner<'model, 'msg>(app: Application, program: Program<'model, 'msg
member __.InitialMainPage = mainPage

member __.CurrentModel = lastModel


member __.Dispatch(msg) = dispatch msg

member runner.ChangeProgram(newProgram: Program<obj, obj, obj -> (obj -> unit) -> ViewElement>) : unit =
Device.BeginInvokeOnMainThread(fun () ->
// TODO: transmogrify the model
Expand Down