From f024dfac0d87c020db31cdf94ba544585f4aeb13 Mon Sep 17 00:00:00 2001
From: muellerp <Philipp1.Mueller@Student.Reutlingen-University.de>
Date: Fri, 14 Feb 2025 00:52:44 +0100
Subject: [PATCH] added the tray icon and changed the process monitor to
support breaks
---
.../InnoLabProjektDektopApp/App.xaml.cs | 30 ++-
.../InnoLabProjektDektopApp/Assets/end.png | Bin 0 -> 1206 bytes
.../InnoLabProjektDektopApp/Assets/pause.png | Bin 0 -> 633 bytes
.../InnoLabProjektDektopApp/Assets/skip.png | Bin 0 -> 928 bytes
.../InnoLabProjektDektopApp/Assets/start.png | Bin 0 -> 922 bytes
.../InnoLabProjektDektopApp.csproj | 25 ++-
.../Services/ProcessMonitor.cs | 148 ++++++++++++-
.../Utils/NotifyIconManager.cs | 198 ++++++++++++++++++
.../obj/project.assets.json | 90 ++++++--
9 files changed, 456 insertions(+), 35 deletions(-)
create mode 100644 InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/end.png
create mode 100644 InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/pause.png
create mode 100644 InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/skip.png
create mode 100644 InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/start.png
create mode 100644 InnoLabProjektDektopApp/InnoLabProjektDektopApp/Utils/NotifyIconManager.cs
diff --git a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/App.xaml.cs b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/App.xaml.cs
index c4a739a..7116453 100644
--- a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/App.xaml.cs
+++ b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/App.xaml.cs
@@ -1,4 +1,6 @@
-using System.Configuration;
+using InnoLabProjektDektopApp.Services;
+using InnoLabProjektDektopApp.Utils;
+using System.Configuration;
using System.Data;
using System.Windows;
@@ -9,6 +11,32 @@ namespace InnoLabProjektDektopApp
/// </summary>
public partial class App : Application
{
+ private readonly NotifyIconManager _notifyIcon = new();
+ private static ProcessMonitor _processMonitor = new();
+
+ internal static ProcessMonitor GetProcessMonitor()
+ {
+ return _processMonitor;
+ }
+
+ public App()
+ {
+
+ }
+
+
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ _notifyIcon.Initialize();
+ base.OnStartup(e);
+ }
+
+ protected override void OnExit(ExitEventArgs e)
+ {
+ _notifyIcon.Dispose();
+ base.OnExit(e);
+ }
+
}
}
diff --git a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/end.png b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/end.png
new file mode 100644
index 0000000000000000000000000000000000000000..d474536f30b680927718424c5f2a1d0d3c1ccd84
GIT binary patch
literal 1206
zcmeAS@N?(olHy`uVBq!ia0y~yU`POA4mJh`hDS5XEf^SBYCT;XLn`9l&WT<nVkpq|
zyg^&Q)$wREN8AC{3i0U=glbA{^A59{Kj1B8v|FKI)zq|T2ixoCB?^zul>95v3bkA=
z#l@y}cj~|WA*y#{Q}RXIS29&EyLb4f7J~$T6N3OlkElVJydb%B0Sm*N3Dq@9-#p&T
z{rGp<uKjAf^4+!qzhkR{e68PdSg6jeQY`a)(|^NvBfqKa+lq6kAHPPu*>S^tWArQm
z6Gn$W=1Jm4AL~xOx9(GP_%l68eX||&q1cV{rJ5bM56pb&R`fCW|6ZpXDs`_ur~fQ;
zW^Q6*=;#-)+n;=-qIrY&9~q`a->Xl1TwrLJ)8BVacE+7NYY%sU|5GKzxQmY)XBO12
z6a2iNt>N#>wsT@7N34Xr-0F7q=3j1z6u%Q*D9p=HV8_H#{84d=Sc4SDj3;)Y{Bu)z
zV>{OKHne_7<|@qP5I@R4?fB22VrjprTP9my?rC_^?&*F@K*3J!&Sh4{C3<!J948d_
z=<X@h<#>1GJtxCH3C1YrgxdJ&|IA|F=5+6n)71EWmaFl3%hKYe*7Hp~<rkKiH_Y;g
zFp`Sx&S!0C4X~EnC4OJ1!Hi|io;B)!7n!6?Y|47xa>?VvmN#=-6L=L|omR6iUU+1?
zpX1LL86UF}EI!&YI>bkCM93=YK1?`rT>8em_jAjZDe`NsFcZ2~q%=>suk+#8Lmcb(
z|8IWC%V1Rz$|GOuWjCQ_Cc~WBbKml<lD4T~__chs9OH(UD;$1L{n|c%ZS5B>1xJsk
zimFQa*^k3&N^Tf4eBoyeI)5}^ad7btv3eE;Z-pJ=^&$+W0&Xi070+)9x|J9#$Z$uv
zIKKN;EnkF@B)=f*Jw^ln<FnN=zkhB>XYfAi?-1ksfos9kAMX?^SPEQ2oI5K{uI^Yr
z`Ot2zMq!pcT@Gho{hr0nwYGQ<V}e`VF9+t_N2xK*f<emvsy^+u*J9BZ+~D%($h_7E
zk7hTpGw5cUN^-32-oI*6gDJzZ5*52s;fnX_Cbj*jwCdV4MfQNi$B9~5s~$(l>z-10
zX_z&!sfz3JWpQ0QzZbj*oCL0=`)&#Cyf4k5?Q(j`fggHv->h~$@Bc=WF+wiNze`W?
z3&VrV+;@CUW(@w1mY>M~`Cz*RZzj_RjXI$<M_2bBeU$BYsOLx6)>%3&d&IVO{)l3T
z_^7*meWJn|SA#WYf*cEkIixf>-ap%T^5UI`OT#9wbd^oo+;@0aEbqR3iO2Q7-@cmg
zq<>f9<!w<RIXAA<tXEiTsjzgO;C7wcAq-|urlnf4T=|uJ+3xyN#hWctoh7O+?<?_N
zkyoMhE#S=WzRs2B+tY5J+Bx;Y#Q*Whl2uP!Q&~6|dZM^;nH!o`oKa<FSUk<?Hp2o1
zt>Tjm2UaY-V8)=)aVo}$!5~X>3oirLBBSX%<SYNrG<%0yfzIKJpBNYz7(8A5T-G@y
GGywpvZvfT+
literal 0
HcmV?d00001
diff --git a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/pause.png b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/pause.png
new file mode 100644
index 0000000000000000000000000000000000000000..d4d8de1c99759bb7fe97ee7c69ed0c709950ef02
GIT binary patch
literal 633
zcmeAS@N?(olHy`uVBq!ia0y~yU`POA4mJh`hDS5XEf^S>96VhdLn`9lPLIxGa^zuo
z_^;iM#nDTJ>Fu=bS8uNPA=`g8toM20-VdvVc7&}C{?pX(Ny&kM=@iSUr!N^;rf^O<
zeVLI%Ls(<_a%O=5wE#VTc7+8#3u5N+IXKL8*l8o%&|uV9RB6S)n9B6@Q^^5)kq?6Z
z)V5~a`nvXfxO}o|HOqF!Ew7``2qZk*#V&v9&4rW_hns3l0tLzkBp<A2&ThM9CYbQ>
zOS7QDjFqB0Sbto99_{T_+cPz%f@Afpbny(sV1qR&93Ki5AI!YDjaiqQ!{LB%<6Ewr
z^UIl87_WYfZsc${P|fsGbVuyL+doSfWF6Rhc01&<KX$Qa+OAvk?WdSA%Ll#(vI$$y
zDExR6ed61Heu3Kd4XhhkH?l_R8gty+_TlDpeu0gwdz-h!GH^UlJ>y+*hxJa=4%R|$
zsqLo?3aUHi*8UT?94-+p5G@cr;i^&dgU$JhxBuHa9C7Yxzah<ZTlB^}fA$YT&s1&R
zF|At|<Gi!2?{=!h4Lg?GU)yI?aPDW?D%!!2=Xj^-SnL7aj%b1H3krAhFmG?aaq~I9
z;nzIJYw~|oBXVbZCG6TaHNLiI>Knm3Y!}w$8#*_%zLu-e*z7#{B4g@o4u=E14CxK~
z`PN8g-F9hcz0B{{aK1-!J;#cxEISPtSy~uZf8hvdIrNx=gE{P_-~x`;<AMTgYc44}
z2y*o+EAT`tb#G7-k#l#D*x=RA;HqKM*I<w^RgSSMphAW*@qm^slgPpk7EFg4LaSIb
foE{b;44fb7a3FEtPa$_lOCS3j3^P6<r_iYx`z
literal 0
HcmV?d00001
diff --git a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/skip.png b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/skip.png
new file mode 100644
index 0000000000000000000000000000000000000000..8008a3bf5f57d0d46ac19a70efcc243cdc2c4967
GIT binary patch
literal 928
zcmeAS@N?(olHy`uVBq!ia0y~yU`POA4mJh`hDS5XEf^S>(>+}rLn`9l&N=8M6DZ*N
zm6=IVfl;yk@iE`BNi5<{n@*qCXxuTWWzFOHN9!+yKX4F!^RoQ;-stU4?+!F4YOG%O
zJ*4#eo;+K-Pu{N%Y}~S|TVAqZ2Pe+~h9i6(r>mKG9NskS*rQGf_kldqhuxWfZ(Wn$
z_-yN^t6%r7ke=CaJpD8Cp;||dt6zN?H+Ty%tnzhcSg|HwtHDF8eUaDY4J-kH_e&VA
z?s}WgaP`YYhLD%rOc_GI1Tu!a*jCG+^}?HR!JBPz3|_UF3?X-~aXT#4mvt!HzK~(l
zS5JnNvfGLbMqfP{Q%Y`gH1O0GF}%r>W<78%oQ+}i?KH-Om)fii7jumn4Zd7tjM>7q
zJ$LS&h|Ir-Bdfil8Ls?#!H|^w+c*0D?Oz;D9Um^rUejgBs?}sDbG^6Sy!_<l3(O8H
z^+g>-x-)-VyOw&%M1eu%*Coa`T=TY@+uyF@ZgM!!tI?2CYs3)vqcqw)H?~n=Lh<2+
z44b}qGV1KsJ;%FTp<`aA1mlE->scBEKEA4yvTGLDwk(m2Vc9+-hBBvfw`Ru+FHaO>
zn6_^cL!C+J`vaa4)-r|+XRd^^Imk4vyZwtvYJMe0(hF_Igl~!IKfTY+U|43S$q?VR
zuE+XU#-n|Uk45R#3*LS#CET!G$;z)thv8n&YXf_yH0F+V{nbqJR<HFBZ`!sv^w$gZ
zhyH7w-qbBJPm#NI{)qFwk2U{KWWUz(SliF{K;X06Zn>R2p|7=B7o->Sn&xCPO{n3i
zO=URqrs^2WhA$@>H|)+TVY=~a34_tDEEb10JI;nP>#SHDmhCHHxEb5ZbmH1{HixUB
zdl^E01u<ysUd7%JBrodFy6#v0e~<NE;cFRJEXx1I67u3#ZTyi{FK2TtND9|gU$AJO
zCWBUaC@3LFIDD;V501TWz>s2oapPP*h4Ld-!B#wl2N(plb8KXDFc9_3Wax-)iC|Wk
z(Y3^c;fSu&8b$#h*B~i|M`DWC7&w+GY4S1@b_--Pumn$>!q%|EwZoL5X{Co3v%?*w
wBT@_pLsXVBD&z?!@iruAO}a$LSUbjC8Ha*N=l-xVFfcH9y85}Sb4q9e028-`)Bpeg
literal 0
HcmV?d00001
diff --git a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/start.png b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Assets/start.png
new file mode 100644
index 0000000000000000000000000000000000000000..abda107909a20c2245dcd84c6b6e138357e5b7c2
GIT binary patch
literal 922
zcmeAS@N?(olHy`uVBq!ia0y~yU`POA4mJh`hDS5XEf^S>6FprVLn`9l&f33@FHq#@
zerch=ol{*_hhL~>I@`;BVZn#xP8#bqG&EEf3HC~HzF+W&@ynMIscT+yK0VuA{mgpv
zxqF-aHWfctOW$X^xo-3GHO0@~<lb4r^~Q6v_0MArNBA2VB^n|a3#-B#7&}A-mY1`V
z#y#-N)?`QT56x>%lj>Tyeso*^Z>?yl=zZ{ib>?D*jHdd72ThNB-zp%%%TW5ixuUJ&
z*Z&<R-GYoJ2P0Y6u!XtaG&5r8I`^^R@ge6U@4H0Y*e{qYciz?cBZk*WjKQ}&>Y8<j
z(KJ(Oh9-^FNMj}t!JIK|YT49nQ@@$Up5{~7o4S@sVQuPK7KNp$XBi$yPuXkn@aeom
zo6;BxgdW{@w{e@p*CcUoQyRmCbsuex)OYWYX*uxj@VZTDOczS_H#R@-_^ZHi>&io&
zY&V80e{~-5KJpS^+ReZ9)GSel%YU`_;*`#@I`V8jHA|ME)V{f*@xf}%TTfQ65oIvB
zXlYSA;aP%guF>fzP6k)|){3Sb?F(vqO*&K8vMu1OV`P6X@JBkgJL=jh28~~wN0^T&
zDp@r~pV<_~c46KhOW_^wrj_zCNOi0f-mz|4sV@UZ(m9rO-Knw440*+t9ernB_%qx&
z{44R$PWO46)EMemWj{*f-0rdduJ}=5&(f4?#s$1{f5|3p{JXMv{<_#beANseTyz}L
zrZemj5fs>0dRMf;vb*q3@u|JbyYnm8eBjDDeet?t!k4<b2Xl6FtZVa%`qES#^JEU!
z198JT$;T|(mv)`YQx=~j%D`IR`apbR#_N6igm*6JVOZw3LTvN2P{uPe19W#Ci|1`H
zPjl_?d$BuL;9uAMJthy!?H|pF=E|1bd5tI8;Yr<%?Wb3zeo^YXy<eyyam~}hqv`v#
z7}_>X%VsiIvNeXgA#rVLDZ?b*5Wzs@+ReR;n?g@_teChjlHo+SuJR(cUwwQEOSi6J
zQdqn744=Z@t!H=^v}`@Yv0%#9Gi(op^&&nw+9-vr->1A|LEQIgkIH!+dQLL%IIL-~
o*sFbj;Rsj9<=srAbN|}wiQh_8U8irwz`(%Z>FVdQ&MBb@0MXTy(f|Me
literal 0
HcmV?d00001
diff --git a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/InnoLabProjektDektopApp.csproj b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/InnoLabProjektDektopApp.csproj
index 63aa5dd..1d636e3 100644
--- a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/InnoLabProjektDektopApp.csproj
+++ b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/InnoLabProjektDektopApp.csproj
@@ -17,17 +17,21 @@
<None Remove="Assets\blockedProcesses.json" />
<None Remove="Assets\distractingPrograms.json" />
<None Remove="Assets\distractingWebsites.json" />
+ <None Remove="Assets\end.png" />
<None Remove="Assets\gamesicon.png" />
<None Remove="Assets\icon.ico" />
<None Remove="Assets\logo.png" />
<None Remove="Assets\otherwebsitesicon.png" />
+ <None Remove="Assets\pause.png" />
<None Remove="Assets\pencilicon.png" />
<None Remove="Assets\pornicon.png" />
<None Remove="Assets\profileicon.png" />
<None Remove="Assets\programsicon.png" />
<None Remove="Assets\settings.json" />
<None Remove="Assets\shoppingicon.png" />
+ <None Remove="Assets\skip.png" />
<None Remove="Assets\socialmediaicon.png" />
+ <None Remove="Assets\start.png" />
<None Remove="Screens\FirstLaunch\Mascott_InnoLab.jpg" />
</ItemGroup>
@@ -48,8 +52,9 @@
</ItemGroup>
<ItemGroup>
+ <PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="2.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
- <PackageReference Include="System.Management" Version="9.0.0" />
+ <PackageReference Include="System.Management" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
@@ -62,9 +67,15 @@
<Content Include="Assets\distractingWebsites.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="Assets\end.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
<Content Include="Assets\gamesicon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="Assets\pause.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
<Content Include="Assets\pencilicon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -83,12 +94,18 @@
<Content Include="Assets\shoppingicon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="Assets\skip.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
<Content Include="Assets\socialmediaicon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Resource Include="Assets\icon.ico">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Resource>
+ <Content Include="Assets\icon.ico">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Assets\start.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
<Resource Include="Assets\logo.png" />
<Content Include="Assets\otherwebsitesicon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
diff --git a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Services/ProcessMonitor.cs b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Services/ProcessMonitor.cs
index 026c355..23cc27e 100644
--- a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Services/ProcessMonitor.cs
+++ b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Services/ProcessMonitor.cs
@@ -13,23 +13,38 @@ namespace InnoLabProjektDektopApp.Services
public DateTime EndTime { get; set; } = endTime;
}
+ public class BreakInfo(DateTime startTime, DateTime endTime)
+ {
+ public DateTime StartTime { get; set; } = startTime;
+ public DateTime EndTime { get; set; } = endTime;
+ }
+
class ProcessMonitor
{
- private readonly Dictionary<string, DateTime> processStartTimes = new Dictionary<string, DateTime>();
- private static List<string> blockedProcesses = new List<string>();
- private bool isMonitoring = false;
- private readonly List<ProcessInfo> processInfoList = new List<ProcessInfo>();
+ private static List<string> blockedProcesses = [];
+
+ private readonly Dictionary<string, DateTime> processStartTimes = [];
+ private readonly List<ProcessInfo> processInfoList = [];
+ public bool isMonitoring = false;
private DateTime startTime;
+ private readonly List<BreakInfo> breakInfoList = [];
+ public bool IsBreak { get; private set;}
+ private DateTime breakStartTime;
+
public ProcessMonitor()
{
+ IsBreak = false;
blockedProcesses = LoadBlockedProcesses();
-
}
public async void StartMonitoring()
{
+ if (isMonitoring || IsBreak)
+ {
+ return;
+ }
startTime = DateTime.Now;
Debug.WriteLine("Started Process Monitoring");
var query = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 1),
@@ -37,26 +52,100 @@ namespace InnoLabProjektDektopApp.Services
var watcher = new ManagementEventWatcher { Query = query };
isMonitoring = true;
+
+ // check if any distracting processes are already running
+ var processes = GetRunningProcessList();
+ foreach (var process in processes)
+ {
+ if (IsProcessOnBlockedList(process.Key))
+ {
+ var result = MessageBox.Show($"Are you sure you want to get distracted by {process.Key}?", "Distracting Process Detected",
+ MessageBoxButton.YesNo,
+ MessageBoxImage.Question,
+ MessageBoxResult.No,
+ MessageBoxOptions.DefaultDesktopOnly
+ );
+ if (result == MessageBoxResult.No)
+ {
+ KillProcessesByName(process.Key);
+ }
+ else
+ {
+ TrackProcess(process.Key, DateTime.Now);
+ }
+ }
+ }
+
await Task.Run(() =>
{
while (isMonitoring)
{
// this wait is here to prevent another event from being triggered before the previous one is handled
- var e = watcher.WaitForNextEvent();
- Task.Run(() => HandleNewProcess(e));
- Task.Delay(100).Wait();
+ var task = Task.Run(() => watcher.WaitForNextEvent());
+ if (Task.WaitAny(task, Task.Delay(100)) == 0)
+ {
+ if (!isMonitoring) break;
+ Task.Run(() => HandleNewProcess(task.Result));
+ }
}
});
}
public void StopMonitoring()
{
+ if (!isMonitoring)
+ {
+ return;
+ }
Debug.WriteLine("Stopping Process Monitoring");
CalculateCurrentDistractionStage(DateTime.Now);
isMonitoring = false;
}
- public void CalculateCurrentDistractionStage(DateTime endTime)
+ public void StartBreak()
+ {
+ if (IsBreak)
+ {
+ return;
+ }
+ IsBreak = true;
+ breakStartTime = DateTime.Now;
+ StopMonitoring();
+ }
+
+ public void EndBreak()
+ {
+ if (!IsBreak)
+ {
+ return;
+ }
+ breakInfoList.Add(new BreakInfo(breakStartTime, DateTime.Now));
+ IsBreak = false;
+ StartMonitoring();
+ }
+
+ public void FinishSession()
+ {
+ StopMonitoring();
+ EndBreak();
+
+ // save the processInfoList and breakInfoList to a file
+ var processInfoListFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets\\processInfoList.json");
+ var processInfoListJson = JsonConvert.SerializeObject(processInfoList);
+ File.WriteAllText(processInfoListFilePath, processInfoListJson);
+
+ var breakInfoListFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets\\breakInfoList.json");
+ var breakInfoListJson = JsonConvert.SerializeObject(breakInfoList);
+ File.WriteAllText(breakInfoListFilePath, breakInfoListJson);
+
+ // reset the processInfoList and breakInfoList
+ processInfoList.Clear();
+ breakInfoList.Clear();
+ processStartTimes.Clear();
+
+ }
+
+ public int CalculateCurrentDistractionStage(DateTime endTime)
{
TimeSpan totalDistractionTime = CalculateTotalDistractionTime();
@@ -69,6 +158,7 @@ namespace InnoLabProjektDektopApp.Services
double distractionFraction = (distractedMinutes / totalMinutes);
int stage = (int)Math.Ceiling(distractionFraction * 7);
Debug.WriteLine($"Distraction stage: {stage}");
+ return stage;
}
@@ -231,19 +321,59 @@ namespace InnoLabProjektDektopApp.Services
var mergedIntervals = new List<(DateTime Start, DateTime End)> { intervals[0] };
+ // Iterate through the intervals, starting from the second one
foreach (var interval in intervals.Skip(1))
{
var last = mergedIntervals.Last();
+ // If the current interval overlaps with the last merged interval, merge them
if (interval.StartTime <= last.End)
{
mergedIntervals[^1] = (last.Start, new DateTime(Math.Max(last.End.Ticks, interval.EndTime.Ticks)));
}
else
{
+ // Otherwise, add the current interval as a new merged interval
mergedIntervals.Add(interval);
}
}
+ // Remove overlaps with breaks
+ foreach (var breakInfo in breakInfoList)
+ {
+ mergedIntervals = mergedIntervals.SelectMany(interval =>
+ {
+ // If the interval ends before the break starts or starts after the break ends, keep the interval as is
+ if (interval.End <= breakInfo.StartTime || interval.Start >= breakInfo.EndTime)
+ {
+ return [interval];
+ }
+ // If the interval starts before the break and ends after the break, split the interval into two
+ else if (interval.Start < breakInfo.StartTime && interval.End > breakInfo.EndTime)
+ {
+ return
+ [
+ (interval.Start, breakInfo.StartTime),
+ (breakInfo.EndTime, interval.End)
+ ];
+ }
+ // If the interval starts before the break and ends during the break, adjust the end time to the start of the break
+ else if (interval.Start < breakInfo.StartTime)
+ {
+ return new List<(DateTime Start, DateTime End)> { (interval.Start, breakInfo.StartTime) };
+ }
+ // If the interval starts during the break and ends after the break, adjust the start time to the end of the break
+ else if (interval.End > breakInfo.EndTime)
+ {
+ return [(breakInfo.EndTime, interval.End)];
+ }
+ // If the interval is completely within the break, remove the interval
+ else
+ {
+ return [];
+ }
+ }).ToList();
+ }
+
return mergedIntervals.Aggregate(TimeSpan.Zero, (sum, interval) => sum + (interval.End - interval.Start));
}
diff --git a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Utils/NotifyIconManager.cs b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Utils/NotifyIconManager.cs
new file mode 100644
index 0000000..dc6b7a1
--- /dev/null
+++ b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/Utils/NotifyIconManager.cs
@@ -0,0 +1,198 @@
+using InnoLabProjektDektopApp.Services;
+using System;
+using Drawing = System.Drawing;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Threading;
+using Forms = System.Windows.Forms;
+using System.Windows.Media;
+using System.Windows.Navigation;
+using System.IO;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+using System.Net.Http.Json;
+using System.Text.Json;
+
+namespace InnoLabProjektDektopApp.Utils
+{
+ internal class NotifyIconManager
+ {
+ private readonly Forms.NotifyIcon _notifyIcon = new();
+ private readonly ProcessMonitor _processMonitor = App.GetProcessMonitor();
+ private DispatcherTimer _countdownTimer;
+ private TimeSpan _countdownTime;
+ private Forms.ToolStripLabel _countdownLabel; // Reference to the countdown label
+ private class Settings
+ {
+ public int focusPeriod { get; set; }
+ public int breakPeriod { get; set; }
+ public int cycles { get; set; }
+ public string distractionMode { get; set; }
+ public string mascotVisible { get; set; }
+ public bool wordsOfAffirmation { get; set; }
+ public bool insultingWords { get; set; }
+ }
+ private Settings _settings = new();
+
+ public void Initialize()
+ {
+ _notifyIcon.Icon = new Drawing.Icon("Assets/icon.ico");
+ _notifyIcon.Text = "CoFlow";
+ _notifyIcon.Visible = true;
+ _notifyIcon.ContextMenuStrip = new Forms.ContextMenuStrip();
+ _notifyIcon.MouseClick += NotifyIcon_MouseClick;
+
+ // Initialize the countdown timer
+ _countdownTimer = new DispatcherTimer();
+ _countdownTimer.Interval = TimeSpan.FromSeconds(1);
+ _countdownTimer.Tick += CountdownTimer_Tick;
+
+ RerenderContextMenu();
+ }
+
+ public void Dispose()
+ {
+ _notifyIcon.Dispose();
+ _countdownTimer.Stop();
+ }
+
+ private void RerenderContextMenu(bool showContextMenu = false)
+ {
+ _notifyIcon.ContextMenuStrip.Items.Clear();
+ LoadSettings();
+
+ if (_processMonitor.isMonitoring || _processMonitor.IsBreak)
+ {
+ _notifyIcon.ContextMenuStrip.Items.Add(new Forms.ToolStripLabel($"Focussession 1/{_settings.cycles}", null, false));
+ // Add the countdown label (initialize it if it doesn't exist)
+ _countdownLabel = new Forms.ToolStripLabel($"Countdown: {_countdownTime:mm\\:ss}");
+ _notifyIcon.ContextMenuStrip.Items.Add(_countdownLabel);
+ if (!_processMonitor.IsBreak)
+ {
+ _notifyIcon.ContextMenuStrip.Items.Add("Take a Break", Drawing.Image.FromFile("Assets/pause.png"), (sender, args) =>
+ {
+ _countdownTimer.Stop();
+ _processMonitor.StartBreak();
+ RerenderContextMenu(true);
+ });
+ }
+ if (_processMonitor.IsBreak)
+ {
+ _notifyIcon.ContextMenuStrip.Items.Add("Skip Break", Drawing.Image.FromFile("Assets/skip.png"), (sender, args) =>
+ {
+ _countdownTimer.Start();
+ _processMonitor.EndBreak();
+ RerenderContextMenu(true);
+ });
+ }
+ _notifyIcon.ContextMenuStrip.Items.Add("End Session", Drawing.Image.FromFile("Assets/end.png"), (sender, args) =>
+ {
+ _processMonitor.StopMonitoring();
+ StopCountdown();
+ Window mainWindow = Application.Current.MainWindow;
+ NavigationService mainNavigation = ((System.Windows.Navigation.NavigationWindow)mainWindow).NavigationService;
+ mainNavigation.Navigate(new Overview());
+ RerenderContextMenu(true);
+ });
+ }
+ else
+ {
+ _notifyIcon.ContextMenuStrip.Items.Add(new Forms.ToolStripLabel("Current Settings:", null, false));
+ _notifyIcon.ContextMenuStrip.Items.Add(new Forms.ToolStripLabel(
+ $"Focus Duration: {_settings.focusPeriod} min | Break Duration: {_settings.breakPeriod} min | Cycles: {_settings.cycles}", null, false));
+ _notifyIcon.ContextMenuStrip.Items.Add("Start Session", Drawing.Image.FromFile("Assets/start.png"), (sender, args) =>
+ {
+ _processMonitor.StartMonitoring();
+ StartCountdown(TimeSpan.FromMinutes(_settings.focusPeriod));
+ RerenderContextMenu(true);
+ Window mainWindow = Application.Current.MainWindow;
+ NavigationService mainNavigation = ((System.Windows.Navigation.NavigationWindow)mainWindow).NavigationService;
+ mainNavigation.Navigate(
+ new Session(_settings.focusPeriod,
+ _settings.breakPeriod,
+ _settings.cycles,
+ _settings.distractionMode,
+ _settings.mascotVisible,
+ _settings.wordsOfAffirmation,
+ _settings.insultingWords));
+ });
+ }
+
+
+ // Reopen the context menu if requested
+ if (showContextMenu)
+ {
+ _notifyIcon.ContextMenuStrip.Show();
+ }
+ }
+
+ private void NotifyIcon_MouseClick(object sender, Forms.MouseEventArgs e)
+ {
+ if (e.Button == Forms.MouseButtons.Left)
+ {
+ Window mainWindow = Application.Current.MainWindow;
+ mainWindow.WindowState = WindowState.Normal;
+ mainWindow.Activate();
+ NavigationService mainNavigation = ((System.Windows.Navigation.NavigationWindow)mainWindow).NavigationService;
+ if (!_processMonitor.isMonitoring && !_processMonitor.IsBreak)
+ {
+ mainNavigation.Navigate(new Overview());
+ }
+ }
+ }
+
+ private void StartCountdown(TimeSpan duration)
+ {
+ _countdownTime = duration;
+ _countdownTimer.Start();
+ }
+
+ private void StopCountdown()
+ {
+ _countdownTimer.Stop();
+ _countdownTime = TimeSpan.Zero;
+ UpdateCountdownLabel(); // Update the label to show 00:00
+ }
+
+ private void CountdownTimer_Tick(object sender, EventArgs e)
+ {
+ if (_countdownTime > TimeSpan.Zero)
+ {
+ _countdownTime = _countdownTime.Subtract(TimeSpan.FromSeconds(1));
+ UpdateCountdownLabel(); // Update only the countdown label
+ }
+ else
+ {
+ _countdownTimer.Stop();
+ }
+ }
+
+ private void UpdateCountdownLabel()
+ {
+ if (_countdownLabel != null)
+ {
+ _countdownLabel.Text = $"Countdown: {_countdownTime:mm\\:ss}";
+ }
+ }
+
+ private void LoadSettings()
+ {
+ string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "settings.json");
+ if (File.Exists(path))
+ {
+ string jsonContent = File.ReadAllText(path);
+ var settings = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(jsonContent);
+ if (settings != null && settings.TryGetValue("profile1", out JsonElement profileSettings))
+ {
+ _settings.focusPeriod = int.Parse(profileSettings.GetProperty("focusPeriod").GetString().Replace(" minutes", ""));
+ _settings.breakPeriod = int.Parse(profileSettings.GetProperty("breakPeriod").GetString().Replace(" minutes", ""));
+ _settings.cycles = int.Parse(profileSettings.GetProperty("cycles").GetString() ?? "1");
+ _settings.distractionMode = profileSettings.GetProperty("distractionMode").GetString() ?? "default";
+ _settings.mascotVisible = profileSettings.GetProperty("mascotVisibility").GetString() ?? "yes";
+ _settings.wordsOfAffirmation = bool.Parse(profileSettings.GetProperty("wordsOfAffirmation").GetString() ?? "true");
+ _settings.insultingWords = bool.Parse(profileSettings.GetProperty("insultingWords").GetString() ?? "false");
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/obj/project.assets.json b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/obj/project.assets.json
index 5c0a935..1d3f3fa 100644
--- a/InnoLabProjektDektopApp/InnoLabProjektDektopApp/obj/project.assets.json
+++ b/InnoLabProjektDektopApp/InnoLabProjektDektopApp/obj/project.assets.json
@@ -2,6 +2,22 @@
"version": 3,
"targets": {
"net8.0-windows7.0": {
+ "Hardcodet.NotifyIcon.Wpf/2.0.1": {
+ "type": "package",
+ "compile": {
+ "lib/net8.0-windows7.0/Hardcodet.NotifyIcon.Wpf.dll": {
+ "related": ".xml"
+ }
+ },
+ "runtime": {
+ "lib/net8.0-windows7.0/Hardcodet.NotifyIcon.Wpf.dll": {
+ "related": ".xml"
+ }
+ },
+ "frameworkReferences": [
+ "Microsoft.WindowsDesktop.App"
+ ]
+ },
"Newtonsoft.Json/13.0.3": {
"type": "package",
"compile": {
@@ -15,7 +31,7 @@
}
}
},
- "System.CodeDom/9.0.0": {
+ "System.CodeDom/9.0.1": {
"type": "package",
"compile": {
"lib/net8.0/System.CodeDom.dll": {
@@ -31,10 +47,10 @@
"buildTransitive/net8.0/_._": {}
}
},
- "System.Management/9.0.0": {
+ "System.Management/9.0.1": {
"type": "package",
"dependencies": {
- "System.CodeDom": "9.0.0"
+ "System.CodeDom": "9.0.1"
},
"compile": {
"lib/net8.0/System.Management.dll": {
@@ -59,6 +75,27 @@
}
},
"libraries": {
+ "Hardcodet.NotifyIcon.Wpf/2.0.1": {
+ "sha512": "dtxmeZXzV2GzSm91aZ3hqzgoeVoARSkDPVCYfhVUNyyKBWYxMgNC0EcLiSYxD4Uc4alq/2qb3SmV8DgAENLRLQ==",
+ "type": "package",
+ "path": "hardcodet.notifyicon.wpf/2.0.1",
+ "files": [
+ ".nupkg.metadata",
+ ".signature.p7s",
+ "LICENSE",
+ "hardcodet.notifyicon.wpf.2.0.1.nupkg.sha512",
+ "hardcodet.notifyicon.wpf.nuspec",
+ "icon.png",
+ "lib/net462/Hardcodet.NotifyIcon.Wpf.dll",
+ "lib/net462/Hardcodet.NotifyIcon.Wpf.xml",
+ "lib/net472/Hardcodet.NotifyIcon.Wpf.dll",
+ "lib/net472/Hardcodet.NotifyIcon.Wpf.xml",
+ "lib/net6.0-windows7.0/Hardcodet.NotifyIcon.Wpf.dll",
+ "lib/net6.0-windows7.0/Hardcodet.NotifyIcon.Wpf.xml",
+ "lib/net8.0-windows7.0/Hardcodet.NotifyIcon.Wpf.dll",
+ "lib/net8.0-windows7.0/Hardcodet.NotifyIcon.Wpf.xml"
+ ]
+ },
"Newtonsoft.Json/13.0.3": {
"sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==",
"type": "package",
@@ -89,10 +126,10 @@
"packageIcon.png"
]
},
- "System.CodeDom/9.0.0": {
- "sha512": "oTE5IfuMoET8yaZP/vdvy9xO47guAv/rOhe4DODuFBN3ySprcQOlXqO3j+e/H/YpKKR5sglrxRaZ2HYOhNJrqA==",
+ "System.CodeDom/9.0.1": {
+ "sha512": "2J5uq+2smnj+u1jlyVJ6BGGqaK9fHcK/EwN7mbsuPqTI6dZr86br8Cg6o/5B+icQ9ANTvTDpJjnhDNtYYZijHQ==",
"type": "package",
- "path": "system.codedom/9.0.0",
+ "path": "system.codedom/9.0.1",
"files": [
".nupkg.metadata",
".signature.p7s",
@@ -112,15 +149,15 @@
"lib/net9.0/System.CodeDom.xml",
"lib/netstandard2.0/System.CodeDom.dll",
"lib/netstandard2.0/System.CodeDom.xml",
- "system.codedom.9.0.0.nupkg.sha512",
+ "system.codedom.9.0.1.nupkg.sha512",
"system.codedom.nuspec",
"useSharedDesignerContext.txt"
]
},
- "System.Management/9.0.0": {
- "sha512": "bVh4xAMI5grY5GZoklKcMBLirhC8Lqzp63Ft3zXJacwGAlLyFdF4k0qz4pnKIlO6HyL2Z4zqmHm9UkzEo6FFsA==",
+ "System.Management/9.0.1": {
+ "sha512": "CLEo9O6FuO4GQ3ZQkGssg9CJ2w2TN7GMFf3wHTc7YVWJV4xoyJRPw+XIDQnCcSUJCrHhrAWOO60cAX29EV5LFQ==",
"type": "package",
- "path": "system.management/9.0.0",
+ "path": "system.management/9.0.1",
"files": [
".nupkg.metadata",
".signature.p7s",
@@ -141,7 +178,7 @@
"runtimes/win/lib/net8.0/System.Management.xml",
"runtimes/win/lib/net9.0/System.Management.dll",
"runtimes/win/lib/net9.0/System.Management.xml",
- "system.management.9.0.0.nupkg.sha512",
+ "system.management.9.0.1.nupkg.sha512",
"system.management.nuspec",
"useSharedDesignerContext.txt"
]
@@ -149,24 +186,30 @@
},
"projectFileDependencyGroups": {
"net8.0-windows7.0": [
+ "Hardcodet.NotifyIcon.Wpf >= 2.0.1",
"Newtonsoft.Json >= 13.0.3",
- "System.Management >= 9.0.0"
+ "System.Management >= 9.0.1"
]
},
"packageFolders": {
- "C:\\Users\\Sandra\\.nuget\\packages\\": {}
+ "C:\\Users\\Phil\\.nuget\\packages\\": {},
+ "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
},
"project": {
"version": "1.0.0",
"restore": {
- "projectUniqueName": "D:\\Studium\\7. Semester\\InnoLab\\CoFlowCURRENT\\CoFlow\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp.csproj",
+ "projectUniqueName": "C:\\Users\\Phil\\Source\\Repos\\CoFlow\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp.csproj",
"projectName": "CoFlow",
- "projectPath": "D:\\Studium\\7. Semester\\InnoLab\\CoFlowCURRENT\\CoFlow\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp.csproj",
- "packagesPath": "C:\\Users\\Sandra\\.nuget\\packages\\",
- "outputPath": "D:\\Studium\\7. Semester\\InnoLab\\CoFlowCURRENT\\CoFlow\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp\\obj\\",
+ "projectPath": "C:\\Users\\Phil\\Source\\Repos\\CoFlow\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp.csproj",
+ "packagesPath": "C:\\Users\\Phil\\.nuget\\packages\\",
+ "outputPath": "C:\\Users\\Phil\\Source\\Repos\\CoFlow\\InnoLabProjektDektopApp\\InnoLabProjektDektopApp\\obj\\",
"projectStyle": "PackageReference",
+ "fallbackFolders": [
+ "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
+ ],
"configFilePaths": [
- "C:\\Users\\Sandra\\AppData\\Roaming\\NuGet\\NuGet.Config",
+ "C:\\Users\\Phil\\AppData\\Roaming\\NuGet\\NuGet.Config",
+ "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
@@ -191,19 +234,24 @@
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
- }
+ },
+ "SdkAnalysisLevel": "9.0.100"
},
"frameworks": {
"net8.0-windows7.0": {
"targetAlias": "net8.0-windows",
"dependencies": {
+ "Hardcodet.NotifyIcon.Wpf": {
+ "target": "Package",
+ "version": "[2.0.1, )"
+ },
"Newtonsoft.Json": {
"target": "Package",
"version": "[13.0.3, )"
},
"System.Management": {
"target": "Package",
- "version": "[9.0.0, )"
+ "version": "[9.0.1, )"
}
},
"imports": [
@@ -225,7 +273,7 @@
"privateAssets": "none"
}
},
- "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.204/PortableRuntimeIdentifierGraph.json"
+ "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.103/PortableRuntimeIdentifierGraph.json"
}
}
}
--
GitLab