Last updated on April 11, 2024
Sometimes, it’s just about simplifying my work-life. Regardless of where I’ve worked, filling out time sheets has always been a required part of my working life chore. There are times when I’m diligent at it then there are times when, more often than I would like to admit, I end up playing the guessing game at the end of the week or end of the month. Sure, you could use Outlook Journal to keep track of your hours and I have in the past. It’s just not ideal when you’re interrupted with support issues throughout the day. I need to simplify how I track my time. And so, TimeTracker was born.
The key success factor is to ensure the user only performs minimal amount of steps. Too many steps and we end up with another chore for the user. If I could keep it down to 2 clicks, this tool will work. My first use case is simple: user start a new activity. This would be performed by right-clicking on a system tray icon then selecting the activity they’re working on (see right screenshot). Application will then be responsible for create a new audit entry with activity name and start date. When a different activity is clicked, application will be responsible for closing out prior activity and create a new audit activity. My second use case is to display a report that can be used to fill out the actual time sheet.
Retrieving the Project List
I needed a way to retrieve all projects/activities from time sheet application to be displayed as a menu item. At my office, time sheets are filled out online. Since you can’t access my intranet, I’ve built a mockup (see screenshot below). One major difference is the single sign on (SSO) authentication and authorization mechanism. Other than that, for the most part, this mockup is close to the time sheet application I have at the office.
As you can see, it’s just a simple HTML page with a TABLE element containing the data I wanted on the second column. Below is how I retrieve the HTML page.
HttpWebRequest req = (HttpWebRequest) WebRequest.Create(Settings.Default.TIMESHEET_URL);
HttpWebResponse res = (HttpWebResponse) req.GetResponse();
using (StreamReader reader = new StreamReader(res.GetResponseStream()))
{
return reader.ReadToEnd();
}
Next, I needed a way to parse this HTML page. To achieve this, I’ve decided to use Html Agility Pack which allows me to target the portion of the TD elements using XPATH.
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(GetTimesheetHtml());
// cache project list
this._projectList = new LinkedList();
HtmlNodeCollection items = doc.DocumentNode.SelectNodes(Settings.Default.PROJECT_NAME_XPATH);
bool isFirst = Settings.Default.SKIP_FIRST;
foreach (HtmlNode node in items)
{
if (isFirst)
{
isFirst = false;
continue;
}
string innerText = WebUtility.HtmlDecode(node.InnerText).Trim();
if (string.IsNullOrEmpty(innerText)) continue;
this._projectList.AddLast(innerText);
}
Displaying the Project List
A standard .NET Windows application would launch a .NET Form. In our case, we won’t launch a form at start of this application. Instead, we will create a custom ApplicationContext with a NotifyIcon to be displayed on system tray. This icon will be used to display a menu of projects/activities (see above screenshot). Each menu item will be associated with a mouse click event. When a project/activity menu is clicked, this application will create a new audit record that will be stored in an MS Access database.
private void InitializeContext()
{
this._container = new Container();
this._notifyIcon = new NotifyIcon(this._container)
{
ContextMenuStrip = new ContextMenuStrip(),
Icon = Properties.Resources.clock,
Text = "Time Tracker",
Visible = true
};
this._notifyIcon.ContextMenuStrip.Opening += this.ContextMenuStrip_Opening;
}
protected void ContextMenuStrip_Opening(object Sender, CancelEventArgs e)
{
e.Cancel = false;
this._notifyIcon.ContextMenuStrip.Items.Clear();
LinkedList list = WebManager.Instance.GetProjects(false);
foreach (string item in list)
{
this._notifyIcon.ContextMenuStrip.Items.Add(
item,
item.Equals(EntryManager.Instance.ActiveActivity) ? Properties.Resources.checkmark : null,
this.ContextMenuStrip_Clicked);
}
this._notifyIcon.ContextMenuStrip.Items.Add(
EntryManager.INACTIVE_PROJECT,
EntryManager.INACTIVE_PROJECT.Equals(EntryManager.Instance.ActiveActivity) ?
Properties.Resources.checkmark : null, this.ContextMenuStrip_Clicked);
this._notifyIcon.ContextMenuStrip.Items.Add(new ToolStripSeparator());
this._notifyIcon.ContextMenuStrip.Items.Add("Refresh Project List", null, this.ContextMenuStrip_Clicked);
this._notifyIcon.ContextMenuStrip.Items.Add("View Report", null, this.ContextMenuStrip_Clicked);
this._notifyIcon.ContextMenuStrip.Items.Add(new ToolStripSeparator());
this._notifyIcon.ContextMenuStrip.Items.Add("Exit", null, this.ContextMenuStrip_Clicked);
}
Display the Report
In addition to displaying projects/activities, we want to add “View Report” to the context menu. This will display the activity report for the week and eliminate the guessing game at the end of the week.
Copy of the VS2010 Project can be found here.
Comments are closed.