notifications that actually work

This commit is contained in:
2020-04-27 13:40:41 +03:00
parent b97f9b723c
commit 9c9f74d347
4 changed files with 118 additions and 56 deletions

View File

@@ -42,7 +42,7 @@
x:Name="MinutesText" x:Name="MinutesText"
FontSize="60" FontSize="60"
FontWeight="Bold" FontWeight="Bold"
Text="{x:Bind runningState.MinutesLeft, Converter={StaticResource FormatStringConverter}, Mode=OneWay, ConverterParameter='00'}" /> Text="{x:Bind MainViewRunningState.MinutesLeft, Converter={StaticResource FormatStringConverter}, Mode=OneWay, ConverterParameter='00'}" />
<Run <Run
x:Name="Separator" x:Name="Separator"
FontSize="30" FontSize="30"
@@ -52,7 +52,7 @@
x:Name="SecondsText" x:Name="SecondsText"
FontSize="30" FontSize="30"
FontWeight="SemiBold" FontWeight="SemiBold"
Text="{x:Bind runningState.SecondsLeft, Converter={StaticResource FormatStringConverter}, Mode=OneWay, ConverterParameter='00'}" /> Text="{x:Bind MainViewRunningState.SecondsLeft, Converter={StaticResource FormatStringConverter}, Mode=OneWay, ConverterParameter='00'}" />
</Paragraph> </Paragraph>
</RichTextBlock> </RichTextBlock>
<TextBlock <TextBlock
@@ -62,7 +62,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
FontSize="30" FontSize="30"
FontWeight="Light" FontWeight="Light"
Text="{x:Bind runningState.CurrentPeriod, Converter={StaticResource PeriodToStringConverter}, Mode=OneWay}" /> Text="{x:Bind MainViewRunningState.CurrentPeriod, Converter={StaticResource PeriodToStringConverter}, Mode=OneWay}" />
</Grid> </Grid>
<Grid Grid.Row="0" Grid.Column="1"> <Grid Grid.Row="0" Grid.Column="1">
<Grid> <Grid>
@@ -123,13 +123,13 @@
Click="PlayButton_Click" Click="PlayButton_Click"
Icon="Play" Icon="Play"
Label="Start" Label="Start"
Visibility="{x:Bind runningState.IsRunning, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay, ConverterParameter=True}" /> Visibility="{x:Bind MainViewRunningState.IsRunning, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay, ConverterParameter=True}" />
<AppBarButton <AppBarButton
x:Name="PauseButton" x:Name="PauseButton"
Click="PauseButton_Click" Click="PauseButton_Click"
Icon="Pause" Icon="Pause"
Label="Pause" Label="Pause"
Visibility="{x:Bind runningState.IsRunning, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" /> Visibility="{x:Bind MainViewRunningState.IsRunning, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
<AppBarButton <AppBarButton
x:Name="ResetButton" x:Name="ResetButton"
Click="ResetButton_Click" Click="ResetButton_Click"

View File

@@ -14,11 +14,11 @@ using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation; using Windows.UI.Xaml.Navigation;
using Windows.UI.Notifications;
using Windows.Storage; using Windows.Storage;
using Windows.System.Threading; using Windows.System.Threading;
using Windows.UI.Core; using Windows.UI.Core;
using Microsoft.Toolkit.Uwp.Notifications; using Microsoft.Toolkit.Uwp.Notifications;
using Windows.UI.Notifications;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
@@ -30,11 +30,12 @@ namespace PomoTime
/// </summary> /// </summary>
public sealed partial class MainPage : Page public sealed partial class MainPage : Page
{ {
public RunningState runningState = new RunningState(); public RunningState MainViewRunningState = new RunningState();
private const int DefaultBreakMinutes = 5; private const int DefaultBreakMinutes = 5;
private const int DefaultWorkMinutes = 25; private const int DefaultWorkMinutes = 25;
private const int DefaultLongBreakMinutes = 15; private const int DefaultLongBreakMinutes = 15;
private DateTime SuspendTime;
private int _work_minutes; private int _work_minutes;
private int BreakMinutes { get; set; } private int BreakMinutes { get; set; }
private int WorkMinutes private int WorkMinutes
@@ -42,9 +43,9 @@ namespace PomoTime
get { return _work_minutes; } get { return _work_minutes; }
set set
{ {
if (!runningState.IsRunning && runningState.CurrentPeriod == Period.Work) if (!MainViewRunningState.IsRunning && MainViewRunningState.CurrentPeriod == Period.Work)
{ {
runningState.MinutesLeft = value; MainViewRunningState.MinutesLeft = value;
} }
_work_minutes = value; _work_minutes = value;
} }
@@ -64,6 +65,7 @@ namespace PomoTime
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize; ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
Application.Current.Suspending += OnSuspending; Application.Current.Suspending += OnSuspending;
Application.Current.Resuming += OnResuming;
this.Loaded += MainPageLoaded; this.Loaded += MainPageLoaded;
ApplicationDataContainer roamingSettings = Windows.Storage.ApplicationData.Current.RoamingSettings; ApplicationDataContainer roamingSettings = Windows.Storage.ApplicationData.Current.RoamingSettings;
@@ -102,79 +104,85 @@ namespace PomoTime
BreakMinutes = DefaultBreakMinutes; BreakMinutes = DefaultBreakMinutes;
LongBreakMinutes = DefaultLongBreakMinutes; LongBreakMinutes = DefaultLongBreakMinutes;
} }
runningState.MinutesLeft = WorkMinutes; MainViewRunningState.MinutesLeft = WorkMinutes;
runningState.SecondsLeft = 0; MainViewRunningState.SecondsLeft = 0;
} }
void timer_Tick() void timer_Tick()
{ {
if (!runningState.IsRunning) if (!MainViewRunningState.IsRunning)
{ {
return; return;
} }
if (runningState.SecondsLeft == 0) if (MainViewRunningState.SecondsLeft == 0)
{ {
runningState.SecondsLeft = 59; MainViewRunningState.SecondsLeft = 59;
if (runningState.MinutesLeft == 0) if (MainViewRunningState.MinutesLeft == 0)
{ {
switch (runningState.CurrentPeriod) switch (MainViewRunningState.CurrentPeriod)
{ {
case Period.Work: case Period.Work:
if (runningState.PreviousShortBreaks != 4) if (MainViewRunningState.PreviousShortBreaks != 4)
{ {
runningState.CurrentPeriod = Period.ShortBreak; MainViewRunningState.CurrentPeriod = Period.ShortBreak;
runningState.MinutesLeft = BreakMinutes; MainViewRunningState.MinutesLeft = BreakMinutes;
} }
else else
{ {
runningState.CurrentPeriod = Period.LongBreak; MainViewRunningState.CurrentPeriod = Period.LongBreak;
runningState.MinutesLeft = LongBreakMinutes; MainViewRunningState.MinutesLeft = LongBreakMinutes;
} }
runningState.SecondsLeft = 0; MainViewRunningState.SecondsLeft = 0;
break; break;
case Period.ShortBreak: case Period.ShortBreak:
runningState.CurrentPeriod = Period.Work; MainViewRunningState.CurrentPeriod = Period.Work;
runningState.PreviousShortBreaks += 1; MainViewRunningState.PreviousShortBreaks += 1;
runningState.MinutesLeft = WorkMinutes; MainViewRunningState.MinutesLeft = WorkMinutes;
runningState.SecondsLeft = 0; MainViewRunningState.SecondsLeft = 0;
break; break;
case Period.LongBreak: case Period.LongBreak:
runningState.CurrentPeriod = Period.Work; MainViewRunningState.CurrentPeriod = Period.Work;
runningState.PreviousShortBreaks = 0; MainViewRunningState.PreviousShortBreaks = 0;
runningState.MinutesLeft = WorkMinutes; MainViewRunningState.MinutesLeft = WorkMinutes;
runningState.SecondsLeft = 0; MainViewRunningState.SecondsLeft = 0;
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
SendToast(); SchedulePeriodOverNotification();
} }
else else
{ {
runningState.MinutesLeft--; MainViewRunningState.MinutesLeft--;
} }
} }
else if (MainViewRunningState.SecondsLeft == 1 && MainViewRunningState.MinutesLeft == 0)
{
MainViewRunningState.IsRunning = false;
MainViewRunningState.SecondsLeft--;
SchedulePeriodOverNotification();
}
else else
{ {
runningState.SecondsLeft--; MainViewRunningState.SecondsLeft--;
} }
} }
void SendToast() void SchedulePeriodOverNotification()
{ {
string header; string header;
switch (runningState.CurrentPeriod) switch (MainViewRunningState.CurrentPeriod)
{ {
case Period.LongBreak: case Period.LongBreak:
header = "Long break time!"; header = "Long break time over!";
break; break;
case Period.ShortBreak: case Period.ShortBreak:
header = "Short break time!"; header = "Short break time over!";
break; break;
case Period.Work: case Period.Work:
header = "Work time!"; header = "Work time over!";
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
@@ -199,50 +207,69 @@ namespace PomoTime
Visual = visual, Visual = visual,
}; };
var toast = new ToastNotification(toastContent.GetXml()); TimeSpan WaitTime = new TimeSpan(0, MainViewRunningState.MinutesLeft, MainViewRunningState.SecondsLeft);
toast.ExpirationTime = DateTime.Now.AddMinutes(runningState.MinutesLeft); var toast = new Windows.UI.Notifications.ScheduledToastNotification(toastContent.GetXml(), DateTime.Now + WaitTime);
ToastNotificationManager.CreateToastNotifier().Show(toast); Windows.UI.Notifications.ToastNotificationManager.CreateToastNotifier().AddToSchedule(toast);
}
private void ClearScheduledNotifications()
{
ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier();
IReadOnlyList<ScheduledToastNotification> scheduledToasts = notifier.GetScheduledToastNotifications();
foreach (ScheduledToastNotification n in scheduledToasts)
{
notifier.RemoveFromSchedule(n);
}
} }
private void PlayButton_Click(object sender, RoutedEventArgs e) private void PlayButton_Click(object sender, RoutedEventArgs e)
{ {
AppBarButton b = sender as AppBarButton; AppBarButton b = sender as AppBarButton;
runningState.IsRunning = true; MainViewRunningState.IsRunning = true;
if(MainViewRunningState.MinutesLeft != 0 || MainViewRunningState.SecondsLeft != 0)
{
SchedulePeriodOverNotification();
}
} }
private void PauseButton_Click(object sender, RoutedEventArgs e) private void PauseButton_Click(object sender, RoutedEventArgs e)
{ {
AppBarButton b = sender as AppBarButton; AppBarButton b = sender as AppBarButton;
runningState.IsRunning = false; MainViewRunningState.IsRunning = false;
ClearScheduledNotifications();
} }
private void ResetButton_Click(object sender, RoutedEventArgs e) private void ResetButton_Click(object sender, RoutedEventArgs e)
{ {
AppBarButton b = sender as AppBarButton; AppBarButton b = sender as AppBarButton;
runningState.IsRunning = false; MainViewRunningState.IsRunning = false;
runningState.CurrentPeriod = Period.Work; MainViewRunningState.CurrentPeriod = Period.Work;
runningState.MinutesLeft = WorkMinutes; MainViewRunningState.MinutesLeft = WorkMinutes;
runningState.SecondsLeft = 0; MainViewRunningState.SecondsLeft = 0;
ClearScheduledNotifications();
} }
private void Plus1Button_Click(object sender, RoutedEventArgs e) private void Plus1Button_Click(object sender, RoutedEventArgs e)
{ {
AppBarButton b = sender as AppBarButton; AppBarButton b = sender as AppBarButton;
runningState.MinutesLeft += 1; MainViewRunningState.MinutesLeft += 1;
} }
private void Plus5Button_Click(object sender, RoutedEventArgs e) private void Plus5Button_Click(object sender, RoutedEventArgs e)
{ {
AppBarButton b = sender as AppBarButton; AppBarButton b = sender as AppBarButton;
runningState.MinutesLeft += 5; MainViewRunningState.MinutesLeft += 5;
} }
private void Plus10Button_Click(object sender, RoutedEventArgs e) private void Plus10Button_Click(object sender, RoutedEventArgs e)
{ {
AppBarButton b = sender as AppBarButton; AppBarButton b = sender as AppBarButton;
runningState.MinutesLeft += 10; MainViewRunningState.MinutesLeft += 10;
} }
private void OnSuspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e) private void OnSuspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{ {
@@ -253,18 +280,46 @@ namespace PomoTime
minutes["BreakMinutes"] = BreakMinutes; minutes["BreakMinutes"] = BreakMinutes;
minutes["LongBreakMinutes"] = LongBreakMinutes; minutes["LongBreakMinutes"] = LongBreakMinutes;
roamingSettings.Values["Minutes"] = minutes; roamingSettings.Values["Minutes"] = minutes;
SuspendTime = DateTime.Now;
deferral.Complete(); deferral.Complete();
} }
private void OnResuming(object sender, Object e)
{
TimeSpan TimeFromSuspend = DateTime.Now - SuspendTime;
if(!MainViewRunningState.IsRunning)
{
return;
}
if(TimeFromSuspend.TotalSeconds >= MainViewRunningState.MinutesLeft * 60 + MainViewRunningState.SecondsLeft)
{
MainViewRunningState.IsRunning = false;
MainViewRunningState.MinutesLeft = 0;
MainViewRunningState.SecondsLeft = 0;
return;
}
if(TimeFromSuspend.Seconds > MainViewRunningState.SecondsLeft)
{
MainViewRunningState.MinutesLeft -= TimeFromSuspend.Minutes + 1;
MainViewRunningState.SecondsLeft = MainViewRunningState.SecondsLeft + 60 - TimeFromSuspend.Seconds;
return;
}
MainViewRunningState.MinutesLeft -= TimeFromSuspend.Minutes;
MainViewRunningState.SecondsLeft -= TimeFromSuspend.Seconds;
}
private void MainPageLoaded(object sender, RoutedEventArgs e) private void MainPageLoaded(object sender, RoutedEventArgs e)
{ {
ThreadPoolTimer timer = ThreadPoolTimer.CreatePeriodicTimer(async (t) => ThreadPoolTimer timer = ThreadPoolTimer.CreatePeriodicTimer(async (t) =>
{ {
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, await Dispatcher.RunAsync(CoreDispatcherPriority.High,
() => () =>
{ {
timer_Tick(); timer_Tick();
}); });
}, TimeSpan.FromSeconds(1)); }, TimeSpan.FromSeconds(1));
} }
} }

View File

@@ -9,7 +9,7 @@
<Identity <Identity
Name="44844StepanUsatyuk.PomoTime" Name="44844StepanUsatyuk.PomoTime"
Publisher="CN=D7EE55C2-4D4B-40F8-8EE5-CC4CEBCE2133" Publisher="CN=D7EE55C2-4D4B-40F8-8EE5-CC4CEBCE2133"
Version="1.0.0.0" /> Version="1.0.1.0" />
<mp:PhoneIdentity PhoneProductId="4d8bddac-8ab7-4c19-b3c7-7b5a27b87594" PhonePublisherId="00000000-0000-0000-0000-000000000000"/> <mp:PhoneIdentity PhoneProductId="4d8bddac-8ab7-4c19-b3c7-7b5a27b87594" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>

View File

@@ -19,6 +19,13 @@
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview> <WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled> <AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<PackageCertificateThumbprint>037FCF0D18772F50AACCB9F3A4F9061066C3F0CB</PackageCertificateThumbprint> <PackageCertificateThumbprint>037FCF0D18772F50AACCB9F3A4F9061066C3F0CB</PackageCertificateThumbprint>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
<AppxBundle>Always</AppxBundle>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>