0 Comments
  •   Posted in: 
  • F#

Photograph showing christmas gifts

So with a pandemic, Christmas was interesting, to say the least, this year. Following the COVID-19 guidelines, we were able to exchange our secret Santa gifts this year. There was only one problem. We usually have a little paper-based lottery for assigning the secret Santa. And we tend to do it on the same evening. But with COVID-19 doing its thing there was FaceTime and such involved this year. FaceTime was great but not so good when it comes to the lottery part, especially since no one should know who got who.

So what was there to be done for a successful Secret Santa 2021 without anyone knowing who picked whom? Why not do this on my own, break out Visual Studio Code and write app a little app that will do this for us. So I broke the process down into the following steps:

  • Read the input
  • Assign randomly
  • Send a text message(s)

Disclaimer: I did not receive any compensation for using Twilio. I did this because it seemed like a fun project, and SMS just seemed to be the friendliest approach for everyone involved.

Now for reading the input, I went with a more or less standard CSV file format as follows:

Person1;+15551234
Person2;+15551235

I figured this would allow for some flexibility and allow me to share the code without sharing any private contact information. 😉

Reading the input can be done with a few helpers from the .Net Framework living in the System and System.IO namespace.

type Person = { Name : string; MobileNumber : string }

let parseToPerson (inputString:string) =
    let csvItems = inputString.Split(";")
    {Name = csvItems.[0]; MobileNumber = csvItems.[1]}

Now next to the algorithm which would assign a Secret Santa. In our family, the rules are quite simple. Everyone is the Secret Santa of someone else, and no one is his or her own Secret Santa. The random assignments can are achieved by ordering the list with a random number and then zipping it to the order of the CSV file:

let random = Random()
let rec assignSecretSantas (people : Person seq) =
    let secretSantasAssignments =
        people
        |> Seq.sortBy(fun x -> random.Next())
    
    let assignments = 
        secretSantasAssignments
        |> Seq.zip people
        |> Seq.toList
    
    if assignments |> Seq.exists (fun a -> fst a = snd a) then
        assignSecretSantas people
    else
        assignments

Lastly, the assignment is checked that no one is assigned to themselves. Should there be an illegal assignment, the method will execute recursively.

Now to the part which was new to me. Send a text message from code. I have heard of Twilio before but never had the opportunity to play around with their service. Setting up an account is your run of the mill create an account scenario. They even provide you with a couple of bucks to try out their tutorials. So with my trial account and money at hand, I implemented the SMS part.

The first step is adding the NuGet package. When developing this, I used an F# Script file. Why am I mentioning this, well because since F# 5 adding/using a NuGet package in a script is as simple as adding the following lines to the top of your script file:

#r "nuget: Twilio"

open Twilio
open Twilio.Rest.Api.V2010.Account

But in the final version, I opted for a console app, which uses the standard dotnet add package Twilio to add the package to your project.

Before being able to send messages, the client needs to be initialized.

let initTwilio =
    let accountSid = configuration.GetSection("Twilio").["Sid"]
    let authToken = configuration.GetSection("Twilio").["AuthToken"]
    TwilioClient.Init(accountSid, authToken)

I must say the docs from Twilio were a great help here. Be sure to check them out if you are looking into more advanced scenarios.

With the client initialized, I wrote the code to send the message:

let secretSantaPhoneNumber = "+15551236"
let secretSantaMessage = "Testmessage"
MessageResource.Create(
    Twilio.Types.PhoneNumber(secretSantaPhoneNumber), 
    body=secretSantaMessage, 
    from=Twilio.Types.PhoneNumber("Twilio-Sender-Phone-Number"))

Sending the message was a tad more complicated than initially expected. In comparison, everything worked with my phone number, which I had to provide when signing up. When trying to send a test message to someone else in the family, I got the error message to use a number that had previously been registered with Twilio's trial version. The fix was going for a paid account - but after that, I could implement the sending of Secret Santas:

let rec informSecretSantas dryRun (santas: (Person * Person) list) =
    match santas with
    | [] -> ()
    | head::tail ->
        let santaName = (fst head).Name
        let giftReceiver = (snd head).Name
        let phoneNumber = (fst head).MobileNumber
        let body = $"The secret santa message"
        if dryRun then
            printfn "%s" body
            printfn "Sending to %s" phoneNumber
        else
            let msg = MessageResource.Create(Twilio.Types.PhoneNumber(phoneNumber), body=body, from=Twilio.Types.PhoneNumber("Twilio-Phone-Number"))
            printfn "%A" msg.Status
        informSecretSantas dryRun tail

And with that Christmas 2021 was saved. Now was this the best option? Well, there are quite a few services out there - some even support SMS and don't cost you a thing. But where would have the fun been in one of those? 🙃

For me, the experience of using F# Script files to carve out the different parts of the "app" was great and very intuitive. Running code in the F# REPL / FSI allowed for quick iterations and trying out. An added benefit was using Ionide - the plugin you want to install when developing F# with VS Code. And Ionide just got an update to support F# 5.0. 🥳

Oh, and another word of advice, if you keep the buttons pressed to execute code in the FSI - it will run multiple times. Ask how my family knows after receiving not one but four secret Santa text messages in the first "test" run. 🙈

You can find the entire code on GitHub.


Title photo by Lucie Liz from Pexels

0 Comments

00_Title

This blog post is part of the F# Advent Calendar 2020. A big thank you to Sergey for organizing this year and be sure to check out the other blog posts - after reading this one .

Based on the Model View Update (MVU) pattern the Fabulous frameworks provides the means to write functional first mobile (and desktop), clients. If you are new to Fabulous, I would recommend you check out the post by Tim (the maintainer of Fabulous) or the official docs.

The backend is implemented as an ASP.NET Core web app which has SignalR enabled. You can see how to this here.

To show how you can use SignalR with Fabulous, we will implement a chat application. And I felt like calling it "Fabulous Chat" - see how is easy it is to do fabulous things with this framework ? So let's ignore the question: "Does this world really need yet another chat app?!" in the back of our minds and let's have a look at what we will implement in this app to highlight how you could use SignalR within in a functional first mobile app.

Let's assume we have the following requirements:

  • A user should identify himself by his name.
  • The user should be able to send messages.
  • A user should be able to read messages while the app is active.

In other words, two actions are entirely UI driven, the user enters his username and then enters the chat. The user types a message and then sends it by the push of a button. However, when it comes to being able to read messages, the event will be fired from the background. Further, the SignalR connection usually is established once and then used for the remainder of the session. So let's create a module in our app, which will contain all the operations regarding the SignalR interaction.

module SignalR =
    let connectToServer =
        // connect to SignalR service

    let startListeningToChatMessages (connection: HubConnection) dispatch =
        // receive messages

    let sendMessage (connection: HubConnection) (message: ChatMessage) =
        // send message

We connect to the service after the user has provided his name. Not because it is required per se. But if at some later point we decide to add some proper authentication this will not change the flow of the app. Without further ado, let's implement the login view.

Image showing the login view

The view we use for this part is as described below.

let view model dispatch =
    View.ContentPage
        (title = "Login",
         content =
             View.StackLayout
                 (verticalOptions = LayoutOptions.Center,
                  horizontalOptions = LayoutOptions.Center,
                  children =
                      [ View.Label(text = "Please enter your Username")
                        View.Entry
                            (text = model.Username,
                             maxLength = 15,
                             placeholder = "Please enter your username",
                             completed = (fun _ -> (loginUser dispatch)),
                             textChanged = fun e -> dispatch (UsernameChanged e.NewTextValue))
                        View.Button(text = "Login", command = fun _ -> (loginUser dispatch))
                        ]))

Once the user hits the Login button, we want to establish the SignalR connection.

let connectToServer =
    let connection =
        HubConnectionBuilder()
            .WithUrl(Config.SignalRUrl)
            .WithAutomaticReconnect()
            .Build()

    async {
        do! connection.StartAsync() |> Async.AwaitTask
        return connection
    }

Since we will want to hold on to the connection, we will invoke a Command which will be evaluated in the Update method.

let update msg (model: Model) =
    match msg with
    // ... other message handling
    | Connected connection ->
        { model with
              SignalRConnection = Some connection
              AppState = Ready },
        Cmd.none
    // ... more message handling

Now, after the user is connected to the chat, we will present the chat view. This view allows the user to type a message, send it and read the responses or questions by other users connected to the service.

Image showing the chat view in action

Let's start with writing messages. Similar as with the username we again have an Entry and a button for sending the messages. Once the user sends a message, we invoke SendAsync in our SignalR module:

let sendMessage (connection: HubConnection) (message: ChatMessage) =
    async {
        let jsonMessage = JsonSerializer.Serialize(message)

        do! connection.SendAsync("SendMessage", jsonMessage)
            |> Async.AwaitTask
    }

So thus far, we have connected to the SignalR service, and we can send messages to the server. But we are still missing one essential part, and that is how we can receive messages from the backend service. What we need to do is register a listener to a specific SignalR-method (called NewMessage). We can implement our function as follows:

let startListeningToChatMessages (connection: HubConnection) dispatch =
    let handleReceivedMessage (msg: string) =
        printfn "Received message: %s" msg
        dispatch (Msg.MessageReceived(JsonSerializer.Deserialize<ChatMessage>(msg)))
        ()

    connection.On<string>("NewMessage", handleReceivedMessage)

Now in the handler method, we will dispatch a command every time a new message is received from the SignalR service. So let's extend our login function, from the beginning, to not only create a connection but also register our receiver.

let loginUser dispatch =
    async {
        let! connection = SignalR.connectToServer
        dispatch (Msg.Connected connection)

        SignalR.startListeningToChatMessages connection dispatch
        |> ignore

        dispatch (Msg.LoggedIn)
    }
    |> Async.StartImmediate

We pass in the dispatcher from the view method when registering. This allows us to dispatch a command, i.e. invoke the update method and add the new message to our list of chat messages:

let update msg (model: Model) =
    match msg with
    // ... other message handling
    | MessageReceived chatMessage ->
        { model with
              Messages = chatMessage :: model.Messages },
        Cmd.none
    // ... more message handling

And with that, the user will be able to send and receive chat messages with whoever is using the chat program at the current moment.

Conclusion

And that is how we can use SignalR in a Fabulous app and create a Fabulous Chat app. Perhaps we still have to go over the design and security to really earn that name .

What you also saw is how you can work with events that do not originate from the user's input but happen in the background. This technique can be used whenever you are using some code that gets invoked in the background while your app is doing other fabulous stuff.

You can find the complete sample of the app on GitHub.

Titlephoto by Tyler Lastovich from Pexels

0 Comments

TitleImage

A while back, I used the F# type providers to create a conversion table. That post gave me the idea if it were possible to write an app that gets its data from a website. Perhaps you have also received the request for an app. Nothing expensive and actually all the data that should be displayed is already present on the web, i.e. this website right over here. So the question is: Could such an app be created without having to write a single line of backend code?

In this blog post, I will try to create an app for one of my favourite Xamarin conferences - the Xamarin Expert Day. So let's see if we can create our Fabulous Xamarin Expert Day App.

Getting the data

Type providers are a delightful feature of F#. During compilation type providers generate the data models represented in a data source. I have written a blogpost before on the topic of parsing HTML. This time we will use another toolset that comes with the F# Data NuGet package.

Since we want to get the information about the Xamarin Experts Day conference, we can try parsing the website directly. So we could use the following line to do this:

HtmlDocument.Load "https://expertday.forxamarin.com/"

Unfortunately, we live in the modern ages of JavaScript. I don't want to go on a tangent here, but just state the fact that the Xamarin Experts Day website seems to be loading the information about the talks and the tracks after the initial HTML has been loaded. Luckily when loading the page in a browser, we get an HTML version which contains all of the information we are looking for. So instead of loading the data directly from the website, we can load the data from a file. Budget projects have their limitations... 🙃

HtmlDocument.Parse("ExpertXamarin.html")

When we look at the HTML of the website (in the browser) we can see that the speakers are listed under the following HTML structure:

<li data-speakerid="df2bc5ca-5a6b-48a9-87ac-71c817d7b240" class="sz-speaker sz-speaker--compact ">
<div class="sz-speaker__photo">
  <a href="#" onclick="return ...');">
    <img src="...894db1.jpg">
  </a>
</div>
<h3 class="sz-speaker__name">
  <a href="#" onclick="return ...');">Mark Allibone</a>
</h3>
<h4 class="sz-speaker__tagline">Lead Mobile Developer Rey Automation, Microsoft MVP</h4>
</li>

So we know that we can get the image, name, tagline and id of every speaker. So let's create a record to store that information:

type Speaker = {Id:string; Name:string; Photo:string; Tagline:string}


Creating the record is not strictly necessary. But it does make working with the data a bit easier later on. Another plus is that we could capsule the type provider code in a .Net Standard library and then share it with non F# .Net code. No, you can't access type provider data types directly from C# and while some features in C# get inspired by F#. From what I have heard, I would not hold my breath, hoping to see type providers in C# anytime soon...

With the record in place, all that is left to be done is extracting the data from the HTML. Good thing that F# Data comes along with the HTML CSS selector. The HTML CSS selector allows filtering after ids, classes and tag types. So if we wanted to get the speakers name, we can filter the component and then extract the value as follows:

// .. other parsing methods
let private getName (htmlNode:HtmlNode) =
    htmlNode.CssSelect("h3.sz-speaker__name > a") |> Seq.map (fun h -> h.DirectInnerText()) |> Seq.head

let getSpeakers (html:string) =
    HtmlDocument.Parse(html)
        .CssSelect("li.sz-speaker")
        |> Seq.map (fun s -> {Id = (getId s); Name = (getName s); Photo = (getPhoto s); Tagline = (getTagline s)})

Similarly, the rest of the data can be accessed to fill the other fields in our record. Same goes for the tracks, again we would first create a record where we store the name, time, room and speaker id of every track. We will be able to link a track to a speaker with the id:

type Track = {Room:string; Time:string; Title:string; SpeakerId:string option}

let getTracks (html:string) =
    HtmlDocument.Parse(html)
        .CssSelect("div.sz-session__card")
        |> Seq.map(fun s -> {Room = (getRoom s); Time = (getTime s); Title = (getTitle s); SpeakerId = (getSpeakerId s) })

Now that we have all the data in place, it is time to get cracking on the app.

Fabulous Xamarin Experts App

Before we start writing our UI code, there is still that shortcut we took above with loading the information out of a file. While this works great when using a script in the mobile world, this means we have to pack that HTML doc into the app. There are two approaches: either put it into the Assets folder on Android and in the Resources folder (you can also use XCAssets...) on iOS or make an Embedded Resource in the .Net Standard library. While the first option would be what Apple and Google intended you to use when adding docs, you want to ship with your app. You will have to jump through some hoops to access the document. So let's again save some time and just pack the file as an Embedded Resource in our .Net Standard project. Embedded Resources are packed into your apps binary. This results in an awkward fashion of accessing the data. While described in the official docs here, this is how it is implemented in the Xamarin Experts Day Conference App (we need a shorter name...):

let loadFile filename =
    let assembly = IntrospectionExtensions.GetTypeInfo(typedefof<Model>).Assembly;
    let stream = assembly.GetManifestResourceStream(filename);
    use streamReader = new StreamReader(stream)
    streamReader.ReadToEnd()

With that out of the way. Let's create a list of all the talks with the title, time and room. When selecting a track, we will display the Information of the presentation along with the speaker info.

So the list we can put together like this:

let showTrackCell track =
    View.ViewCell( view =
        View.StackLayout(children = [
            View.Label (text = track.Title, 
                        fontSize = FontSize 22.)
            View.Label (text = track.Time + " in " + track.Room, 
                        fontSize = FontSize 14.,
                        fontAttributes = FontAttributes.Italic)
            ]))

let view (model: Model) dispatch =

    View.ContentPage(
        content = match model.SelectedTrack with 
                    | Some track -> showTrackInfo track model dispatch
                    | None -> View.ListView(
                                    rowHeight = 80,
                                    hasUnevenRows = true,
                                    margin = Thickness(8.,0.,0.,0.),
                                    items = (model.Tracks |> List.map showTrackCell),
                                    selectionMode = ListViewSelectionMode.Single,
                                    itemSelected = (fun args -> dispatch (TrackSelected args))
                                    )
        )

And the "detail view" would be done like this:

let showTrackInfo track (model:Model) dispatch =
    let speaker = match track.SpeakerId with
                  | Some speakerId -> model.Speakers |> Seq.tryPick(fun s -> if s.Id = speakerId then Some s else None)
                  | None -> None

    let addSpeakerInfo (speaker:Speaker) =
        View.StackLayout(margin = Thickness(0.,32.,0.,0.), children = [
                View.Label (text = "Speaker", fontSize = FontSize 22. )
                View.Image (source = (Image.Path speaker.Photo))
                View.Label (text = "Presenter: " + speaker.Name)
                View.Label (text = "Tagline: " + speaker.Tagline)
            ])
        
    let speakerViewElements = match (speaker |> Option.map addSpeakerInfo) with
                              | Some speakerInfo -> speakerInfo
                              | None -> View.Label(text = "Brought to you by the Organizers");

    View.Grid (margin = Thickness(8.,8.,8.,16.),
                rowdefs = [Star; Auto],
                children = [
                    View.StackLayout(children = [
                        View.Label (text = track.Title, fontSize = FontSize 22.)
                        View.Label (text = "In: " + track.Room, fontSize = FontSize 14.)
                        View.Label (text = "At: " + track.Time, fontSize = FontSize 14., margin = Thickness(0.,-4.,0.,0.))
                        speakerViewElements
                        ])
                    (View.Button (text = "Back", command = (fun () -> dispatch (TrackSelected None)))).Row(1)
                ])

You might have noticed that the talk description is missing. The website has a JavaScript function retrieve that additional information. I think it would be possible to replicate the JavaScript call to the backend and then parse through the answer

JSON/HTML answer. But INSERT-LAME-STATEMENT-WHY-I-AM-NOT-LAZY-HERE.

The app still feels a bit ruff I think I might have to follow up in another blog post and make it pretty 😎

Conclusion

In this little experiment, we set out to see if it would be possible to write a mobile app that displays the same information as already present on a website. And while there were some bumps in the road - I am looking at you JavaScript. It was indeed possible to write an app for the Xamarin Experts Day that runs on Android and iOS.

Though I really should get started on my next post and make the app pretty 😇

You can check out the entire app on GitHub.

This post is part of theF# advent calendar. Be sure to check out the other posts.

HTH

1 Comments
  •   Posted in: 
  • F#

A picture containing colour crayons

I recently was faced with the task to render RAL Colours on an app that I was developing. RAL Colours are used mainly in industrial colour appliances - i.e. powder coating. So while well known in the powder coating industry it was quite an exciting read on Wikipedia to find out how RAL colours came to life. The good thing is that there is a finite set of classic RAL colours. Even better there is a table on Wikipedia which contains a good enough approximation for the classic RAL colours.

So instead of copy & pasting the table into an editor and slashing away at the data. I was wondering if there would be a better way to extract the information from the website. And store the data in a more handy form such as a JSON file.

In the last couple of months, I have been dabbling with F# in my free time. Data providers are a powerful tool which is available in the F# language. In short, you can point a data provider at a data source, and during compilation, the types used in that source get generated for you. So for your typical JSON response from a website. You can use the JSON type provider to create a type based on that stream which you then can use throughout your F# program. Now, this is a more than your "create a C# POCO from JSON" Visual Studio feature. You also get methods to slice and dice through your data. In other words, it is an excellent tool for exploring new data sources or just parsing new data sources and processing that data.

As with LINQ extensions it is is possible to write your type providers. But for most general use cases the type provider already exists and can be added to your project as a NuGet package. The NuGet package we will be using is the FSharp.Data which provides type providers for JSON, XML, CSV and HTML (plus the World Bank ‍🤷‍♂️).

Using an F# script, we will first have to reference the type provider:

#I "./packages"
#r "FSharp.Data/lib/netstandard2.0/FSharp.Data.dll"

open FSharp.Data


Side note: I am using paket for my dependency management because it installs the package right into the project folder. You do not need to use paket, but you will have to make sure that the #r ... line points to the dll.

Now type providers create a type based on a data source. In our case I can point it at the Wikipedia website listing all the RAL colours:

type wikipedia = HtmlProvider<"https://en.wikipedia.org/wiki/List_of_RAL_colors">

We could have also provided a local file:

type wikipedia = HtmlProvider<"list_of_ral_colors.html">

The local file is excellent if you do not always want to hit the remote site. But you run the risk of having an older version locally than on the server which can lead to ugly problems. As far as we are concerned for the script. I will point it at Wikipedia and be sure to make my again annual donation at the end of year

In the JSON file, we will want to store the RAL, RGB and colour name. So let's create a record type for that quickly:

type ralColor = { ral: string; hex: string; name: string}

Now that we have our types, we are all set to extract that data. By looking at the website, we can see in which section the table is located:

Picture showing part of the Wikipedia RalColor List

Knowing this location, we can scan the site and hone in on the data we are looking for:

let ralColorSection = wikipedia.Load("https://en.wikipedia.org/wiki/List_of_RAL_colors")
                                .Tables
                                .``All RAL Colours in a single listing``

If you have never used type providers, you will be probably reading the lines above and go: "Okay... I guess..." - so let's just quickly look at what happened underneath those lines of code. As the name suggests, type providers provide a type based on a data source. This is where we nod. So what do we get with the lines above? We get a type which represents the table of RAL colours. We can access all of the rows via ralColorSection.Rows. When iterating over each row we can read the value in a column by using its name. So we could print out all colour names as follows:

ralColorSection.Rows |> Seq.iter (fun r -> printfn "%s" r.``Colour name``)

I know this is freaking cool right! So if we wanted to extract the RAL, RGB and name from the table we could use our previously defined type and the values as follows:

let ralColors = ralColorSection.Rows
                    |> Seq.map((fun r -> 
                        {ral = r.``RAL Number``; 
                            hex = r.``HEX Triplet``; 
                            name = r.``Colour name``}))

Note the two ticks are how F# variables with spaces in them can be accessed. Now we have all the data we wanted. So now all that is left to do is the boring bit of storing it into a JSON file:

#I "./packages"
#r "Newtonsoft.Json/lib/netstandard2.0/Newtonsoft.Json.dll"

// ...

open Newtonsoft.Json

// ...

let writeToJsonFile ralColors =
    let filePath = Path.Combine(__SOURCE_DIRECTORY__, "ral_colour_map.json")
    let jsonString = JsonConvert.SerializeObject(ralColors)
    File.WriteAllText(filePath, jsonString, Encoding.UTF8) |> ignore

And that wraps up this blog post. I hope you have seen that F# 's type providers can be a great way to scan through data sources and extract the information you need. One thing to be aware of when using type providers: You can't directly share the generated type with other .Net languages such as C#. You would have to wrap the data in a record type - by the way: the type we created to hold the subset of data is a record type. So while there might be some additional effort up ahead when writing fully-fledged enterprise applications, they are a no brainer for scripting. And will provide you with a significant productivity boost when exploring new datasets.

Be sure to check out the official documentation on the HTML provider used in this post. As always you can find the entire code on GitHub.

HTH

0 Comments

Showing a wodden peer and the ocean on a sunny day

Fabulousallows writing Xamarin Forms apps with F#in a functional style. Fabulous has been inspired byElm, which proved that by using the Model View Update (MVU for short) pattern functional languages are great for writing UI code. While functional code squashes a plethora of potential bugs around null and race conditions - in this post, we will not focus on that aspect of Fabulous. Instead, let us look at how you can create beautiful UIs that stay maintainable in the future.

This blog post is part of the Xamarin UI July organised bySteven Thewissen. Be sure to check out all the beautiful posts by myfellow co-authors.

Featured #XamarinUIJuly Badge

Inspired by some of Stevens previous posts on - what I like to call - lickable UI. I wanted to show why writing UI in code allows you to write UI that is not only beautiful but easy to maintain and extend. So for this post, I will be implementing a design idea I found onDribbblebyApptaste.

App design as shown on dribbble

Though this blog post will focus on Fabulous, you could apply the same principle when writing your app using C#and XAML. But you will end up with a bunch of files, and it will feel more complicated. F#a terse language to write to begin with and Fabulous allow for writing apps with fewer lines of code than what you usually require with C#and XAML. I am not saying this is what should be your reason to check out Fabulous. But it is a fact that... If you are new to F#and Fabulous next comes a short intro. If this is all old news to you feel free to skip the intro.

A short intro to Fabulous

Let's start with the good oldWelcome to Xamarin Formsblank app:

module App = 
    type Model = 
      { Message : string } // your apps state, we could do without...

    type Msg = 
        | SomeStateChange // just for the demo, we do not need this...

    let initModel = { Message = "Welcome to Xamarin.Forms!" }

    let init () = initModel, Cmd.none

    let update msg model =
        match msg with
        | SomeStateChange -> model, Cmd.none

    let view (model: Model) dispatch =
        View.ContentPage(
          content = View.StackLayout(
            children = [ 
                View.Label(text = model.Message, horizontalOptions = LayoutOptions.Center, verticalOptions = LayoutOptions.CenterAndExpand)
            ]))

    // Note, this declaration is needed if you enable LiveUpdate
    let program = Program.mkProgram init update view

type App () as app = 
    inherit Application ()

    let runner = 
        App.program
#if DEBUG
        |> Program.withConsoleTrace
#endif
        |> XamarinFormsProgram.run app

Yes, this is all the code you would usually have in your blank C#app. We will not go into too much detail on how all the functions work. At the bottom, you can see thetype App, which translates to theApp.xaml.csclass, i.e. the entry point of any Xamarin Forms app. Our analogue to theMainPageis themodule App. The three components of the MVU pattern are present with theModel(an F#record, if your new to F#think of it as a POCO, not quite the same but close enough for now) and theviewandupdatefunctions.

The update function is where all changes of the view are processed. Displaying only text this function has nothing to do really. Since we will be focusing on the UI later, I will give you a short intro to what the update function does in your average app. Imagine all your UI changes and background task events must gosequentiallythrough this point. All state changes are defined. You can reproduce every state of the app - oh and no race conditions

The view function contains theContentPage, which includes aStackLayoutand aLabel. At first, you might not think much about it. But look how terse it is written. For example, theStackLayoutchildren, that is a simple list in F#. So adding another element to the grid would be simply adding a new UI element.

The functions get invoked by Fabulous and do not interact with Xamarin Forms directly. This is important to understand because this means that all of the code you write can be 100% unit tested. All the dependencies to the view are resolved within the Fabulous framework. Theviewfunction returns the instructions on how to create the UI, but it does not create it. If you change a value such as the welcome message, the Fabulous Framework checks what parts have changed and updates the view accordingly. The React.JS framework uses the same technique with a shadow DOM (Document Object Model) that is then taken to update the actual UI.

Atomic Design and coded UIs

Writing your UI with code comes with a few perks. While you could write all of your UI in theviewfunction. It might get a bit hard to view at a glance over time. But being only code, you can split up the code into different functions. This also allows you to reuse parts of the UI in different places. And reusability reusing/combining components is at the heart of Atomic Design.

Atomic Design

While unique design, reusable components sound all great, let's have a look at how we could design such an app with Fabulous. We want to start with the essential elements (Atoms) which we then put together to more significant UI components and in the end the Page.

When we look at the design of the app, we can see that most of the title labels seem to have the same font. Another UI component that quickly gets my eye is the cards holding the description of the destination and the things to do:

DestinationDescription

Now what we can see is that titles have the same font, are bold and apart from the cards in the"Things to do"section have the same font size. So let's create a function that allows us to create a title label with the parameters text and font size:

let titleLabel text fontSize =
    View.Label(text = text,
        fontSize = fontSize,
        textColor = textColor,
        verticalOptions = LayoutOptions.Center,
        fontAttributes = FontAttributes.Bold)

The destination is shown by a picture (gorgeous pictures if I may say so! ) and a short description of the town, country, rating and a favourite It seems that the favourite should be clickable so let's assume that is a button. Probably similar to the search button on the top right. Keeping accessibility in mind, I prefer to use buttons or platform interactive controls in general if an interaction is required by the user. This way, it will be easier to optimize the experience using a screen reader. So we want a button with an icon - or a text. Since Xamarin Forms allows us to use custom fonts, we could use a font such asFont Awesometo provide us with scalable icons. Be sure to check outJames'poston how to use Font Awesome with your Xamarin Forms app. So let's create a function that given the icon, colour, background colour and command function returns us with the button:

let materialFont =
    (match Device.RuntimePlatform with
                             | Device.iOS -> "Material Design Icons"
                             | Device.Android -> "materialdesignicons-webfont.ttf#Material Design Icons"
                             | _ -> null)

let materialButton materialIcon backgroundColor textColor command =
    View.Button(text = materialIcon,
        command = command,
        fontFamily = materialFont,
        fontSize = 20.,
        backgroundColor = backgroundColor,
        widthRequest = 42.,
        textColor = textColor)

So now to the description text i.e. the country. Lets again create a function that will create a label given the text:

let descriptionLabel text =
    View.Label(text = text,
        textColor = secondaryTextColor,
        fontSize = descriptionFontSize
        )

Did you notice the title and description pattern is repeated in the"Things to do"section of the page. Up to now we have created what Atomic Design calls Atoms. Now let's pack some of those atoms into a coherent block such (Molecule):

let titleAndDescription title titleFontSize description =
    View.StackLayout(margin = 0.,
        children=[
            titleLabel title titleFontSize
            descriptionLabel description |> fun(label) -> label.Margin (Thickness(0.,-8.,0.,0.))]

This will allow us to reuse the Title & Description duo further. Also, note that we had to adjust the margin a bit. You can think of the|>as a pipe forward. Since we have a View type, we can pipe it forward to a lambda function where we change the margin. Calling the margin function will again return a View type. If you are using LINQ, you most probably have joined multiple calls to where select et al. - we are doing the exact same thing here.

Now looking back at the short description of the destination, we can also see a rating of the city with stars. So let's create a function that given the icon and text colour returns aLabelbased on font awesome.

let materialIcon materialIcon color =
    View.Label(text = materialIcon,
        textColor = color,
        fontFamily = materialFont,
        fontSize = 18.,
        verticalOptions = LayoutOptions.Center,
        fontAttributes = FontAttributes.Bold)

The rating bar - I assume it is a read-only indicator that shows me an overall rating between zero to five. Given a rating of 4.5, we want four full stars and one covered by half. So let's take this control apart, let's say we want one function that only draws the star for a certain percentage:

let ratingStar percentage =
    let star = materialIcon star starColor
    let boxViewWidth = 16. - (16. * percentage)
    View.Grid(
        padding = 0.,
        margin = Thickness(0.,-4.,0.,0.),
        children = [
            star
            View.BoxView(color = backgroundColor, 
                widthRequest = boxViewWidth,
                isVisible = (if percentage > 0. then true else false),
                horizontalOptions = LayoutOptions.End)
            ])

The function aka star factory is called by another function that draws N stars given the rating:

let ratingControl (rating:decimal) =
    let fullNumber = Math.Ceiling(rating)
    let fraction = (rating - Math.Truncate(rating))
    View.StackLayout(orientation = StackOrientation.Horizontal,
        children = [
            for i in 1m .. fullNumber -> if i = fullNumber then ratingStar (float fraction) else ratingStar 1.
        ])

Now we have all of our building blocks together for the description, but we still have the image with rounded corners left. A quick look at theImageViewfrom Xamarin Forms tells us:"No rounded edges."But when putting the image in aFrame, we can create the rounded edges effect. So let's create a function that gives us an image with round corners:

let roundedCornerImage imagePath =
    View.Frame(cornerRadius = cornerRadius,
        padding = 0.,
        isClippedToBounds = true,
        hasShadow = true,
        content = View.Image(
            source = imagePath,
            aspect = Aspect.AspectFill)
    )

The parts are all made now let's assemble them so that we get the Image with rounded corners overlaid by a short description:

let cityDescriptionFrame city dispatch =
    View.StackLayout(
        margin = Thickness(16.,0.,16.,0.),
        children = [
            (roundedCornerImage city.Image |> fun(img) -> img.HeightRequest 320.)
            View.Frame(
                heightRequest = 70.,
                margin = Thickness(24.,-64.,24.,0.),
                padding = Thickness(20.,12.,16.,12.),
                backgroundColor = Color.White,
                cornerRadius = cornerRadius,
                content = View.Grid(
                    rowdefs=["auto"; "auto" ],
                    coldefs=["*";"auto"],
                    children=[
                        (titleAndDescription city.Name titleFontSize city.Country)
                        (favoriteIcon city dispatch).GridColumn(2)
                        (ratingControl city.Rating).GridRow(1).GridColumnSpan(2)
                        ]
                ),
                hasShadow = true)
        ])

Similarly, we can implement the"Things to do"section. The great thing is we can reuse a lot of components that we have already created. Then we can put all the parts together in the view method which presents us with the following UI:

AppScreenshot

You can find the entire sample onGitHub.

Side notes: No, we are not required to have all the code in one file. But since this is a one-pager application, I left it together, so it is easier to navigate the code in a browser. Further note that theCarouselViewdid not work correctly when I was working with the view. I hope I will be soon able to get it working and have a sample which will allow switching between cities as intended by design.

Conclusion

Applying the Atomic Design pattern to your UI can really make your app easier to maintain and create. Given that Fabulous allows writing your UI in code, it is relatively straight forward to create a custom and consistent UI without much boilerplate code. Further Fabulous offers a live update feature which allows you to live code during a debug session. Not only does the UI adapt, but also the logic is executed. You can read more aboutthe live update featureon the official site.

It seems that writing UI with code is coming back into style during the recent days of 2019. With companies like Apple working on Swift UI. If you are a die-hard C#lover, you should check out thePost by Ryan Davison writing UIs with C#for Xamarin.

You can read more about the Atomic Design pattern onBrad Frosts website.