using System.ComponentModel; using System.Windows.Media; using TeamsLocalLibary.EventArgs; using TeamsNetphoneLink.Teams; using TeamsNetphoneLink.Netphone; using TeamsNetphoneLink.WPF.MVVM; using TeamsNetphoneLink.Communication; using System.Reflection; using TeamsNetphoneLink.WPF; namespace TeamsNetphoneLink { public class Syncronisation { public NetPhoneEvents NetphoneEvents { get; set; } public TeamsGraph TeamsGraph { get; set; } public TeamsLocalAPI TeamsEvents { get; set; } //MVVM View Models public DashboardViewModel _dashboardViewModel { get; } public LogViewModel LogEntries { get; } public FinishPanelViewModel FinishPanelViewModel { get; } public readonly SemaphoreSlim TeamsGraphAuthenticationSemaphore = new(1); private bool _isCallActive = false; private bool _isMeetingActive = false; private bool NetphoneConnected = false; public Syncronisation(NetPhoneEvents netPhoneEvents, TeamsLocalAPI teamsEvents, TeamsGraph teamsGraph, DashboardViewModel dashboardViewModel, LogViewModel logEntries, FinishPanelViewModel finishPanelViewModel) { _dashboardViewModel = dashboardViewModel ?? throw new ArgumentNullException(nameof(dashboardViewModel)); LogEntries = logEntries ?? throw new ArgumentNullException(nameof(logEntries)); FinishPanelViewModel = finishPanelViewModel ?? throw new ArgumentNullException(nameof(finishPanelViewModel)); NetphoneEvents = netPhoneEvents ?? throw new ArgumentNullException(nameof(netPhoneEvents)); TeamsEvents = teamsEvents ?? throw new ArgumentNullException(nameof(teamsEvents)); TeamsGraph = teamsGraph ?? throw new ArgumentNullException(nameof(teamsGraph)); // Event-Handler für Netphone-Events registrieren NetphoneEvents.AddLineStateEventHandler(LineState.Dialing, NetphoneEventCall); NetphoneEvents.AddLineStateEventHandler(LineState.Ringing, NetphoneEventCall); NetphoneEvents.AddLineStateEventHandler(LineState.Active, NetphoneEventCall); NetphoneEvents.AddLineStateEventHandler(LineState.Inactive, NetphoneEventTerminated); NetphoneEvents.AddLineStateEventHandler(LineState.Terminated, NetphoneEventTerminated); NetphoneEvents.AddLoggedInStateEventHandler(NetphoneOnLoggedInStateChanged); if (!Settings.Default.UseGraphForMeetingState) { // Event-Handler für Teams-Events registrieren TeamsEvents.AddEventHandler("IsInMeeting", TeamsIsInMeetingHandler); TeamsEvents.AddConnectionStateHandler(TeamsOnConnectionStateChanged); TeamsEvents.AddTokenRecievedHandler(TeamsTokenRecievedHandler); } else { TeamsGraph.ActivityChanged += TeamsGraphOnActivityChanged; _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.TeamsLocalAPIStatus, Colors.Orange, "Deaktiviert"); } } // Event-Handler für Änderungen des Verbindungsstatus in Teams private void TeamsOnConnectionStateChanged(object? sender, ConnectionStateChangedEventArgs args) { var status = args.WebSocketState switch { System.Net.WebSockets.WebSocketState.Open when Settings.Default.TeamsPermission => (Colors.Green, "Verbunden"), System.Net.WebSockets.WebSocketState.Open => (Colors.Orange, "Authorisieren (Klicken)"), System.Net.WebSockets.WebSocketState.Connecting => (Colors.Blue, "Verbinden..."), System.Net.WebSockets.WebSocketState.Closed => (Colors.Red, "Nicht verbunden"), _ => (Colors.Gray, "Unbekannt") }; _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.TeamsLocalAPIStatus, status.Item1, status.Item2); if(Settings.Default.TeamsPermission) LogEntries.AddLogEntry(args.WebSocketState == System.Net.WebSockets.WebSocketState.Open ? "Info" : "Warn", "TeamsLocalAPI", status.Item2); } private void NetphoneOnLoggedInStateChanged(bool isLoggedIn) { NetphoneConnected = isLoggedIn; var state = isLoggedIn ? ( Colors.Green, "Verbunden" ) : ( Colors.Red, "Nicht verbunden" ); _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.NetphoneCLMGRStatus, state.Item1, state.Item2); LogEntries.AddLogEntry(isLoggedIn ? "Info" : "Warn", "Netphone", state.Item2); } // Event-Handler für den Empfang eines Teams-Tokens private void TeamsTokenRecievedHandler(object sender, TokenReceivedEventArgs e) { if (!Settings.Default.TeamsPermission) { Settings.Default.TeamsPermission = true; Settings.Default.Save(); FinishPanelViewModel.FinishPanelEffect = null; FinishPanelViewModel.FinishPanelEnabled = true; FinishPanelViewModel.FinishPanelFinishTextText = "Verbindung erfolgreich"; FinishPanelViewModel.SetFinishPanelFinishTextColor(Colors.Green); _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.TeamsLocalAPIStatus, Colors.Green, "Verbunden"); LogEntries.AddLogEntry("TeamsLocalAPI", "Token erfolgreich abgerufen"); } } // Event-Handler für eingehende Anrufe private async void NetphoneEventCall(LineState newLineState) { if (_isCallActive) return; _isCallActive = true; await TeamsGraph.SetPresenceAsync(TeamsGraph.PresenceState.Busy); _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.NetphoneCallStatus, Colors.DarkGreen, "Ongoing"); LogEntries.AddLogEntry("Syncronisation", "Netphone Anruf gestartet"); } // Event-Handler für beendete Anrufe private async void NetphoneEventTerminated(LineState newLineState) { if (!_isCallActive) return; _isCallActive = false; await TeamsGraph.SetPresenceAsync(TeamsGraph.PresenceState.Available); _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.NetphoneCallStatus, Colors.DarkOrange, "Not active"); LogEntries.AddLogEntry("Syncronisation", "Netphone Anruf gestoppt"); } private void TeamsGraphOnActivityChanged(object sender, PresenceChangedEventArgs args) { // Define activities that indicate the user is in a meeting var meetingActivities = new HashSet { "InACall", "InAConferenceCall", "InAMeeting", "Presenting" }; if(args.Presence.Activity is null) return; // Check if the current activity is in the meetingActivities set bool isInMeeting = meetingActivities.Contains(args.Presence.Activity); if (!isInMeeting && _isMeetingActive) { _isMeetingActive = false; SetNetphoneStatus(isInMeeting); return; } if (isInMeeting && !_isMeetingActive) { _isMeetingActive = true; SetNetphoneStatus(isInMeeting); } } // Event-Handler für Änderungen des "IsInMeeting"-Status in Teams private void TeamsIsInMeetingHandler(object sender, PropertyChangedEventArgs e) { var isInMeeting = (bool)(sender.GetType()?.GetProperty(e.PropertyName)?.GetValue(sender) ?? false); SetNetphoneStatus(isInMeeting); } private void SetNetphoneStatus(bool meeting) { if (meeting) { if (NetphoneConnected) { NetphoneEvents.SetRichPresenceStatus(0, 1, DateTime.MaxValue); NetphoneEvents.SetAppointmentText("In einem Teams Meeting", DateTime.MaxValue); } _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.TeamsMeetingStatus, Colors.DarkGreen, "Ongoing"); LogEntries.AddLogEntry("Syncronisation", "Teams Meeting gestartet"); } else { if (NetphoneConnected) { NetphoneEvents.SetRichPresenceStatus(0, 0, DateTime.MaxValue); NetphoneEvents.SetAppointmentText("", DateTime.MaxValue); } _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.TeamsMeetingStatus, Colors.DarkOrange, "Not active"); LogEntries.AddLogEntry("Syncronisation", "Teams Meeting gestoppt"); } } // Methode zur Authentifizierung bei der Graph API public async Task GraphAuthenticate(bool clearCache = false) { _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.TeamsGraphAPIStatus, Colors.Blue, "Anmeldung läuft..."); LogEntries.AddLogEntry("TeamsGraphAPI", String.Format("Anmeldung läuft")); var authResult = await TeamsGraph.AuthenticateAsync(clearCache); var status = authResult ? (Colors.Green, "Angemeldet") : (Colors.Red, "Fehler - Anmelden (Klicken)"); _dashboardViewModel.UpdateStatusPanel(StatusPanelNames.TeamsGraphAPIStatus, status.Item1, status.Item2); LogEntries.AddLogEntry("TeamsGraphAPI", status.Item2); return authResult; } public async void InitializeNetphoneAsync() { try { await this.NetphoneEvents.Initialize(waitForNetphone: true).ConfigureAwait(false); } catch (Exception ex) { // Fehlerbehandlung für die Netphone-Initialisierung ExceptionWindowHelper.Show(this.GetType().Name, MethodBase.GetCurrentMethod().Name, "Fehler bei der Initialisierung von der NetphoneAPI", ex.Message, ex.StackTrace); } } public async void InitializeTeamsGraphAsync() { if (!Teams.TeamsGraph.IsGuid(Settings.Default.AppID) || !Teams.TeamsGraph.IsGuid(Settings.Default.TenantID)) { this._dashboardViewModel.UpdateStatusPanel(StatusPanelNames.TeamsGraphAPIStatus, Colors.Red, "Konfiguration fehlt"); return; } try { await this.TeamsGraphAuthenticationSemaphore.WaitAsync().ConfigureAwait(false); if (await this.TeamsGraph.IsCachedAccounts() && Settings.Default.SaveEntraCredentials) { await this.GraphAuthenticate().ConfigureAwait(false); ; } else { this._dashboardViewModel.UpdateStatusPanel(StatusPanelNames.TeamsGraphAPIStatus, Colors.Orange, "Anmelden"); } this.TeamsGraphAuthenticationSemaphore.Release(); if (Settings.Default.UseGraphForMeetingState) { this.TeamsGraph.CheckPresenceStatusTimer(); } } catch (Exception ex) { // Fehlerbehandlung für die TeamsGraph-Initialisierung ExceptionWindowHelper.Show(this.GetType().Name, MethodBase.GetCurrentMethod().Name, "Fehler bei der Initialisierung von TeamsGraph", ex.Message, ex.StackTrace); } } public async void InitializeTeamsLocalAPIAsync() { if (!Settings.Default.UseGraphForMeetingState) { try { await this.TeamsEvents.Initialize().ConfigureAwait(false); } catch (Exception ex) { // Fehlerbehandlung für die TeamsLocalAPI-Initialisierung ExceptionWindowHelper.Show(this.GetType().Name, MethodBase.GetCurrentMethod().Name, "Fehler bei der Initialisierung von der TeamsLocalAPI", ex.Message, ex.StackTrace); } } } } }