Skip to content

Commit

Permalink
Option to use random quotes with management
Browse files Browse the repository at this point in the history
  • Loading branch information
aryehsilver committed Sep 27, 2023
1 parent 6fe82a3 commit 3966d6e
Show file tree
Hide file tree
Showing 18 changed files with 712 additions and 377 deletions.
10 changes: 8 additions & 2 deletions TheShivisiApp.sln
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31005.135
# Visual Studio Version 17
VisualStudioVersion = 17.7.34031.279
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheShivisiApp", "TheShivisiApp\TheShivisiApp.csproj", "{BC2E0E74-F63B-4D8D-B3CD-36A87B95BC6E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotifyIcon", "NotifyIcon\NotifyIcon.csproj", "{E9749304-9102-4D3F-80BF-760D377202C0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheShivisiApp.Models", "TheShivisiApp.Models\TheShivisiApp.Models.csproj", "{5113FE37-B56D-447E-8AD1-1A2FCA3FE19E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -21,6 +23,10 @@ Global
{E9749304-9102-4D3F-80BF-760D377202C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9749304-9102-4D3F-80BF-760D377202C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9749304-9102-4D3F-80BF-760D377202C0}.Release|Any CPU.Build.0 = Release|Any CPU
{5113FE37-B56D-447E-8AD1-1A2FCA3FE19E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5113FE37-B56D-447E-8AD1-1A2FCA3FE19E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5113FE37-B56D-447E-8AD1-1A2FCA3FE19E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5113FE37-B56D-447E-8AD1-1A2FCA3FE19E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
139 changes: 54 additions & 85 deletions TheShivisiApp/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,133 +2,102 @@

public partial class App : Application {
#region Props, Fields & consts
private static readonly string App_Folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\The Shivisi App";
private TaskbarIcon notifyIcon;
private Timer timer;
private AppDbContext _context;
private TaskbarIcon _notifyIcon;
private Timer _timer;
public DateTime LastRead { get; set; }
public bool RunsOnStartup { get; set; } = true;
public bool SplashScreen { get; set; } = true;
public double Interval { get; set; } = 30;
public string NotifText { get; set; } = "Remember!" + Environment.NewLine + "You're not the one in charge here!";
public Settings Settings { get; set; } = new();
#endregion

protected override void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
//create the notifyicon (it's a resource declared in NotifyIconResources.xaml)
notifyIcon = (TaskbarIcon)FindResource("NotifyIcon");

StyleManager.ApplicationTheme = new Windows11Theme();
Windows11Palette.LoadPreset(Windows11Palette.ColorVariation.Dark);
ThemeEffectsHelper.IsAcrylicEnabled = false;
bool showSettings = true;

Start();
}

public void Start() {
if (!Directory.Exists(App_Folder)) {
Directory.CreateDirectory(App_Folder);
}

ReadFromXml();
// Listen to notification activation
ToastNotificationManagerCompat.OnActivated += toastArgs => {
// Obtain the arguments from the notification
ToastArguments args = ToastArguments.Parse(toastArgs.Argument);
ShowSplashScreen();
RunTimer();
}

private void ReadFromXml() {
bool success;
Exception exception = new();
// Obtain any user input (text boxes, menu selections) from the notification
//ValueSet userInput = toastArgs.UserInput;
try {
if (File.Exists(Path.Combine(App_Folder, "Settings.xml"))) {
System.Xml.XmlDocument readFile = new();
readFile.Load(Path.Combine(App_Folder, "Settings.xml"));
// Need to dispatch to UI thread if performing UI operations
Current.Dispatcher.Invoke(delegate {
QuoteWindow quoteWindow = new(args.FirstOrDefault(a => a.Key == "Text").Value, args.FirstOrDefault(a => a.Key == "Source").Value, args.FirstOrDefault(a => a.Key == "Id").Value);
quoteWindow.Show();
quoteWindow.IsTopmost = true;
quoteWindow.IsTopmost = false;
quoteWindow.Focus();
});
System.Xml.XmlNode startupNode = readFile.SelectSingleNode("/Settings/Startup");
RunsOnStartup = startupNode.InnerText == "True";
showSettings = false;
};

System.Xml.XmlNode splashScreenNode = readFile.SelectSingleNode("/Settings/SplashScreen");
SplashScreen = splashScreenNode.InnerText == "True";
if (showSettings) {
_context = new();
_context.Database.Migrate();

System.Xml.XmlNode intervalNode = readFile.SelectSingleNode("/Settings/Interval");
Interval = double.TryParse(intervalNode.InnerText, out double outInterval) ? outInterval : 30;
//create the notifyIcon (it's a resource declared in NotifyIconResources.xaml)
_notifyIcon = (TaskbarIcon)FindResource("NotifyIcon");

System.Xml.XmlNode notifTextNode = readFile.SelectSingleNode("/Settings/NotifText");
NotifText = notifTextNode.InnerText;
} else {
RunsOnStartup = true;
SplashScreen = true;
Interval = 30;
NotifText = "Remember!" + Environment.NewLine + "You're not the one in charge here!";
}
StyleManager.ApplicationTheme = new Windows11Theme();
Windows11Palette.LoadPreset(Windows11Palette.ColorVariation.Dark);
ThemeEffectsHelper.IsAcrylicEnabled = false;

Settings = _context.Settings.SingleOrDefault();
LastRead = DateTime.Now;

if (Interval <= 0) {
RadWindow.Alert(new DialogParameters {
Header = "Error",
Content = "The interval value must be greater than 0" + Environment.NewLine + "1 minute intervals will be used instead"
});
Interval = 1;
}
success = true;
} catch (Exception ex) {
success = false;
exception = ex;
}

if (!success) {
RadWindow.Alert(new DialogParameters {
Header = "The Shivisi App - Error",
Content = "Error reading the settings" + Environment.NewLine + exception.Message
});
ShowSplashScreen();
RunTimer();
}
}

private void ShowSplashScreen() {
if (SplashScreen) {
if (Settings.ShowSplashScreen) {
SplashScreen splash = new("Data/SplashScreen.png");
splash.Show(true, true);
splash.Close(TimeSpan.FromSeconds(5));
}
}

private void RunTimer() {
timer = new Timer {
_timer = new Timer {
// [1 min = 60,000 | 5 min = 300,000 | 30 min = 1,800,000 | 1 hr = 3,600,000]
Interval = Interval * 60000
Interval = Settings.Interval * 60000
};
timer.Start();
timer.Elapsed += new ElapsedEventHandler(Timer_Elapsed);
_timer.Start();
_timer.Elapsed += new ElapsedEventHandler(Timer_Elapsed);
}

private void Timer_Elapsed(object sender, ElapsedEventArgs e) {
private async void Timer_Elapsed(object sender, ElapsedEventArgs e) {
// ISSUE: This will only get hit the next time the timer finishes it's elapsed time.
// What if the user has chosen a smaller interval, say from 30 min down to 5,
// how will the app know to change it until another 30 min passes and we hit the elapsed?
// Settings need to raise an event which will be picked up here...
CheckTimeStamps();
PopTheToast.PopIt(NotifText);
await CheckTimeStamps();
if (Settings.UseRandomQuote) {
Random random = new();
List<Quote> quotesList = await _context.Quotes.ToListAsync();
int rnd = random.Next(quotesList.Count);
Quote quote = quotesList.FirstOrDefault(q => q.Id == rnd);
PopTheToast.PopIt(quote.QuotedText, quote.Source, quote.Id);
} else {
PopTheToast.PopIt($"Remember!{Environment.NewLine}You're not the one in charge here!", $"Via TSA - {$"Version {VersionHelper.GetRunningVersion()}".Remove(13)}", 0);
}
}

private void CheckTimeStamps() {
DateTime time = File.GetLastWriteTime(Path.Combine(App_Folder, "Settings.xml"));
if (LastRead < time) {
System.Xml.XmlDocument readFile = new();
readFile.Load(Path.Combine(App_Folder, "Settings.xml"));

System.Xml.XmlNode intervalNode = readFile.SelectSingleNode("/Settings/Interval");
timer.Interval = (double.TryParse(intervalNode.InnerText, out double outInterval) ? outInterval : 30) * 60000;

System.Xml.XmlNode notifTextNode = readFile.SelectSingleNode("/Settings/NotifText");
NotifText = notifTextNode.InnerText;

private async Task CheckTimeStamps() {
DateTime lastUpdated = Settings.LastUpdated;
if (LastRead < lastUpdated) {
Settings = await _context.Settings.SingleOrDefaultAsync();
_timer.Interval = Settings.Interval * 60000;
LastRead = DateTime.Now;
}
}

protected override void OnExit(ExitEventArgs e) {
notifyIcon.Dispose(); // the icon would clean up automatically, but this is cleaner
_notifyIcon.Dispose(); // the icon would clean up automatically, but this is cleaner
base.OnExit(e);
}
}
4 changes: 3 additions & 1 deletion TheShivisiApp/Data/NotifyIconResources.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
<!-- The "shared" directive is needed if we reopen the sample window a few times - WPF will otherwise
reuse the same context menu (which is a resource) again (which will have its DataContext set to the old TaskbarIcon) -->
<ContextMenu x:Shared="false" x:Key="SysTrayMenu">
<MenuItem Header="Open Settings" Command="{Binding ShowWindowCommand}" />
<MenuItem Header="Open settings" Command="{Binding ShowWindowCommand}" />
<MenuItem Header="View quotes" Command="{Binding ShowQuotesCommand}" />
<MenuItem Header="New quote" Command="{Binding NewQuoteWindowCommand}" />
<!--<MenuItem Header="Close Settings" Command="{Binding HideWindowCommand}" />-->
<Separator />
<MenuItem Header="Exit" Command="{Binding ExitApplicationCommand}" />
Expand Down
9 changes: 8 additions & 1 deletion TheShivisiApp/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
global using NotifyIcon;
global using Microsoft.EntityFrameworkCore;
global using Microsoft.Toolkit.Uwp.Notifications;
global using NotifyIcon;
global using Pixata.Extensions;
global using System;
global using System.Collections.ObjectModel;
global using System.IO;
global using System.Reflection;
global using System.Threading.Tasks;
Expand All @@ -8,3 +12,6 @@
global using Telerik.Windows.Controls;
global using Telerik.Windows.Controls.MaterialControls;
global using TheShivisiApp.Helpers;
global using TheShivisiApp.Models;
global using TheShivisiApp.Views;
global using Timer = System.Timers.Timer;
11 changes: 6 additions & 5 deletions TheShivisiApp/Helpers/PopTheToast.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using Microsoft.Toolkit.Uwp.Notifications;

namespace TheShivisiApp.Helpers;
namespace TheShivisiApp.Helpers;

public class PopTheToast {
public static void PopIt(string notifText) =>
public static void PopIt(string notifText, string source, int id) =>
new ToastContentBuilder()
.AddText("The Shivisi App")
.AddText(!string.IsNullOrWhiteSpace(notifText) ? notifText : "Remember!" + Environment.NewLine + "You're not the one in charge here!")
//.AddHeroImage(new Uri("file:///"))
.AddAppLogoOverride(new Uri("file:///" + Path.GetFullPath("Data/Logo.png")), ToastGenericAppLogoCrop.Circle)
.AddAttributionText("Via TSA")
.AddAttributionText(source)
.AddArgument("Text", notifText)
.AddArgument("Source", source)
.AddArgument("Id", id)
.Show(toast => toast.ExpirationTime = DateTime.Now.AddMinutes(1));
}
6 changes: 6 additions & 0 deletions TheShivisiApp/Helpers/VersionHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TheShivisiApp.Helpers;

public static class VersionHelper {
public static Version GetRunningVersion() =>
Assembly.GetExecutingAssembly().GetName().Version;
}
31 changes: 26 additions & 5 deletions TheShivisiApp/TheShivisiApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,26 @@
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows10.0.17763.0</TargetFramework>
<UseWPF>true</UseWPF>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>TheShivisiApp</RootNamespace>
<EnableDefaultItems>False</EnableDefaultItems>
<ApplicationIcon>Data\SNI</ApplicationIcon>
<AssemblyName>The Shivisi App</AssemblyName>
<AssemblyVersion>3.2.2.0</AssemblyVersion>
<FileVersion>3.2.2.0</FileVersion>
<Version>3.2.2</Version>
<AssemblyVersion>4.1.2.0</AssemblyVersion>
<FileVersion>4.1.2.0</FileVersion>
<Version>4.1.2</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.6" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageReference Include="Telerik.UI.for.Wpf.NetCore.Xaml" Version="2022.3.912" />
<PackageReference Include="Telerik.Windows.Themes.Windows11.for.Wpf" Version="2022.3.912" />
<PackageReference Include="Pixata.Extensions" Version="1.25.0" />
</ItemGroup>

<ItemGroup>
Expand All @@ -26,7 +33,16 @@
<Page Include="Data\NotifyIconResources.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings.xaml">
<Page Include="Views\EditQuoteWindow.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\QuotesListWindow.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\QuoteWindow.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsWindow.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Compile Include="App.xaml.cs">
Expand All @@ -36,8 +52,12 @@
<Compile Include="GlobalUsings.cs" />
<Compile Include="Helpers\GridHelper.cs" />
<Compile Include="Helpers\PopTheToast.cs" />
<Compile Include="Helpers\VersionHelper.cs" />
<Compile Include="ViewModels\NotifyIconViewModel.cs" />
<Compile Include="Views\Settings.xaml.cs" />
<Compile Include="Views\EditQuoteWindow.xaml.cs" />
<Compile Include="Views\QuotesListWindow.xaml.cs" />
<Compile Include="Views\QuoteWindow.xaml.cs" />
<Compile Include="Views\SettingsWindow.xaml.cs" />
</ItemGroup>

<ItemGroup>
Expand All @@ -59,6 +79,7 @@
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Resource>
<ProjectReference Include="..\NotifyIcon\NotifyIcon.csproj" />
<ProjectReference Include="..\TheShivisiApp.Models\TheShivisiApp.Models.csproj" />
<Resource Include="Data\SNI">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Resource>
Expand Down
29 changes: 16 additions & 13 deletions TheShivisiApp/ViewModels/NotifyIconViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Windows.Input;
using TheShivisiApp.Views;

namespace TheShivisiApp.ViewModels;

Expand All @@ -9,16 +8,24 @@ namespace TheShivisiApp.ViewModels;
/// in App.xaml.cs could have created this view model, and assigned it to the NotifyIcon.
/// </summary>
public class NotifyIconViewModel {
/// <summary>
/// Shows a window, if none is already open.
/// </summary>
public ICommand ShowWindowCommand => new DelegateCommand {
CanExecuteFunc = () => Application.Current.MainWindow == null,
//CanExecuteFunc = () => Application.Current.MainWindow == null,
CommandAction = () => {
Settings settings = new Settings();
if (settings.Success) {
settings.Show();
}
new SettingsWindow().Show();
}
};

public ICommand ShowQuotesCommand => new DelegateCommand {
//CanExecuteFunc = () => Application.Current.MainWindow == null,
CommandAction = () => {
new QuotesListWindow().Show();
}
};

public ICommand NewQuoteWindowCommand => new DelegateCommand {
//CanExecuteFunc = () => Application.Current.MainWindow == null,
CommandAction = () => {
new EditQuoteWindow(new()).Show();
}
};

Expand All @@ -37,10 +44,6 @@ public class NotifyIconViewModel {
new DelegateCommand { CommandAction = () => Application.Current.Shutdown() };
}


/// <summary>
/// Simplistic delegate command for the demo.
/// </summary>
public class DelegateCommand : ICommand {
public Action CommandAction { get; set; }
public Func<bool> CanExecuteFunc { get; set; }
Expand Down
Loading

0 comments on commit 3966d6e

Please sign in to comment.