using System; using System.Diagnostics; using System.Drawing; using System.Net.Http; using System.Windows.Forms; using Outlook = Microsoft.Office.Interop.Outlook; namespace MeetingClock { public partial class MainWindow : Form { private readonly string LINK_URL = "https://zechert.net/meeting-clock"; private BluetoothManager bluetoothManager; private MeetingClockManager meetingClockManager; private readonly HttpClient client = new HttpClient(); private string clockVersion = null; private Settings settings = new Settings(); private bool showBalloon = false; private OutlookManager outlookManager = new OutlookManager(); private bool clockSettingsCanBeChanged; private string currentAppointment = ""; public MainWindow() { InitializeComponent(); this.Text += " - " + Properties.Settings.Default.Version; } private async void MainWindow_Load(object sender, System.EventArgs e) { this.clockSettingsCanBeChanged = false; this.checkBoxAutostart.Checked = this.settings.Autostart; this.checkBoxStartMinimized.Checked = this.settings.StartMinimized; this.checkBoxEnableBluetooth.Checked = this.settings.StartBluetooth; this.checkBoxIgnoreAllDayAppointments.Checked = this.settings.IgnoreAllDayAppointments; this.checkBoxIgnoreCancelledAppointments.Checked = this.settings.IgnoreCancelledAppointments; this.checkBoxIgnoreFreeAppointments.Checked = this.settings.IgnoreFreeAppointments; this.checkBoxIgnoreOutOfOfficeAppointments.Checked = this.settings.IgnoreOutOfOfficeAppointments; this.checkBoxIgnoreTentativeAppointments.Checked = this.settings.IgnoreTentativeAppointments; this.numericUpDownReminderTime.Value = this.settings.ReminderTime; if (this.settings.StartMinimized) { this.WindowState = FormWindowState.Minimized; } this.bluetoothManager = new BluetoothManager(); this.bluetoothManager.StateChanged += BluetoothManager_StateChanged; this.meetingClockManager = new MeetingClockManager(bluetoothManager); this.meetingClockManager.StateChanged += MeetingClockManager_StateChanged; await this.bluetoothManager.Initialize(); if (this.settings.StartBluetooth && this.bluetoothManager.State != BluetoothManager.BluetoothState.On) { await this.bluetoothManager.Enable(); } } private void UpdateBluetoothState() { switch (this.bluetoothManager.State) { case BluetoothManager.BluetoothState.NotInitialized: this.labelBluetoothState.Text = "not initialized"; this.labelBluetoothState.ForeColor = SystemColors.ControlText; this.UpdateIcon(Properties.Resources.icon_neutral); this.buttonEnableBluetooth.Enabled = false; break; case BluetoothManager.BluetoothState.Exception: this.labelBluetoothState.Text = "system exception"; this.labelBluetoothState.ForeColor = Color.Red; this.UpdateIcon(Properties.Resources.icon_error); this.buttonEnableBluetooth.Enabled = false; ShowArchitectureWarning(); break; case BluetoothManager.BluetoothState.NoBluetoothAdapter: this.labelBluetoothState.Text = "no bluetooth adapter found"; this.labelBluetoothState.ForeColor = Color.Red; this.UpdateIcon(Properties.Resources.icon_error); this.buttonEnableBluetooth.Enabled = false; break; case BluetoothManager.BluetoothState.NoBluetoothRadio: this.labelBluetoothState.Text = "no bluetooth radio found"; this.labelBluetoothState.ForeColor = Color.Red; this.UpdateIcon(Properties.Resources.icon_error); this.buttonEnableBluetooth.Enabled = false; break; case BluetoothManager.BluetoothState.Disabled: this.labelBluetoothState.Text = "disabled"; this.labelBluetoothState.ForeColor = SystemColors.ControlText; this.UpdateIcon(Properties.Resources.icon_warning); this.buttonEnableBluetooth.Enabled = true; break; case BluetoothManager.BluetoothState.Off: this.labelBluetoothState.Text = "off"; this.labelBluetoothState.ForeColor = Color.DarkOrange; this.UpdateIcon(Properties.Resources.icon_warning); this.buttonEnableBluetooth.Enabled = true; break; case BluetoothManager.BluetoothState.On: this.labelBluetoothState.Text = "on"; this.UpdateIcon(Properties.Resources.icon_neutral); this.labelBluetoothState.ForeColor = Color.Green; this.buttonEnableBluetooth.Enabled = false; break; case BluetoothManager.BluetoothState.Unknown: this.labelBluetoothState.Text = "unknown"; this.UpdateIcon(Properties.Resources.icon_off); this.labelBluetoothState.ForeColor = SystemColors.ControlText; this.buttonEnableBluetooth.Enabled = false; break; } } private void BluetoothManager_StateChanged(BluetoothManager manager, BluetoothManager.BluetoothState oldState, BluetoothManager.BluetoothState newState) { this.BeginInvoke((Action) (() => { this.UpdateBluetoothState(); })); } private void UpdateMeetingClockState() { this.clockSettingsCanBeChanged = false; switch (this.meetingClockManager.State) { case MeetingClockManager.MeetingClockState.NotInitialized: this.labelMeetingClockState.Text = "not initialized"; this.labelMeetingClockState.ForeColor = SystemColors.ControlText; this.UpdateIcon(Properties.Resources.icon_neutral); this.groupBoxClockSettings.Enabled = false; break; case MeetingClockManager.MeetingClockState.NoComPort: if (this.bluetoothManager.State == BluetoothManager.BluetoothState.On) { this.labelMeetingClockState.Text = "not paired"; } else { this.labelMeetingClockState.Text = "bluetooth disabled"; } this.labelMeetingClockState.ForeColor = Color.Red; this.UpdateIcon(Properties.Resources.icon_error); this.groupBoxClockSettings.Enabled = false; break; case MeetingClockManager.MeetingClockState.Disconnected: this.labelMeetingClockState.Text = "not connected"; this.labelMeetingClockState.ForeColor = Color.DarkOrange; this.UpdateIcon(Properties.Resources.icon_neutral); this.groupBoxClockSettings.Enabled = false; break; case MeetingClockManager.MeetingClockState.Connected: this.labelMeetingClockState.Text = "connected on " + this.meetingClockManager.Port + ", " + this.meetingClockManager.Version; this.labelMeetingClockState.ForeColor = Color.Green; this.UpdateIcon(Properties.Resources.icon_ok); if (this.clockVersion != null && this.meetingClockManager.Version != this.clockVersion) { DialogResult result = MessageBox.Show("A new version of the meeting clock firmware is available.\n\n" + "Do you want to open " + LINK_URL + " to download the new version now?", "New Firmware Available", MessageBoxButtons.YesNo, MessageBoxIcon.Information); if (result == DialogResult.Yes) { System.Diagnostics.Process.Start(LINK_URL); } } this.groupBoxClockSettings.Enabled = true; this.ReadClockSettings(); this.ShowNextAppointment(); break; } } private void MeetingClockManager_StateChanged(MeetingClockManager manager, MeetingClockManager.MeetingClockState oldState, MeetingClockManager.MeetingClockState newState) { this.BeginInvoke((Action)(() => { this.UpdateMeetingClockState(); })); } private void ShowArchitectureWarning() { String computerArchitecture = Environment.Is64BitOperatingSystem ? "x64" : "x86"; String programArchitecture = Environment.Is64BitProcess ? "x64" : "x86"; String message = "" + "This application cannot access the Bluetooth device on your computer. " + "This is normally a sign that you downloaded the wrong architecture (x64, x86) of this application.\n" + "\n" + "Your computer uses " + computerArchitecture + " architecture.\n" + "This application is " + programArchitecture + " architecture.\n" + "\n" + "This application will only work on Windows 10.\n\n" + "Please download the correct version of this application from " + LINK_URL + ".\n" + "\n" + "This application will now exit!\n" + "\n" + "Do you want to open " + LINK_URL + " now?"; DialogResult result = MessageBox.Show(message, "Bluetooth Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); if (result == DialogResult.Yes) { System.Diagnostics.Process.Start(LINK_URL); } Application.Exit(); } private void ButtonOpenSystemSettingsPrivacy_Click(object sender, EventArgs e) { System.Diagnostics.Process.Start("ms-settings:privacy-radios"); } private void buttonOpenSystemSettingsBluetooth_Click(object sender, EventArgs e) { System.Diagnostics.Process.Start("ms-settings:bluetooth"); } private void buttonWebsite_Click(object sender, EventArgs e) { System.Diagnostics.Process.Start(LINK_URL); } private async void ButtonEnableBluetooth_Click(object sender, EventArgs e) { Windows.Devices.Radios.RadioAccessStatus result = await this.bluetoothManager.Enable(); DialogResult open = DialogResult.Cancel; String openLink = ""; switch (result) { case Windows.Devices.Radios.RadioAccessStatus.DeniedBySystem: open = MessageBox.Show( "The operating system denied access to the bluetooth radio. Please enable bluetooth yourself.\n\nDo you want to open bluetooth settings now?", "Access denied", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); openLink = "ms-settings:bluetooth"; break; case Windows.Devices.Radios.RadioAccessStatus.DeniedByUser: open = MessageBox.Show( "Switching the bluetooth state automatically is forbidden by your privacy settings.\n\nDo you want to open privacy settings now?", "Access denied", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); openLink = "ms-settings:privacy-radios"; break; case Windows.Devices.Radios.RadioAccessStatus.Unspecified: open = MessageBox.Show( "Switching the bluetooth state failed for an unknown reason. Please enable bluetooth yourself.\n\nDo you want to open bluetooth settings now?", "Access denied", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); openLink = "ms-settings:bluetooth"; break; } if (open == DialogResult.Yes) { System.Diagnostics.Process.Start(openLink); } } private void UpdateIcon(Icon newIcon) { this.Icon = newIcon; this.notifyIcon.Icon = newIcon; } private void MainWindow_FormClosed(object sender, FormClosedEventArgs e) { Debug.WriteLine(String.Format("Form was closed because of {0}", e.CloseReason.ToString())); this.bluetoothManager.Stop(); this.meetingClockManager.Stop(); } private void checkBoxAutostart_CheckedChanged(object sender, EventArgs e) { this.settings.Autostart = this.checkBoxAutostart.Checked; } private void checkBoxStartMinimized_CheckedChanged(object sender, EventArgs e) { this.settings.StartMinimized = this.checkBoxStartMinimized.Checked; } private void checkBoxEnableBluetooth_CheckedChanged(object sender, EventArgs e) { this.settings.StartBluetooth = this.checkBoxEnableBluetooth.Checked; } private void MainWindow_Resize(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) { if (this.showBalloon) { this.notifyIcon.ShowBalloonTip(3000); } this.ShowInTaskbar = false; this.FormBorderStyle = FormBorderStyle.SizableToolWindow; } } private void NotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e) { this.FormBorderStyle = FormBorderStyle.Sizable; this.WindowState = FormWindowState.Normal; this.ShowInTaskbar = true; } private void timerEnableBalloon_Tick(object sender, EventArgs e) { this.showBalloon = true; this.timerEnableBalloon.Stop(); } private void checkBoxIgnoreAllDayAppointments_CheckedChanged(object sender, EventArgs e) { this.settings.IgnoreAllDayAppointments = this.checkBoxIgnoreAllDayAppointments.Checked; } private void checkBoxIgnoreCancelledAppointments_CheckedChanged(object sender, EventArgs e) { this.settings.IgnoreCancelledAppointments = this.checkBoxIgnoreCancelledAppointments.Checked; } private void checkBoxIgnoreFreeAppointments_CheckedChanged(object sender, EventArgs e) { this.settings.IgnoreFreeAppointments = this.checkBoxIgnoreFreeAppointments.Checked; } private void checkBoxIgnoreOutOfOfficeAppointments_CheckedChanged(object sender, EventArgs e) { this.settings.IgnoreOutOfOfficeAppointments = this.checkBoxIgnoreOutOfOfficeAppointments.Checked; } private void checkBoxIgnoreTentativeAppointments_CheckedChanged(object sender, EventArgs e) { this.settings.IgnoreTentativeAppointments = this.checkBoxIgnoreTentativeAppointments.Checked; } private void ReadClockSettings() { this.numericUpDownTimeInterval.Value = this.meetingClockManager.GetTimeInterval() ?? this.numericUpDownTimeInterval.Value; this.numericUpDownDateInterval.Value = this.meetingClockManager.GetDateInterval() ?? this.numericUpDownDateInterval.Value; this.numericUpDownTemperatureInterval.Value = this.meetingClockManager.GetTemperatureInterval() ?? this.numericUpDownTemperatureInterval.Value; this.trackBarBrightness.Value = this.meetingClockManager.GetBrightness() ?? this.trackBarBrightness.Value; this.labelBrightness.Text = this.trackBarBrightness.Value.ToString(); this.trackBarScrollSpeed.Value = this.meetingClockManager.GetScrollSpeed() ?? this.trackBarScrollSpeed.Value; this.labelScrollSpeed.Text = this.trackBarScrollSpeed.Value.ToString(); this.numericUpDownScrollWait.Value = (this.meetingClockManager.GetScrollWait() / 10) ?? this.numericUpDownScrollWait.Value; this.checkBoxDateEnabled.Checked = this.meetingClockManager.GetDateEnabled() ?? this.checkBoxDateEnabled.Checked; this.checkBoxTemperatureEnabled.Checked = this.meetingClockManager.GetTemperatureEnabled() ?? this.checkBoxTemperatureEnabled.Checked; this.clockSettingsCanBeChanged = true; } private void trackBarBrightness_ValueChanged(object sender, EventArgs e) { this.labelBrightness.Text = trackBarBrightness.Value.ToString(); if (this.clockSettingsCanBeChanged) { this.meetingClockManager.SetBrightness(trackBarBrightness.Value); } } private void trackBarScrollSpeed_ValueChanged(object sender, EventArgs e) { this.labelScrollSpeed.Text = trackBarScrollSpeed.Value.ToString(); if (this.clockSettingsCanBeChanged) { this.meetingClockManager.SetScrollSpeed(trackBarScrollSpeed.Value); this.StartScrollDemo(); } } private void numericUpDownScrollWait_ValueChanged(object sender, EventArgs e) { if (this.clockSettingsCanBeChanged) { this.meetingClockManager.SetScrollWait((int)(this.numericUpDownScrollWait.Value * 10)); this.StartScrollDemo(); } } private void StartScrollDemo() { if (this.timerScrollDemo.Enabled) { this.timerScrollDemo.Stop(); } else { this.meetingClockManager.ScrollText("Beispiel-Text"); } this.timerScrollDemo.Start(); } private void timerScrollDemo_Tick(object sender, EventArgs e) { this.meetingClockManager.ScrollText(""); timerScrollDemo.Stop(); } private void numericUpDownTimeInterval_ValueChanged(object sender, EventArgs e) { if (this.clockSettingsCanBeChanged) { this.meetingClockManager.SetTimeInterval((int)(this.numericUpDownTimeInterval.Value)); } } private void numericUpDownDateInterval_ValueChanged(object sender, EventArgs e) { if (this.clockSettingsCanBeChanged) { this.meetingClockManager.SetDateInterval((int)(this.numericUpDownDateInterval.Value)); } } private void numericUpDownTemperatureInterval_ValueChanged(object sender, EventArgs e) { if (this.clockSettingsCanBeChanged) { this.meetingClockManager.SetTemperatureInterval((int)(this.numericUpDownTemperatureInterval.Value)); } } private void checkBoxDateEnabled_CheckedChanged(object sender, EventArgs e) { if (this.clockSettingsCanBeChanged) { this.meetingClockManager.SetDateEnabled(this.checkBoxDateEnabled.Checked); } } private void checkBoxTemperatureEnabled_CheckedChanged(object sender, EventArgs e) { if (this.clockSettingsCanBeChanged) { this.meetingClockManager.SetTemperatureEnabled(this.checkBoxTemperatureEnabled.Checked); } } private void buttonResetDefault_Click(object sender, EventArgs e) { DialogResult dialogResult = MessageBox.Show("Are you sure? All clock settings will be reset to their default values!", "Confirm Reset", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); if (dialogResult == DialogResult.Yes) { this.clockSettingsCanBeChanged = false; this.meetingClockManager.SetBrightness(15); this.meetingClockManager.SetTimeInterval(35); this.meetingClockManager.SetDateInterval(3); this.meetingClockManager.SetDateEnabled(true); this.meetingClockManager.SetDateInterval(3); this.meetingClockManager.SetTemperatureEnabled(true); this.meetingClockManager.SetTemperatureInterval(3); this.meetingClockManager.SetScrollSpeed(5); this.meetingClockManager.SetScrollWait(40); this.ReadClockSettings(); } } private void timerAdjustClock_Tick(object sender, EventArgs e) { if (this.clockSettingsCanBeChanged) { this.meetingClockManager.Adjust(); } } private void timerGetAppointment_Tick(object sender, EventArgs e) { this.ShowNextAppointment(); } private async void ShowNextAppointment() { if (!this.clockSettingsCanBeChanged) { this.currentAppointment = ""; return; } Outlook.AppointmentItem appointment = await this.outlookManager.GetNextAppointment( this.settings.IgnoreAllDayAppointments, this.settings.IgnoreCancelledAppointments, this.settings.IgnoreFreeAppointments, this.settings.IgnoreOutOfOfficeAppointments, this.settings.IgnoreTentativeAppointments); if (appointment == null) { Debug.WriteLine("No upcoming appointment send to clock"); this.currentAppointment = ""; return; } string appointmentName = String.Format("{0} - {1} {2}", appointment.Start.ToString("t"), appointment.End.ToString("t"), appointment.Subject); if (appointment.Start > DateTime.Now.AddMinutes(this.settings.ReminderTime)) { Debug.WriteLine(String.Format("Upcoming appointment is too far in future, not displaying: {0}", appointmentName)); this.currentAppointment = ""; return; } if (this.currentAppointment == appointmentName) { Debug.WriteLine("Current appointment is already displayed, not doing anything"); return; } this.currentAppointment = appointmentName; this.meetingClockManager.ScrollText(this.currentAppointment); this.meetingClockManager.NextDate(appointment.Start); Debug.WriteLine(String.Format("Current appointment is set to: {0}", this.currentAppointment)); } private void numericUpDownReminderTime_ValueChanged(object sender, EventArgs e) { this.settings.ReminderTime = (int)this.numericUpDownReminderTime.Value; } } }