0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WindowsAdvent Calendar 2024

Day 24

WinUI3でポモドーロタイマーを作ってみよう!#3

Posted at

はじめに

#2で(下記)、設定画面を実装した続きから行う。(全3記事を予定)

プロジェクトの作成(#2の続きから)

#タイマー画面の実装

そもそも、ポモドーロタイマー(テクニック)とは(下記URLより)

ポモドーロテクニックは、仕事を 25 分ずつのセッションに分け、そのあいだに短い休憩をはさんで行う時間管理術です。集中力を維持しながら生産性を上げる効果があるこの手法は、ビジネスシーンだけでなく、勉強などに集中したいときにも活用できるテクニックです。

まず、画面を作成する

TimerPage.xaml
    <Grid>
        <Ellipse Fill="#FF4CAF50"  Width="300" Height="300" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock x:Name="TimerTextBlock" FontSize="72" FontWeight="Bold" TextAlignment="Center" Foreground="White" Margin="0,0,0,20"/>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                <Button x:Name="StartButton" Content="Start" Click="StartButton_Click" Margin="5" Style="{StaticResource AccentButtonStyle}" CornerRadius="10" Padding="15,5"/>
                <Button x:Name="ResetButton" Content="Reset" Click="ResetButton_Click" Margin="5" Style="{StaticResource DefaultButtonStyle}" CornerRadius="10" Padding="15,5"/>
            </StackPanel>
            <TextBlock x:Name="StatusTextBlock"  HorizontalAlignment="Center" Margin="0,20,0,0" Foreground="WhiteSmoke"/>
        </StackPanel>
    </Grid>

次に、タイマーのロジックを実装する

TimerPage.xaml.cs
        private DispatcherTimer timer;
        private TimeSpan remainingTime;
        private bool isRunning = false;
        private int pomodoroCount = 0;
        private int pomodoroPhase = 4;
        private double pomodoroMinutes = 25;

        public TimerPage()
        {
            this.InitializeComponent();
            remainingTime = TimeSpan.FromMinutes(pomodoroMinutes);
            UpdateTimerDisplay();

            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += Timer_Tick;
        }

        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            if (!isRunning)
            {
                timer.Start();
                isRunning = true;
                StartButton.Content = "Pause";
            }
            else
            {
                timer.Stop();
                isRunning = false;
                StartButton.Content = "Start";
            }
        }

        private void ResetButton_Click(object sender, RoutedEventArgs e)
        {
            timer.Stop();
            isRunning = false;
            StartButton.Content = "Start";
            remainingTime = TimeSpan.FromMinutes(pomodoroMinutes);
            pomodoroCount = 0;
            UpdateTimerDisplay();
        }

        private void Timer_Tick(object sender, object e)
        {
            remainingTime = remainingTime.Subtract(TimeSpan.FromSeconds(1));
            UpdateTimerDisplay();

            if (remainingTime == TimeSpan.Zero)
            {
                timer.Stop();
                isRunning = false;
                StartButton.Content = "Start";
                pomodoroCount++;

                string message = (pomodoroCount % pomodoroPhase == 0) ? "Long break" : "Short break";
                ShowNotification(message);

                remainingTime = (pomodoroCount % pomodoroPhase == 0) ? TimeSpan.FromMinutes(20) : TimeSpan.FromMinutes(5);
                UpdateTimerDisplay();
            }
        }

        private void UpdateTimerDisplay()
        {
            TimerTextBlock.Text = remainingTime.ToString(@"mm\:ss");
            if (isRunning)
            {
                StatusTextBlock.Text = $"Pomodoro {pomodoroCount + 1} / {pomodoroPhase} in progress";
            }
            else
            {
                if (pomodoroCount % pomodoroPhase == 0 && pomodoroCount > 0)
                {
                    StatusTextBlock.Text = "Long break";
                }
                else if (pomodoroCount > 0)
                {
                    StatusTextBlock.Text = "Short break";
                }
                else
                {
                    StatusTextBlock.Text = "Waiting to Start";
                }
            }
        }

        private async void ShowNotification(string message)
        {
            ContentDialog dialog = new ContentDialog
            {
                Title = message,
                CloseButtonText = "OK",
                XamlRoot = this.Content.XamlRoot
            };
            await dialog.ShowAsync();
        }
    

これだけだと寂しいので

タイマーのダイアログが起動している間、効果音を鳴らし続けるロジックも追加する

((著作権フリー)効果音が下記からDLいたしました。)

TimerPage.xaml.cs
 private async void ShowNotification(string message)
 {
     ContentDialog dialog = new ContentDialog
     {
         Title = message,
         CloseButtonText = "OK",
         XamlRoot = this.Content.XamlRoot
     };
     MediaPlayer player = new MediaPlayer();
     StorageFolder installedLocation = Package.Current.InstalledLocation;
     StorageFile file = await StorageFile.GetFileFromPathAsync(System.IO.Path.Combine(installedLocation.Path, "Assets\\alert.mp3"));
     player.Source = MediaSource.CreateFromStorageFile(file);
     player.IsLoopingEnabled = true;
     player.Play();

     await dialog.ShowAsync();

     player.Pause();
     player.Dispose();
 }

WinUIWinUI3はじめてみよう3_0.jpg

これでタイマー画面の実装完成!

#Todoリスト画面の実装

画面を作成する

TaskPage.xaml
  <StackPanel Orientation="Vertical" Margin="20">
        <TextBox x:Name="NewTodoTextBox" PlaceholderText="New Todo" />
        <Button x:Name="AddButton" Content="Add" Click="AddButton_Click" Margin="0,5,0,0" />

        <ListView ItemsSource="{x:Bind todos}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                        <TextBlock Text="{Binding}" VerticalAlignment="Center" />
                        <Button Margin="10,0,0,0" Content="Delete" Click="DeleteButton_Click" />
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

    </StackPanel>

Todoリストでもサウンド設定と同じくローカルのストレージを利用して

Todoリストをメモ上に保存するロジックを実装する

TaskPage.xaml.cs
        private const string StorageFileName = "todos.txt";
        private ObservableCollection<string> todos = new ObservableCollection<string>();

        public TaskPage()
        {
            this.InitializeComponent();
            Loaded += TaskPage_Loaded;
        }
        
        private async void TaskPage_Loaded(object sender, RoutedEventArgs e)
        {
            await LoadTodosAsync();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
        }

        private async Task LoadTodosAsync()
        {
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            try
            {
                StorageFile file = await localFolder.GetFileAsync(StorageFileName);
                string content = await FileIO.ReadTextAsync(file);
                string[] lines = content.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                todos.Clear();
                foreach (string line in lines)
                {
                    todos.Add(line);
                }
            }
            catch (FileNotFoundException)
            {
                //NOT EXIST
                StorageFile file = await localFolder.CreateFileAsync(StorageFileName, CreationCollisionOption.ReplaceExisting);
                await FileIO.WriteTextAsync(file, "");
            }
        }

        private async Task SaveTodosAsync()
        {
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            StorageFile file = await localFolder.CreateFileAsync(StorageFileName, CreationCollisionOption.ReplaceExisting);
            string content = string.Join(Environment.NewLine, todos);
            await FileIO.WriteTextAsync(file, content);
        }

        private async void AddButton_Click(object sender, RoutedEventArgs e)
        {
            string newTodo = NewTodoTextBox.Text.Trim();
            if (!string.IsNullOrEmpty(newTodo))
            {
                todos.Add(newTodo);
                NewTodoTextBox.Text = "";
                await SaveTodosAsync();
            }
        }

        private async void DeleteButton_Click(object sender, RoutedEventArgs e)
        {
            if (sender is Button button && button.DataContext is string todo)
            {
                todos.Remove(todo);
                await SaveTodosAsync();
            }
        }

WinUIWinUI3はじめてみよう3_1.jpg

これでTodoリスト画面の実装完成!

これで全画面の実装が完了したのでアプリケーション完成!!!

#最後に

アプリケーションをデバッグ環境ではなく、リリースして使う方法を紹介する。

プロジェクトを右クリックでパッケージ化して公開するをクリック。

アプリ パッケージの作成を選択する。

サイドローディングを選択し次へ。

WinUIWinUI3はじめてみよう3_2.jpg

証明書を作成するを選択し、作成ボタンを押下する

自己署名の欄に発行者共通名と適当なパスワードを入れてOK押下

WinUIWinUI3はじめてみよう3_3.jpg

WinUIWinUI3はじめてみよう3_4.jpg

信頼するボタンを押下して次へ、

パッケージの選択と構成で任意の選択をして次へ、

更新設定も任意のパスをいれて作成する。

WinUIWinUI3はじめてみよう3_5.jpg

すると、成果物の出力先フォルダのパスが表示される

上記のパスにある成果物内のインストーラーをクリックするとリリース版がインストールされる。

WinUIWinUI3はじめてみよう3_6.jpg

WinUIWinUI3はじめてみよう3_7.jpg

今回の成果物

ソース

まとめ

全3記事でポモドーロタイマーのアプリケーションをWinUI3で実装してみた。

WinFormsと比べると情報が少なく、苦労する箇所もあったが、

Win 3 GalleryやMS公式のリファレンスを参照してどうにかなった👍

今後も学習していきたい。📝

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?