App 02: Stopwatch

This is a stopwatch app with a lap counter and a list of lap times.

Had to learn alot about layouts in xaml to get this one looking similar to the one from the book, which was fun.

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Stopwatch.MainPage"
             BackgroundColor="Black">

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="BlackButtonStyle" TargetType="Button">
                <Setter Property="TextColor"
                        Value="White" />
                <Setter Property="BackgroundColor"
                        Value="Black" />
                <Setter Property="CornerRadius"
                        Value="15" />
                <Setter Property="BorderColor" 
                        Value="White"/>
                <Setter Property="BorderWidth" Value="2" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label Text="Stopwatch" Grid.Row="0" Grid.ColumnSpan="2" 
               HorizontalTextAlignment="Start" TextColor="White" />
        <Label Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="0" 
               HorizontalTextAlignment="End" Text="Current lap" TextColor="White" />
        <Label x:Name="CurrentLapTimeDisplay" Grid.Row="2" Grid.ColumnSpan="2" 
               Grid.Column="0" FontSize="20" HorizontalTextAlignment="End"
               Margin="0,0,12,0" Text="0:00:0" TextColor="White" />

        <StackLayout Grid.Row="3" Grid.ColumnSpan="2" Grid.Column="0" >
            <ProgressBar x:Name="LapProgressBar" ></ProgressBar>
            <Label x:Name="TotalTimeDisplay" HorizontalTextAlignment="Center" FontSize="50" 
                   Text="0:00:0" TextColor="White"></Label>
        </StackLayout>


        <Button x:Name="StartButton" Grid.Row="4" Grid.Column="0" Text="start" Margin="12,0,0,0"
                Clicked="StartButton_OnClicked"
                Style="{StaticResource BlackButtonStyle}" />
        <Button x:Name="StopButton" Grid.Row="4" Grid.Column="0" Text="stop"  IsVisible="False" Margin="12,0,0,0" 
                Clicked="StopButton_OnClicked"
                Style="{StaticResource BlackButtonStyle}" />
        <Button x:Name="ResetButton" Grid.Row="4" Grid.Column="1" Text="reset"  IsVisible="False" Margin="0,0,12,0" 
                Clicked="ResetButton_OnClicked"
                Style="{StaticResource BlackButtonStyle}" />
        <Button x:Name="LapButton" Grid.Row="4" Grid.Column="1" Text="lap" Margin="0,0,12,0" Clicked="LapButton_OnClicked"
                Style="{StaticResource BlackButtonStyle}" />

        
        <ListView Grid.Row="5" Grid.ColumnSpan="2" Grid.Column="0" x:Name ="LapsTable" BackgroundColor="Black" >
           
        </ListView>

    </Grid>

</ContentPage>

ManiPage.xaml.cs

using System;
using System.Collections.ObjectModel;
using Xamarin.Forms;

namespace Stopwatch
{
    public partial class MainPage
    {
        private readonly ObservableCollection<string> _lapTimes;
        private TimeSpan _totalTime;
        private TimeSpan _currentLapTime;
        private TimeSpan _previousLapTime;
        private DateTime _previousTick;
        private bool _isRunning;

        public MainPage()
        {
            InitializeComponent();
            InitializeTimers();

            _lapTimes = new ObservableCollection<string>();
            LapsTable.ItemsSource = _lapTimes;
        }

        private void InitializeTimers()
        {          
            _totalTime = TimeSpan.Zero;
            _currentLapTime = TimeSpan.Zero;
            _previousLapTime = TimeSpan.Zero;
            _previousTick = DateTime.MinValue;
        }

        private void Start()
        {
            _isRunning = true;
            StartButton.IsVisible = false;
            StopButton.IsVisible = true;
            LapButton.IsVisible = true;
            ResetButton.IsVisible = false;
            _previousTick = DateTime.UtcNow;
            Device.StartTimer(TimeSpan.FromSeconds(.1), TimerTick);
        }

        private void Stop()
        {
            _isRunning = false;
            StartButton.IsVisible = true;
            StopButton.IsVisible = false;
            ResetButton.IsVisible = true;
            LapButton.IsVisible = false;
        }

        private void Reset()
        {
            InitializeTimers();
            ShowCurrentTime();
            _lapTimes.Clear();
        }

        private bool TimerTick()
        {
            var delta = DateTime.UtcNow - _previousTick;
            _previousTick += delta;
            _totalTime += delta;
            _currentLapTime += delta;

            ShowCurrentTime();
            return _isRunning;
        }

        private void ShowCurrentTime()
        {
            TotalTimeDisplay.Text = _totalTime.ToString("m':'ss':'f");
            CurrentLapTimeDisplay.Text = _currentLapTime.ToString("m':'ss':'f");
            LapProgressBar.Progress = _currentLapTime.TotalSeconds;
            
        }

        private void InsertLapInList(TimeSpan timeSpan)
        {
            var lapNumber = _lapTimes.Count + 1;
            var lap = "Lap " + lapNumber + " " + timeSpan.ToString("m':'ss':'f");
            _lapTimes.Add(lap);
        }

        private void StartButton_OnClicked(object sender, EventArgs e)
        {
            Start();          
        }

        private void StopButton_OnClicked(object sender, EventArgs e)
        {
            Stop();
        }

        private void ResetButton_OnClicked(object sender, EventArgs e)
        {
           Reset();
        }

        private void LapButton_OnClicked(object sender, EventArgs e)
        {
            InsertLapInList(_currentLapTime);
            _previousLapTime = _currentLapTime;
            _currentLapTime = TimeSpan.Zero;
            
        }
    }
}

See you with the next app.

Leave a comment