Finishing the App

We have a fully functional calculator app, but there are still some things we can do to further customize and refine the app. In this module, we will look at the ThemeService from Uno.Extensions and use this to toggle between light and dark theme in the app. Then we will finish by overriding the default colors to give the app a more custom look and feel.

Adding the ThemeService

We need to update the constructor of our DataContext (MVVM ViewModel) to use the IThemeService. First, we need to update the initial value of the IsDark property to use the IThemeServicce.IsDark property. Because the IThemeService may still update the initial theme as initializes, we will want to hook into its ThemeChanged event and update the IsDark property when the theme changes. Finally, we will want to update the theme when the IsDark property is changed by the user.

Update the MainViewModel with the following constructor, _themeService field and IsDark property:

namespace SimpleCalculator;

public partial class MainViewModel : ObservableObject
{
    private readonly IThemeService _themeService;

    public MainViewModel(IThemeService themeService)
    {
        _themeService = themeService;
        IsDark = _themeService.IsDark;
        _themeService.ThemeChanged += (_, _) => IsDark = _themeService.IsDark;
    }

    private bool _isDark;
    public bool IsDark
    {
        get => _isDark;
        set
        {
            if (SetProperty(ref _isDark, value))
            {
                _themeService.SetThemeAsync(value ? AppTheme.Dark : AppTheme.Light);
            }
        }
    }

    [ObservableProperty]
    private Calculator _calculator = new();

    [RelayCommand]
    private void Input(string key) =>
        Calculator = Calculator.Input(key);
}

With our ViewModel updated we need to update our MainPage.cs file so that we initialize the MainViewModel with an IThemeService instance.

namespace SimpleCalculator;

public partial class MainPage : Page
{
    public MainPage()
    {
        this.DataContext(new MainViewModel(this.GetThemeService()), (page, vm) => page
          // Left out for brevity
        );
    }
}

Customizing the Color Palette

So far we have the default Uno Material color palette from Uno.Material with some overrides from the new app template. We can further customize the color palette by updating the color overrides in the Styles folder of our SimpleCalculator project.

ColorPaletteOverride.cs code contents (collapsed for brevity)
using Uno.Themes.Markup;

namespace SimpleCalculator.Styles;

public sealed class ColorPaletteOverride : ResourceDictionary
{
    public ColorPaletteOverride()
    {
        this.Build(r => r
            // Background
            .Add<Color>(Theme.Colors.Background.Default.Key, "#FCFCFF", "#1A1C1E")
            // OnBackground
            .Add<Color>(Theme.Colors.OnBackground.Default.Key, "#1A1C1E", "#E2E2E5")
            // Primary
            .Add<Color>(Theme.Colors.Primary.Default.Key, "#006399", "#95CCFF")
            .Add<Color>(Theme.Colors.Primary.Container.Key, "#CDE5FF", "#004A75")
            .Add<Color>(Theme.Colors.Primary.Inverse.Key, "#95CCFF", "#006399")
            // OnPrimary
            .Add<Color>(Theme.Colors.OnPrimary.Default.Key, "#FFFFFF", "#003352")
            .Add<Color>(Theme.Colors.OnPrimary.Container.Key, "#001D32", "#CDE5FF")
            // Secondary
            .Add<Color>(Theme.Colors.Secondary.Default.Key, "#51606F", "#B9C8DA")
            .Add<Color>(Theme.Colors.Secondary.Container.Key, "#D5E4F6", "#3A4857")
            // OnSecondary
            .Add<Color>(Theme.Colors.OnSecondary.Default.Key, "#FFFFFF", "#233240")
            .Add<Color>(Theme.Colors.OnSecondary.Container.Key, "#0E1D2A", "#D5E4F6")
            // Tertiary
            .Add<Color>(Theme.Colors.Tertiary.Default.Key, "#00658D", "#83CFFF")
            .Add<Color>(Theme.Colors.Tertiary.Container.Key, "#C6E7FF", "#004C6B")
            // OnTertiary
            .Add<Color>(Theme.Colors.OnTertiary.Default.Key, "#FFFFFF", "#00344B")
            .Add<Color>(Theme.Colors.OnTertiary.Container.Key, "#001E2D", "#C6E7FF")
            // Surface
            .Add<Color>(Theme.Colors.Surface.Default.Key, "#FCFCFF", "#335476")
            .Add<Color>(Theme.Colors.Surface.Variant.Key, "#DEE3EB", "#42474E")
            .Add<Color>(Theme.Colors.Surface.Inverse.Key, "#2F3033", "#E2E2E5")
            .Add<Color>(Theme.Colors.Surface.Tint.Key, "#006399", "#95CCFF")
            // OnSurface
            .Add<Color>(Theme.Colors.OnSurface.Default.Key, "#1A1C1E", "#E2E2E5")
            .Add<Color>(Theme.Colors.OnSurface.Variant.Key, "#42474E", "#C2C7CF")
            .Add<Color>(Theme.Colors.OnSurface.Inverse.Key, "#F0F0F4", "#1A1C1E")
            // Outline
            .Add<Color>(Theme.Colors.Outline.Default.Key, "#72777F", "#8C9198")
            .Add<Color>(Theme.Colors.Outline.Variant.Key, "#C2C7CF", "#42474E")
            // Error
            .Add<Color>(Theme.Colors.Error.Default.Key, "#BA1A1A", "#FFB4AB")
            .Add<Color>(Theme.Colors.Error.Container.Key, "#FFDAD6", "#93000A")
            // OnError
            .Add<Color>(Theme.Colors.OnError.Default.Key, "#FFFFFF", "#690005")
            .Add<Color>(Theme.Colors.OnError.Container.Key, "#410002", "#FFDAD6"));
    }
}

With the color palette updated, we can now run the app again to see the updated look for our calculator. The final result will be similar to the image below:

Final Result

Next Steps

Congratulations you have now created your first Uno app! The four permutations of the SimpleCalculator can be found within our Uno.Samples GitHub Repository.

To continue to learn more about Uno Platform be sure to check out the Uno Platform documentation and the Uno Platform samples.

Previous