-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(workspace): implement daily achievement board
Signed-off-by: hoyho <[email protected]>
- Loading branch information
Showing
10 changed files
with
487 additions
and
183 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text.Json; | ||
using DynamicData; | ||
using DynamicData.Kernel; | ||
using iTimeSlot.Models; | ||
|
||
public interface IStatistics | ||
{ | ||
DailyStat ReadTodayData(); | ||
void ReadWeekData(); | ||
|
||
void CompleteTask(int minute); | ||
void CompleteBreak(int minute); | ||
} | ||
|
||
|
||
//DiskStatistics is a class that implements IStatistics interface using disk as storage | ||
public class DiskStatistics : IStatistics | ||
{ | ||
private string iTimeslotDateFormat ="yyyy-MM-dd"; //date format: 2024-06-01 | ||
private string _dataPath = ""; | ||
|
||
public DiskStatistics(string dataPath) | ||
{ | ||
_dataPath = dataPath; | ||
} | ||
|
||
private void EnsureExist() | ||
{ | ||
if (string.IsNullOrEmpty(_dataPath)) | ||
{ | ||
throw new Exception("Data path is not set"); | ||
} | ||
var parentDir = Path.GetDirectoryName(_dataPath); | ||
if (string.IsNullOrEmpty(parentDir)) | ||
throw new Exception("Invalid Parent directory"); | ||
|
||
if (!Directory.Exists(parentDir)) | ||
{ | ||
Directory.CreateDirectory(parentDir); | ||
} | ||
|
||
if (!File.Exists(_dataPath)) | ||
{ | ||
File.WriteAllText(_dataPath, "{}"); | ||
} | ||
} | ||
|
||
public void CompleteBreak(int minute) | ||
{ | ||
EnsureExist(); | ||
LogFinishedInterval(IntervalType.Break, minute); | ||
} | ||
|
||
public void CompleteTask(int minute) | ||
{ | ||
EnsureExist(); | ||
LogFinishedInterval(IntervalType.Work, minute); | ||
} | ||
|
||
|
||
|
||
private void LogFinishedInterval(IntervalType type, int minute) | ||
{ | ||
//read from disk and update | ||
try | ||
{ | ||
string jsonString = File.ReadAllText(_dataPath); | ||
var stats = JsonSerializer.Deserialize(jsonString, new JsonContext().Stats); | ||
if (stats == null) | ||
{ | ||
stats = new Stats() | ||
{ | ||
DailyStats = new List<DailyStat>() { } | ||
}; | ||
} | ||
else if (stats.DailyStats == null) | ||
{ | ||
stats.DailyStats = new List<DailyStat>() { }; | ||
} | ||
|
||
var entry = new DailyStat() | ||
{ | ||
Date = DateTime.Today.ToString(iTimeslotDateFormat), | ||
}; | ||
|
||
var existed = stats.DailyStats.FirstOrDefault(s => s.Date == DateTime.Today.ToString(iTimeslotDateFormat)); | ||
if (existed != null) | ||
{ | ||
entry = existed; | ||
} | ||
|
||
//update entry | ||
if (type == IntervalType.Work) | ||
{ | ||
entry.WorkCount += 1; | ||
entry.TotalWorkMinutes += minute; | ||
} | ||
else | ||
{ | ||
entry.BreakCount += 1; | ||
entry.TotalBreakMinutes += minute; | ||
} | ||
|
||
//add to list if not existed | ||
if (existed == null) | ||
{ | ||
stats.DailyStats.Add(entry); | ||
} | ||
|
||
var json = JsonSerializer.Serialize(stats, new JsonContext().Stats); | ||
File.WriteAllText(_dataPath, json); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine("Failed to update db:" + ex.Message); | ||
} | ||
|
||
} | ||
|
||
public DailyStat ReadTodayData() | ||
{ | ||
EnsureExist(); | ||
string jsonString = File.ReadAllText(_dataPath); | ||
var stats = JsonSerializer.Deserialize(jsonString, new JsonContext().Stats); | ||
|
||
var ds = new DailyStat() | ||
{ | ||
Date = DateTime.Today.ToString(iTimeslotDateFormat), | ||
}; | ||
|
||
if (stats == null || stats.DailyStats == null) | ||
{ | ||
return ds; | ||
} | ||
|
||
var existed = stats.DailyStats.FirstOrDefault(s => s.Date == DateTime.Today.ToString(iTimeslotDateFormat)); | ||
if (existed != null) | ||
{ | ||
ds = existed; | ||
} | ||
|
||
return ds; | ||
} | ||
|
||
public void ReadWeekData() | ||
{ | ||
EnsureExist(); | ||
throw new NotImplementedException(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,12 @@ | ||
using System; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace iTimeSlot.Models; | ||
|
||
[JsonSerializable(typeof(Settings))] | ||
[JsonSerializable(typeof(bool))] | ||
[JsonSerializable(typeof(int))] | ||
[JsonSerializable(typeof(TimeSpan))] | ||
[JsonSerializable(typeof(TimeSlot))] | ||
using System; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace iTimeSlot.Models; | ||
|
||
[JsonSerializable(typeof(Stats))] | ||
[JsonSerializable(typeof(Settings))] | ||
[JsonSerializable(typeof(bool))] | ||
[JsonSerializable(typeof(int))] | ||
[JsonSerializable(typeof(TimeSpan))] | ||
[JsonSerializable(typeof(TimeSlot))] | ||
internal partial class JsonContext : JsonSerializerContext {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
|
||
|
||
using System; | ||
using System.Collections.Generic; | ||
|
||
public class DailyStat | ||
{ | ||
public string Date { get; set; } | ||
Check warning on line 8 in Models/Stat.cs GitHub Actions / Pre Release (ubuntu-latest)
Check warning on line 8 in Models/Stat.cs GitHub Actions / Pre Release (windows-latest)
|
||
|
||
//WorkCount is the number of work intervals completed | ||
public int WorkCount { get; set; } | ||
|
||
//TotalWorkMinutes is the total minutes spent on work | ||
public int TotalWorkMinutes { get; set; } | ||
|
||
//BreakCount is the number of break intervals completed | ||
public int BreakCount { get; set; } | ||
|
||
//TotalBreakMinutes is the total minutes spent on break | ||
public int TotalBreakMinutes { get; set; } | ||
|
||
} | ||
|
||
public class Stats | ||
{ | ||
public List<DailyStat> DailyStats { get; set; } | ||
Check warning on line 26 in Models/Stat.cs GitHub Actions / Pre Release (ubuntu-latest)
Check warning on line 26 in Models/Stat.cs GitHub Actions / Pre Release (windows-latest)
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,65 @@ | ||
using System; | ||
using System.Text.Json.Serialization; | ||
using CommunityToolkit.Mvvm.ComponentModel; | ||
|
||
namespace iTimeSlot.Models | ||
{ | ||
public class TimeSlot : ObservableObject | ||
{ | ||
public bool IsSystemPreserved { get; set; } | ||
|
||
private TimeSpan _ts; | ||
|
||
[JsonPropertyName("TimeSpan")] | ||
public TimeSpan Ts | ||
{ | ||
get { return _ts; } | ||
set { _ts = value; } | ||
} | ||
|
||
|
||
//keep this public parameterless constructor for json serialization and deserialization | ||
[JsonConstructor] | ||
public TimeSlot() | ||
{ | ||
|
||
} | ||
|
||
public TimeSlot(TimeSpan srcTs, bool isSystemPreserved = false) | ||
{ | ||
this._ts = srcTs; | ||
IsSystemPreserved = isSystemPreserved; | ||
} | ||
|
||
public TimeSlot(int minute, bool isSystemPreserved = false) : this(TimeSpan.FromMinutes(minute), isSystemPreserved) | ||
{ | ||
|
||
} | ||
|
||
public override string ToString() | ||
{ | ||
int m = (int)_ts.TotalMinutes; | ||
string unit = m >1? "mins" : "min"; | ||
return $"{(int)_ts.TotalMinutes} {unit}".TrimEnd(); | ||
} | ||
|
||
public TimeSpan ToTimeSpan() | ||
{ | ||
return _ts; | ||
} | ||
|
||
public int TotalSeconds() | ||
{ | ||
return (int)_ts.TotalSeconds; | ||
} | ||
|
||
} | ||
} | ||
using System; | ||
using System.Text.Json.Serialization; | ||
using CommunityToolkit.Mvvm.ComponentModel; | ||
|
||
namespace iTimeSlot.Models | ||
{ | ||
public class TimeSlot : ObservableObject | ||
{ | ||
public bool IsSystemPreserved { get; set; } | ||
public IntervalType IntervalType { get; set; } | ||
|
||
private TimeSpan _ts; | ||
|
||
[JsonPropertyName("TimeSpan")] | ||
public TimeSpan Ts | ||
{ | ||
get { return _ts; } | ||
set { _ts = value; } | ||
} | ||
|
||
|
||
//keep this public parameterless constructor for json serialization and deserialization | ||
[JsonConstructor] | ||
public TimeSlot() | ||
{ | ||
|
||
} | ||
|
||
public TimeSlot(TimeSpan srcTs, IntervalType iType, bool isSystemPreserved = false) | ||
{ | ||
this._ts = srcTs; | ||
IsSystemPreserved = isSystemPreserved; | ||
IntervalType = iType; | ||
} | ||
|
||
public TimeSlot(int minute, IntervalType iType, bool isSystemPreserved = false) : | ||
this(TimeSpan.FromMinutes(minute),iType, isSystemPreserved) | ||
{ | ||
|
||
} | ||
|
||
public override string ToString() | ||
{ | ||
int m = (int)_ts.TotalMinutes; | ||
string unit = m > 1 ? "mins" : "min"; | ||
return $"{(int)_ts.TotalMinutes} {unit}".TrimEnd(); | ||
} | ||
|
||
public TimeSpan ToTimeSpan() | ||
{ | ||
return _ts; | ||
} | ||
|
||
public int TotalSeconds() | ||
{ | ||
return (int)_ts.TotalSeconds; | ||
} | ||
|
||
} | ||
public enum IntervalType | ||
{ | ||
Work, | ||
Break | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,31 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace iTimeSlot.Shared | ||
{ | ||
|
||
public static class DefaultConfig | ||
{ | ||
public static string[] RemindBefores = new string[] | ||
{ | ||
"1 minute before", | ||
"2 minute before", | ||
"5 minute before", | ||
"10 minute before" | ||
}; | ||
|
||
|
||
public static readonly List<TimeSpan> SysTimeSlots = new List<TimeSpan>{ | ||
TimeSpan.FromMinutes(5), | ||
TimeSpan.FromMinutes(25), | ||
TimeSpan.FromMinutes(60) | ||
}; | ||
|
||
public static readonly bool SysCloseWithoutExit = true; | ||
public static readonly bool SysPlaySound = false; | ||
public static readonly bool SysShowProgInTray = true; | ||
} | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace iTimeSlot.Shared | ||
{ | ||
|
||
public static class DefaultConfig | ||
{ | ||
public static string[] RemindBefores = new string[] | ||
{ | ||
"1 minute before", | ||
"2 minute before", | ||
"5 minute before", | ||
"10 minute before" | ||
}; | ||
|
||
|
||
public static readonly List<TimeSpan> SysWorkTimeSlots = new List<TimeSpan>{ | ||
TimeSpan.FromMinutes(25), | ||
TimeSpan.FromMinutes(60) | ||
}; | ||
public static readonly List<TimeSpan> SysBreakTimeSlots = new List<TimeSpan>{ | ||
TimeSpan.FromMinutes(5), | ||
}; | ||
|
||
public static readonly bool SysCloseWithoutExit = true; | ||
public static readonly bool SysPlaySound = false; | ||
public static readonly bool SysShowProgInTray = true; | ||
} | ||
|
||
} |
Oops, something went wrong.