Monthly Archives: March 2020

Text to Speech on mobile with Xamarin

Previously I looked at Speech synthesis in Windows with C# but what about speech synthesis on mobile.

Xamarin.Essentials has this covered with the TextToSpeechTextToSpeech class and is included by default when creating a Xamarin Forms mobile application.

It’s really simple to add text to speech capabilities, we simply write code such as

await TextToSpeech.SpeakAsync("Hello World");

As you can see by the use of the await keyword (and the standard Async suffix), the SpeakAsync method returns a task. It also accepts a cancellation token if you need to cancel mid utterance. There’s also an overload which accepts SpeechOptions which allows us to set the volume, pitch and locale.

The second TextToSpeech method is GetLocalesAsync which allows is to get a list of supported locales from the device that can then be used within the SpeakAsync method’s SpeechOptions.

await TextToSpeech.GetLocalesAsync();

Note: It’s fun listening to the attempts at different accents depending upon the locale.

Changing the date/time on the Tizen emulator

To set the date/time on the Tizen emulator

  • Obviously ensure you have the emulator running
  • Right mouse click on the emulator
  • Select Shell
  • Type su to switch to super user or you’ll get an “Operation not permitted” error
  • The default password is tizen
  • Type date –set=”27 Mar 2020 23:59:45″ and press enter
  • Tizen is a Linux based OS, hence we can use Linux commands in the shell.

Adding a Tizen project to Xamarin Forms

The great thing about creating a Xamarin Forms project is that you can create projects for Android, iOS and UWP at the same time, but there’s no options for Tizen.

Assuming we’re installed the Tizen Visual Studio templates, then it’s easy to add Tizen to an existing Xamarin Forms project and have it use the shared code project.

Assuming you’ve already created a Mobile App (Xamarin.Forms) application (mine’s called MyProject) and selected Android, iOS and UWP, now…

  • From File | New | Project select the Tizen XAML App (Xamarin.Forms) project, name the project along the lines of MyProject.Tizen
  • After you click Create you’ll be presented with the Tizen Project Wizard
  • Select Common (if not already selected) and leave Mobile, TV etc. options unchecked
  • Select the option Select Project in Solution and choose the shared project name, i.e. ours is MyProject
  • Click OK

Now you’ll see the Tizen project and it’s already set up to use your project’s shared code. So we can write our XAML for all four platforms. Obviously if we’re aiming to deploy to a watch (for example) we’ll need to optimise the XAML for this type of device. We use OnIdiom, for example

FontSize="{OnIdiom Watch=Small, Phone=Large}

and we’re done.

Custom Fonts in Xamarin Forms

First off, this post Fonts in Xamarin.Forms is a far more complete description of all things font related in Xamarin Forms than this post will be, so go check it out.

In this post I’m just going to discuss how we can add and use “custom” fonts, i.e. fonts not on a device by default.

Custom Fonts

In this instance a custom font simply means a font that’s not, by default, loaded onto a device.

We can find lots of free fonts etc. via Google Fonts.

As per the previously mentioned Microsoft/Xamarin post, we’ll demonstrate things using the Lobster-Regular.ttf font.

Within Google Font simply search for Lobster and then download the Lobster.zip to your machine. If you then unzip this file you’ll have two files, the .ttf and a license file.

To look at the font and/or to get the Font name, in Windows we can right mouse click the .ttf file and select Preview. Hence we see the following

  • Font name: Lobster
  • Version: Version 2.100
  • OpenType Layout, TrueType Outlines

We also see a sample of the font for the alphabet, but more interestingly a sample for different font sizes, 12, 18, 24, 36 etc.

Preview Feature

Within the previously mentioned post they talk about adding your custom font to the shared project of your Xamarin Forms application. This was a preview feature and at the time of writing this post, I was unable to see this work. Hence this post will be out of data as soon as this is implemented. However for completeness I’ll relay what the post says on this.

To add a custom font to your shared project…

  • Create a Resources/Fonts folder (this folder configuration isn’t a requirement)
  • Add your .ttf or otf font files to this new folder and mark their properties as Embedded Resource
  • In the AssemblyInfo.cs file (for example) ad the ExportFont attribute, for example
    using Xamarin.Forms;
    
    [assembly: ExportFont("Lobster-Regular.ttf")]
    
  • Using the font is then as simple as writing the following

    <Label Text="Hello Xamarin.Forms"
       FontFamily="Lobster-Regular" />
    

    Existing/non-preview usage

    So, as mentioned, I was unable to get the preview working at this time, so let’s look at the “current” way to implement custom fonts. Let’s therefore assume we did not do any of the Preview steps.

    For Android…

    Copy your .ttf or .otf files into your Android project’s Assets folder and mark them as AndroidAsset via the file’s properties option in Visual Studio.

    Now it the shared project we need to reference the font slightly differently

    <Label Text="Hello Xamarin.Forms"
       FontFamily="Lobster-Regular.ttf#Lobster Regular" />
    

    For iOS…

    Copy your .ttf or .otf files into your iOS project’s Resources folder and mark them as BundleResource via the file’s properties option in Visual Studio.

    There’s and addition step, where we need to add the font(s) to the info.plist, i.e.

    <key>UIAppFonts</key>
    <array>
        <string>Lobster-Regular.ttf</string>
    </array>
    

    The big difference to the Android example is that the code only has the typeface name, for example

    <Label Text="Hello Xamarin.Forms"
       FontFamily="Lobster-Regular" />
    

    For UWP…

    Copy your .ttf or .otf files into your UWP project’s Assets folder and mark them as Content via the file’s properties option in Visual Studio.

    As per the Android example, the code would look like this within the shared project

    <Label Text="Hello Xamarin.Forms"
       FontFamily="Lobster-Regular.ttf#Lobster Regular" />
    

    Different fonts for different OS’s

    As you’ve seen in the examples for setting the FontFamily attribute, Android and iOS differ in what they expect, so we’re going to need a better way to supply this value. Or it may be we actually want different font’s on different devices.

    We can create a style and use OnPlatform capabilities of Xamarin Forms to achieve this.

    i.e. in this example we’ll set the fonts

    <ResourceDictionary>
      <OnPlatform x:TypeArguments="x:String" x:Key="LabelFont">
        <On Platform="Android" Value="Lobster-Regular.ttf#Lobster Regular" />
        <On Platform="UWP" Value="/Assets/Lobster-Regular.ttf#Lobster Regular" />
        <On Platform="iOS" Value="Lobster-Regular" />
      </OnPlatform>
    </ResourceDictionary>
    

    and then we can change our Label sample code to the following

    <Label Text="Hello Xamarin.Forms"
       FontFamily="{StaticResource LabelFont}" />
    

    Sample Project

    See https://github.com/putridparrot/blog-projects/FontTestApp

Creating an Android Virtual Device

Whilst running Android applications on a real device is pretty quick nowadays, it’s still useful to run our apps against an emulator.

In this post we’re going to look at creating an emulator which works/looks like a Samsung s10e.

Device information and skins

In the case of Samsung devices, simply visit Samsung, Emulator Skin Overview.

Here you can find skin downloads (to give your emulator more of a look of the device) along with device information, such as screen size, resolution etc. Download the skin.

Note: You’ll need to be registered on the Samsung developer site to download the skins, but it’s a painless process.

In the case of the s10e, the device has a 5.8 inch display and a resolution of 1080×2280. So we’re put that information into our virtual device in a minute, before we do that, extract the downloaded skin into the following folder

%USERPROFILE%\AppData\Local\Android\Sdk\skins\samsung_s10e

Now we’re got all the relevant skin related files let’s move onto creating our virtual device.

Android device manager

From Visual Studio or Android Studio, locate the button to run the Android Device Manager. In either case either press New… or Create Virtual Device…

To save trying to describe both UI’s I’m going to stick with the Android Studio UI. So after click on Create Virtual Device, do the following

  • Click New Hardware Profile
  • Set Device Name to Samsung S10e
  • Ensure Device Type is Phone/Tablet
  • Set screen size to 5.8
  • Set Resolution to 1080 x 2280

Leave all other options as they are but now scroll down to the Default Skin option. Clicking on the … button does nothing until you switch from No Skin to select a skin, any skin will work. Don’t worry if you get a warning about the skin not being the right size as we’re going to change it now. Click on the … button and locate the samsaung_s10e folder we put the skin files into.

Finally, click Finish.

  • With the new device selected, press the Next button
  • Currently the s10e is running Android Pie API Level 28, so select this or your preferred version of Android
  • Press Next and if all looks good, then press Finish

If you need to edit the configuration you can do so via the Android Virtual Device Manager, you’ll need to select the device and then click the edit button. You’ll need to click the Show Advanced Settings button to change memory, or if you wish to change the skin.

Multilingual App Toolkit (MAT)

I’ve previously looked at the MAT in the post Adventures in UWP – Globalization & Localization UWP – Globalization & Localization. I’ve also used this within mobile applications using Xamarin Forms which I was about to update, but then realised I’d forgotten how this stuff worked.

Requirements

Before we start, we need to install a couple of things.

  • From Visual Studio 2019 (if not already installed) select Extensions | Manage Extensions and download the Multilingual App Toolkit. You’ll need to restart Visual Studio for the installation to take place.
  • Install (if not already installed) the Multilingual app toolkit 4.0 Editor as this is extremely useful for managing our translated files, but is NOT required.

Note: This does not currently seem to be supported in Visual Studio for Mac.

Mobile Application

Let’s start by creating a Xamarin Forms application to see how things work.

  • Create a Mobile App (Xamarin.Forms) in Visual Studio
  • Add a Resources folder to the shared project and then add a Resource File item to this folder, named AppResources.resx
  • Right mouse click on the shared project and select Properties, now select Package and towards the bottom of this screen, change the Assembly neutral language to your default language – for example mine’s English (United Kingdom). In other words our project culture will be set to en-GB
  • Enable MAT by selecting Tools | Multilingual App Toolkit | Enable on your solutions

At this point we now have the basics in place to begin localizing our application. We can now start adding strings to our AppResources.resx or alternatively we could start adding new languages, so let’s do that.

  • Right mouse click on your shared project and select Multilingual App Toolkit and from this select, Add translation languages…

Note: You may get and error regarding the need to install translation providers, this requires us to add an Azure subscription, but we don’t actually need this to use the tools, so just ignore this error for now.

From the Translation Languages check on any languages you want to support (you can also add languages at any point so don’t worry if you need to add more at a later date).

In my case I’m going to add German [de] and French (France) [fr-FR]. Once you press OK you’ll see two additional AppResources files added to the Resources folder, AppResources.de.resx for German and AppResources.fr-FR.resx for French.

You’ll also see the MultiligualResources folder with two .xlf files, one for German and one for French, these are used by MAT to generate our new AppResources files.

Note: Do not edit the localized AppResources.*.resx files by hand. Only AppResources.resx should be edited.

Editing our resources

Now that we have the xlf files and the default culture AppResources.resx file, we’ll want to start adding some strings.

Open the AppResources.resx file in Visual Studio and add some named strings, the Name being the identifier or key, the Value being the string to display and we can also add comments which might be useful for somebody who handles the subsequent translations.

So I’m going to create a basic login page, hence we’ll add the following

  • Name: Welcome, Value: Welcome to the application
  • Name: Login, Value: Login
  • Name: Username, Value: Username or email address
  • Name: Password, Value: Enter your password

Now build your application before we look to create some translations.

There’s a couple of ways to proceed with this, the simplest is as follows

  • From Visual Studio. Select you MultilingualResources folder or each .xlf in turn.
  • Right mouse click on the folder or file then select Multilingual App Toolkit | Generate Machine Translations.

You may find that some values are not translated, for example in my case Welcome to the application was not translated, we can edit the de.xlf file directly. In this case I change the target element to Willkommen bei der Anwendung and changed the target state to needs-review-translation

Once you’ve made your changes then build the project and MAT will generate the AppResources.*.resx files.

The second way to handle the translations and probably one that would be useful for people who are working on translations of your application. In this case we use the Multilingual Editor that was installed earlier. Open each of your xlf files in turn. For each one we’ll see a list of the strings as entered into the AppResources.rex file. So let’s concentrate on editing the .de.xlf German translation file.

  • Having opened the .de.xlf file, select the Strings tab at the bottom of the screen to ensure all the strings were added, now here we could manually translate each row by selecting the each row in turn, then changing the Translation in the editor in the middle of the editor UI.
  • If you edit the translation yourself then the State on the right of the screen will switch to Translated. This state will tell the MAT editor whether it should try to translate the value. If the user has marked the state as Translated we can assume this is correct and the editor will not attempt to translate the string using it’s generate translation option. You can change this State back to New if you want the auto-translation to take place.
  • If you prefer or like me you’re simply going to use something like Bing or Google to do the translations, i.e. https://www.bing.com/translator/. Then the Editor offers the Translate button. Clicking this will generate translations for all the text and mark them with the State Needs Review which is basically saying that the translation was made but needs somebody to review whether this makes sense in each language. You can leave this State as is or change to Translated if you’re happy with these translations.
  • Once completed, save the file(s) and build your solution to get the AppResources.*.rexr updated.

Displaying our translations in an application

Note: This post has been updated as the previously used Multilingual plugin is no longer required.

We can display translations is XAML using the AppResources generated code, for example

Title="{x:Static resources:AppResources.Settings}

and in code just as easily we use

var title = AppResources.Settings;

To test your translations you can set things up in code, i.e.

In your App.xaml.cx, after the InitializeComponent you can place the following code to set the culture to that of the device

var culture = CrossMultilingual.Current.DeviceCultureInfo;
AppResources.Culture = culture;

If you want to test your German translation, for example, replace these two lines with

var culture = new CultureInfo("de");
AppResources.Culture = culture;
CrossMultilingual.Current.CurrentCultureInfo = culture;

See https://github.com/putridparrot/blog-projects/tree/master/MatTestMobile for a sample application.

If you prefer to use the Android Emulator to set your language – which ofcourse makes a lot of sense, then go to Android Settings | System | Languages & input | Languages then Add a language if the one you want is not listed, then drag and drop that language to the top of the Languages list and Android will switch to that language.

Application lifecycle within Xamarin Forms

You’ve got your Xamarin Forms (or native Android/iOS) application up and running and now you need to start thinking about what happens when your application hibernates.

An application can go into hibernation (or sleep mode) and then resume at some point. The OS hibernates an application in response to events, such as power off or lock screen but also if it’s running low on memory. Therefore, so that our application “places nicely” on the OS, we need to think about how we will persist state and restore state during this hibernation phases.

Let’s look at the various methods in Xamarin Forms for handling different aspects of the application’s life cycle…

Xamarin Forms

Initialization/Starting

By default a Xamarin Forms application will create an OnInitialized method which is basically where the InitializeComponent method is called. It’s a good place to set up any initialization for your UI elements etc.

Assuming we’re starting our application from cold (i.e. first start) Then the following lifecycle methods are called in order

  1. OnInitialized
  2. OnStart

According to the App Lifecycle documentation “On Android, the OnStart method will be called on rotation as well as when the application first starts, if the main activity lacks ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation in the [Activity()] attribute”.

So OnInitialized remains the best place to set defaults up, but OnStart may be the best place to make any UI changes based upon orientation etc.

Entering sleep mode

If the device goes into sleep mode (we can simulate easily by hitting the power button on our emulator or device). The following is called

  1. OnSleep

This is our opportunity to persist state from the device so that when we resume the application it’ll appear in the same state as when it went into sleep mode.

There’s various ways to achieve this, if we’re using a pure MVVM approach with Prism (for example) we might use the EventAggregator to send a sleep message to all listening view models etc., which would then persist their data, or maybe we hold a cache (or similar) as a single data store and we persist this. Whichever way we go, the intention is that everything that is required to get the application back to the state pre-sleep, needs persisting. This also includes things such as which view (in a multiple view application) is displayed along with things like the view stack – well you get the idea, it depends how far you want to go to recreate the state of your application.

Note: another useful way to deal with view model data etc. is to actually persist it automatically when it changes, I don’t mean for every change of an entry control, but for example if you get data from a service, then you might store this in a cache and persist at the same time – obviously it depends on your specific scenarios and design.

Resuming from sleep mode

When an application is resumed, the following is called

  1. OnResume

At this point we need to read any persisted data, hydrate our data/view models with this previously stored data and then get the application back into the state it was when it went into sleep mode. As mentioned for OnSleep, this includes any changes to the UI to put the correct view in place. Basically the user should not even realise that the application was, essentially, closed and restarted.

To test OnResume we simply click the power button on the emulator or unlock the device at which point OnResume will be called.

References

Xamarin.Forms App Lifecycle
Android Activity Lifecycle
UIApplicationDelegate Class

Creating a Swift Package

In my previous post I looked at creating a CircleImage, basically creating a reusable SwiftUI control. Now let’s look at how we might start creating packages to allow us to share such library code.

Creating a Swift Package

From Xcode, select File | New | Swift Package. A very basic package is created (mine’s name MyLibrary) with a Sources/YouPackageName/YourPackageName.swift file containing the following code

struct MyLibrary {
    var text = "Hello, World!"
}

We’ll stick with this simple bit of code but make the struct and the text var public. Also we’ll need to add a public init method or you’ll see an error such as this

initializer is inaccessible due to ‘internal’ protection level

So the new code looks like this

public struct MyLibrary {
    public var text = "Hello, World!"
    
    public init() {
    }
}

Now use Command + B to build the package.

Local Package

To use the package locally, i.e. not having it deployed to a remote repos or the likes.

Within the application that you wish to use the package, simply (using Finder) select the package folder (i..e mine’s MyLibrary) and drag and drop this into your application under the top level project node in the Project Navigator.

Now we can use the code by simply importing it, for example

import MyLibrary

and now within your code

let text = MyLibrary().text

Making our package more useful

Let’s now move the code for our CircleImage into the package, we’ll leave the package name and therefore the component will be renamed, as MyLibrary

Here’s the code

import SwiftUI

@available(iOS 13, *)
public struct MyLibrary: View {
    var image: Image
    var borderColor: Color
    var shadowRadius: CGFloat

    public var body: some View {
        image
            .clipShape(Circle())
            .overlay(Circle().stroke(borderColor, lineWidth: 4))
            .shadow(radius: shadowRadius)
    }
    
    public init(image: Image,
                borderColor: Color = .white,
                shadowRadius: CGFloat = 10) {
        self.image = image
        self.borderColor = borderColor
        self.shadowRadius = shadowRadius
    }
}

In the above we’ve removed the public keyword on the fields and instead relied on the init method to set up any defaults. We also need to mark the code with the @available attribute to state what versions of OSX or iOS is supported, for example Image is available in 13.0 of iOS.

Within the package file Package.swift we also add the platforms value, here’s a snippet of my code, showing where to expect the platforms value

...
    name: "MyLibrary",
    platforms: [
        .macOS(.v10_15),
        .iOS(.v13),
    ],
    products: [
...

and in our application we now simply use something like the following

MyLibrary(image: landmark.image)
   .offset(x: 0, y: -130)
   .padding(.bottom, -130)

We’ll look at using GitHub or the likes to host our package in a subsequent post, but this gives an idea on how to get something up and running.

Swift UI Circle Image

Here’s a simple circle image using SwiftUI. This is pretty much taken from the SwiftUI Tutorial with a few additions.

struct CircleImage: View {
    var image: Image
    var borderColor: Color = .white
    var shadowRadius: CGFloat = 10

    var body: some View {
        image
            .clipShape(Circle())
            .overlay(Circle().stroke(borderColor, lineWidth: 4))
            .shadow(radius: shadowRadius)
    }
}

In this case we pass and image to the CircleImage, clipping it into a circle shape. Then we display a line (in white by default) around it with a shadow (with radius 10 by default).

We simply clip the supplied image, i.e.

CircleImage(image: Image("imageFrom.Assets.xcassets"), 
   borderColor: .red, 
   shadowRadius: 5)

The image should be stored within the Assets.xcassets editor.

Splitter bars in React

I went through a load of splitter bar implementations for use within a React site, i.e. I simply wanted to partition my application into two halves (top and bottom), with a horizontal splitter bar.

The top half should be filled with a grid of data (I was using ag-grid), the bottom half filled with the query builder control. Also the button half should be capable of being collapse/hidden.

I was surprised at how hard it was to find anything that “just worked”. But this one did…

Run

yarn add m-react-splitters

Mine is “m-react-splitters”: “^1.2.0”. Now import the following

import Splitter from "m-react-splitters";
import "m-react-splitters/lib/splitters.css";

and here’s the basics for the code (obviously replacing the comment blocks with your components).

<Splitter
   position="horizontal"
   maximizedPrimaryPane={!showQueryBuilder}>
<div style={{width: "100%, height: "100%" }}>
<!-- grid -->
</div>
<div style={{width: "100%, height: "100%", overflow: "auto" }}>
<!-- query builder -->
</div>