using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Globalization; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; using PepperDash.Essentials.Core.Touchpanels.Keyboards; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; using PepperDash.Essentials.Devices.Common.Cameras; namespace PepperDash.Essentials.UIDrivers.VC { /// /// This fella will likely need to interact with the room's source, although that is routed via the spark... /// Probably needs event or FB to feed AV driver - to show two-mute volume when appropriate. /// /// public class EssentialsVideoCodecUiDriver : PanelDriverBase { IAVWithVCDriver Parent; /// /// /// VideoCodecBase Codec; /// /// To drive UI elements outside of this driver that may be dependent on this. /// //BoolFeedback InCall; BoolFeedback LocalPrivacyIsMuted; /// /// For the subpages above the bar /// JoinedSigInterlock VCControlsInterlock; /// /// For the camera control mode (auto/manual/off) /// JoinedSigInterlock VCCameraControlModeInterlock; /// /// For the different staging bars: Active, inactive /// JoinedSigInterlock StagingBarsInterlock; /// /// For the staging button feedbacks /// JoinedSigInterlock StagingButtonsFeedbackInterlock; SmartObjectNumeric DialKeypad; SubpageReferenceList ActiveCallsSRL; SmartObjectDynamicList RecentCallsList; SmartObjectDynamicList DirectoryList; SmartObjectDPad CameraPtzPad; SmartObjectDynamicList CameraModeList; SmartObjectDynamicList CameraSelectList; BoolFeedback DirectoryBackButtonVisibleFeedback; // These are likely temp until we get a keyboard built StringFeedback DialStringFeedback; StringBuilder DialStringBuilder = new StringBuilder(); BoolFeedback DialStringBackspaceVisibleFeedback; StringFeedback SearchStringFeedback; StringBuilder SearchStringBuilder = new StringBuilder(); BoolFeedback SearchStringBackspaceVisibleFeedback; StringFeedback PasswordStringFeedback; StringBuilder PasswordStringBuilder = new StringBuilder(); ModalDialog IncomingCallModal; eKeypadMode KeypadMode; bool CodecHasFavorites; bool ShowCameraModeControls; CTimer BackspaceTimer; /// /// The panel header driver /// EssentialsHeaderDriver HeaderDriver; /// /// /// /// /// public EssentialsVideoCodecUiDriver(BasicTriListWithSmartObject triList, IAVWithVCDriver parent, VideoCodecBase codec, EssentialsHeaderDriver headerDriver) : base(triList) { try { if (codec == null) throw new ArgumentNullException("Codec cannot be null"); Codec = codec; Parent = parent; HeaderDriver = headerDriver; SetupCallStagingPopover(); SetupDialKeypad(); ActiveCallsSRL = new SubpageReferenceList(triList, UISmartObjectJoin.CodecActiveCallsHeaderList, 5,5,5); SetupRecentCallsList(); SetupFavorites(); SetupLayoutControls(); codec.CallStatusChange += new EventHandler(Codec_CallStatusChange); //InCall = new BoolFeedback(() => false); LocalPrivacyIsMuted = new BoolFeedback(() => false); VCControlsInterlock = new JoinedSigInterlock(triList); VCCameraControlModeInterlock = new JoinedSigInterlock(triList); VCControlsInterlock.HideAndClear(); /* if (CodecHasFavorites || codec is IHasZoomRoomLayouts) //Checking for Zoom Room...picked a ZoomRoom specific interface to check for VCControlsInterlock.SetButDontShow(UIBoolJoin.VCKeypadWithFavoritesVisible); else VCControlsInterlock.SetButDontShow(UIBoolJoin.VCKeypadVisible); */ StagingBarsInterlock = new JoinedSigInterlock(triList); if(Codec is IHasCallHistory) StagingBarsInterlock.SetButDontShow(UIBoolJoin.VCStagingInactivePopoverWithRecentsVisible); else StagingBarsInterlock.SetButDontShow(UIBoolJoin.VCStagingInactivePopoverWithoutRecentsVisible); StagingButtonsFeedbackInterlock = new JoinedSigInterlock(triList); StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingKeypadPress); // Return formatted when dialing, straight digits when in call DialStringFeedback = new StringFeedback(() => { // Format the number feedback if in dial mode and the codec is not IHasStartMeeting (ZoomRoom) if (KeypadMode == eKeypadMode.Dial && !(Codec is IHasStartMeeting)) return GetFormattedDialString(DialStringBuilder.ToString()); else return DialStringBuilder.ToString(); }); DialStringFeedback.LinkInputSig(triList.StringInput[UIStringJoin.CodecAddressEntryText]); DialStringBackspaceVisibleFeedback = new BoolFeedback(() => DialStringBuilder.Length > 0); DialStringBackspaceVisibleFeedback .LinkInputSig(triList.BooleanInput[UIBoolJoin.VCKeypadBackspaceVisible]); SearchStringFeedback = new StringFeedback(() => { if (SearchStringBuilder.Length > 0) { Parent.Keyboard.EnableGoButton(); return SearchStringBuilder.ToString(); } else { Parent.Keyboard.DisableGoButton(); return "Tap for keyboard"; } }); SearchStringFeedback.LinkInputSig(triList.StringInput[UIStringJoin.CodecDirectorySearchEntryText]); PasswordStringFeedback = new StringFeedback(() => { if (PasswordStringBuilder.Length > 0) { Parent.Keyboard.EnableGoButton(); return PasswordStringBuilder.ToString(); } else { Parent.Keyboard.DisableGoButton(); return ""; } }); PasswordStringFeedback.LinkInputSig(triList.StringInput[UIStringJoin.PasswordPromptPasswordText]); SetupDirectoryList(); SearchStringBackspaceVisibleFeedback = new BoolFeedback(() => SearchStringBuilder.Length > 0); SearchStringBackspaceVisibleFeedback.LinkInputSig(triList.BooleanInput[UIBoolJoin.VCDirectoryBackspaceVisible]); triList.SetSigFalseAction(UIBoolJoin.VCDirectoryBackPress, GetDirectoryParentFolderContents); DirectoryBackButtonVisibleFeedback = (codec as IHasDirectory).CurrentDirectoryResultIsNotDirectoryRoot; DirectoryBackButtonVisibleFeedback .LinkInputSig(triList.BooleanInput[UIBoolJoin.VCDirectoryBackVisible]); triList.SetSigFalseAction(UIBoolJoin.VCKeypadTextPress, RevealKeyboard); triList.SetSigFalseAction(UIBoolJoin.VCDirectorySearchTextPress, RevealKeyboard); triList.SetSigHeldAction(UIBoolJoin.VCDirectoryBackspacePress, 500, StartSearchBackspaceRepeat, StopSearchBackspaceRepeat, SearchKeypadBackspacePress); if (Codec is IPasswordPrompt) { SetupPasswordPrompt(); } // If the codec is ready, then get the values we want, otherwise wait if (Codec.IsReady) Codec_IsReady(); else codec.IsReadyChange += (o, a) => Codec_IsReady(); } catch (Exception e) { Debug.Console(1, "Exception in VideoCodecUiDriver Constructor: {0}", e); } } /// /// /// /// /// void Codec_IsReady() { SetupAddresses(); if(HeaderDriver.HeaderButtonsAreSetUp) HeaderDriver.ComputeHeaderCallStatus(Codec); SetupCameraControls(); } void SetupAddresses() { string roomContactNumbers = ""; string roomPhoneNumber = ""; string roomVideoAddress = ""; Debug.Console(1, @" Codec.CodecInfo.IpAddress: {0} Codec.CodecInfo.SipUri: {1} Codec.CodecInfo.SipPhoneNumber: {2} Codec.CodecInfo.E164Alias: {3} Codec.CodecInfo.H323Id: {4} ", Codec.CodecInfo.IpAddress, Codec.CodecInfo.SipUri, Codec.CodecInfo.SipPhoneNumber, Codec.CodecInfo.E164Alias, Codec.CodecInfo.H323Id); // Populate phone number if (!string.IsNullOrEmpty(Codec.CodecInfo.SipUri)) // If both values are present, format the string with a pipe divider { roomPhoneNumber = Codec.CodecInfo.SipUri; } else if (!string.IsNullOrEmpty(Codec.CodecInfo.SipPhoneNumber)) // If only one value present, just show the phone number { roomPhoneNumber = GetFormattedPhoneNumber(Codec.CodecInfo.SipPhoneNumber); } // Populate video number if (!string.IsNullOrEmpty(Codec.CodecInfo.IpAddress)) { roomVideoAddress = Codec.CodecInfo.IpAddress; } else if (!string.IsNullOrEmpty(Codec.CodecInfo.E164Alias)) { roomVideoAddress = Codec.CodecInfo.E164Alias; } else if (!string.IsNullOrEmpty(Codec.CodecInfo.H323Id)) { roomVideoAddress = Codec.CodecInfo.H323Id; } Debug.Console(1, @" Room Contact Numbers: Phone Number: {0} Video Number: {1} ", roomPhoneNumber, roomVideoAddress); if (!string.IsNullOrEmpty(roomPhoneNumber) && !string.IsNullOrEmpty(roomVideoAddress)) { roomContactNumbers = string.Format("{0} | {1}", roomPhoneNumber, roomVideoAddress); } else if (!string.IsNullOrEmpty(roomPhoneNumber)) { roomContactNumbers = roomPhoneNumber; } else if (!string.IsNullOrEmpty(roomVideoAddress)) { roomContactNumbers = roomVideoAddress; } TriList.SetString(UIStringJoin.RoomAddressPipeText, roomContactNumbers); TriList.SetString(UIStringJoin.RoomPhoneText, roomPhoneNumber); TriList.SetString(UIStringJoin.RoomVideoAddressText, roomVideoAddress); } /// /// Handles status changes for calls /// /// /// void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) { var call = e.CallItem; var meetingInfoSender = sender as IHasMeetingInfo; switch (e.CallItem.Status) { case eCodecCallStatus.Connected: // fire at SRL item Parent.ShowNotificationRibbon("Connected", 2000); OnCallConnected(); //VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCKeypadVisible); break; case eCodecCallStatus.Connecting: // fire at SRL item Parent.ShowNotificationRibbon("Connecting", 0); OnCallConnected(); break; case eCodecCallStatus.Dialing: Parent.ShowNotificationRibbon("Connecting", 0); break; case eCodecCallStatus.Disconnected: if (IncomingCallModal != null) IncomingCallModal.HideDialog(); if (!Codec.IsInCall) { KeypadMode = eKeypadMode.Dial; // show keypad if we're in call UI mode ShowKeypad(); DialStringBuilder.Remove(0, DialStringBuilder.Length); DialStringFeedback.FireUpdate(); Parent.ShowNotificationRibbon("Disconnected", 2000); Debug.Console(0, "Setting Connect Button mode to 0"); } break; case eCodecCallStatus.Disconnecting: break; case eCodecCallStatus.EarlyMedia: break; case eCodecCallStatus.Idle: break; case eCodecCallStatus.OnHold: break; case eCodecCallStatus.Preserved: break; case eCodecCallStatus.RemotePreserved: break; case eCodecCallStatus.Ringing: { // fire up a modal if( !Codec.CodecInfo.AutoAnswerEnabled && call.Direction == eCodecCallDirection.Incoming) ShowIncomingModal(call); break; } } if (meetingInfoSender != null && Codec.IsInCall) { var meetingInfo = meetingInfoSender.MeetingInfo; TriList.UShortInput[UIUshortJoin.VCStagingConnectButtonMode].UShortValue = (ushort) (meetingInfo.IsSharingMeeting ? 2 : 1); } else { TriList.UShortInput[UIUshortJoin.VCStagingConnectButtonMode].UShortValue = (ushort) (Codec.IsInCall ? 1 : 0); } uint stageJoin; if (Codec.IsInCall) stageJoin = UIBoolJoin.VCStagingActivePopoverVisible; else { if (Codec is IHasCallHistory) stageJoin = UIBoolJoin.VCStagingInactivePopoverWithRecentsVisible; else stageJoin = UIBoolJoin.VCStagingInactivePopoverWithoutRecentsVisible; } if (IsVisible) StagingBarsInterlock.ShowInterlocked(stageJoin); else StagingBarsInterlock.SetButDontShow(stageJoin); HeaderDriver.ComputeHeaderCallStatus(Codec); // Update active call list UpdateHeaderActiveCallList(); } private void OnCallConnected() { HidePasswordPrompt(); KeypadMode = eKeypadMode.DTMF; DialStringBuilder.Remove(0, DialStringBuilder.Length); DialStringFeedback.FireUpdate(); DialStringTextCheckEnables(); StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingKeypadPress); ShowKeypad(); UnmuteRoomOnCallConnect(); } private void UnmuteRoomOnCallConnect() { var volControl = Parent.CurrentRoom as IHasCurrentVolumeControls; if (volControl == null) { return; } var currentVolControls = volControl.CurrentVolumeControls as IBasicVolumeWithFeedback; if (currentVolControls != null) { currentVolControls.MuteOff(); } } /// /// Redraws the calls list on the header /// void UpdateHeaderActiveCallList() { var activeList = Codec.ActiveCalls.Where(c => c.IsActiveCall).ToList(); ActiveCallsSRL.Clear(); ushort i = 1; foreach (var c in activeList) { //var item = new SubpageReferenceListItem(1, ActiveCallsSRL); ActiveCallsSRL.StringInputSig(i, 1).StringValue = c.Name; ActiveCallsSRL.StringInputSig(i, 2).StringValue = c.Number; ActiveCallsSRL.StringInputSig(i, 3).StringValue = c.Status.ToString(); ActiveCallsSRL.StringInputSig(i, 4).StringValue = string.Format("Participant {0}", i); ActiveCallsSRL.UShortInputSig(i, 1).UShortValue = (ushort)(c.Type == eCodecCallType.Video ? 2 : 1); var cc = c; // for scope in lambda ActiveCallsSRL.GetBoolFeedbackSig(i, 1).SetSigFalseAction(() => Codec.EndCall(cc)); i++; } ActiveCallsSRL.Count = (ushort)activeList.Count; // If Active Calls list is visible and codec is not in a call, hide the list if (!Codec.IsInCall && Parent.PopupInterlock.CurrentJoin == Parent.CallListOrMeetingInfoPopoverVisibilityJoin) Parent.PopupInterlock.ShowInterlockedWithToggle(Parent.CallListOrMeetingInfoPopoverVisibilityJoin); } /// /// /// void ShowIncomingModal(CodecActiveCallItem call) { Debug.Console(1, "Showing Incoming Call Modal"); (Parent as IAVWithVCDriver).PrepareForCodecIncomingCall(); IncomingCallModal = new ModalDialog(TriList); string msg; string icon; if (call.Type == eCodecCallType.Audio) { icon = "Phone"; msg = string.Format("Incoming phone call from: {0}", call.Name); } else { icon = "Camera"; msg = string.Format("Incoming video call from: {0}", call.Name); } // Hide screensaver var screenSaverParent = Parent.Parent as IHasScreenSaverController; if (screenSaverParent != null) { screenSaverParent.ScreenSaverController.Hide(); } else { Debug.Console(1, "Parent.Parent is null or does not implement IHasScreenSaverController"); } IncomingCallModal.PresentModalDialog(2, "Incoming Call", icon, msg, "Ignore", "Accept", false, false, b => { if (b == 1) Codec.RejectCall(call); else //2 AcceptIncomingCall(call); IncomingCallModal = null; }); } /// /// /// void AcceptIncomingCall(CodecActiveCallItem call) { (Parent as IAVWithVCDriver).PrepareForCodecIncomingCall(); (Parent as IAVWithVCDriver).ActivityCallButtonPressed(); Codec.AcceptCall(call); } /// /// /// public override void Show() { VCControlsInterlock.Show(); StagingBarsInterlock.Show(); DialStringFeedback.FireUpdate(); base.Show(); } /// /// /// public override void Hide() { VCControlsInterlock.Hide(); StagingBarsInterlock.Hide(); base.Hide(); } /// /// Builds the call stage /// void SetupCallStagingPopover() { TriList.SetSigFalseAction(UIBoolJoin.VCStagingDirectoryPress, ShowDirectory); TriList.SetSigFalseAction(UIBoolJoin.VCStagingKeypadPress, ShowKeypad); TriList.SetSigFalseAction(UIBoolJoin.VCStagingRecentsPress, ShowRecents); TriList.SetSigFalseAction(UIBoolJoin.VCStagingCameraPress, ShowCameraControls); TriList.SetSigFalseAction(UIBoolJoin.VCStagingConnectPress, ConnectPress); TriList.SetSigFalseAction(UIBoolJoin.VCStagingMeetNowPress, MeetNowPress); TriList.SetSigFalseAction(UIBoolJoin.CallStopSharingPress, CallStopSharingPress); var meetingInfoCodec = Codec as IHasMeetingInfo; TriList.SetSigFalseAction(UIBoolJoin.CallEndPress, () => { if (Codec.ActiveCalls.Count > 1) { Parent.PopupInterlock.ShowInterlocked(Parent.CallListOrMeetingInfoPopoverVisibilityJoin); } else if (meetingInfoCodec != null && Codec.ActiveCalls.Count == 1) { var meetingInfo = meetingInfoCodec.MeetingInfo; if (meetingInfo != null && meetingInfo.IsSharingMeeting) { var presentationMeetingCodec = Codec as IHasPresentationOnlyMeeting; if (presentationMeetingCodec != null) { presentationMeetingCodec.StartNormalMeetingFromSharingOnlyMeeting(); } } else { Codec.EndAllCalls(); } } else { Codec.EndAllCalls(); } }); TriList.SetSigFalseAction(UIBoolJoin.CallEndAllConfirmPress, () => { Parent.PopupInterlock.HideAndClear(); Codec.EndAllCalls(); }); if (meetingInfoCodec != null) { TriList.SetSigFalseAction(UIBoolJoin.MeetingLeavePress, () => { Parent.PopupInterlock.HideAndClear(); if (meetingInfoCodec.MeetingInfo.IsHost) { Codec.EndAllCalls(); } else { var startMeetingCodec = Codec as IHasStartMeeting; if (startMeetingCodec != null) { startMeetingCodec.LeaveMeeting(); } } }); } } void SetupCameraControls() { CameraPtzPad = new SmartObjectDPad(TriList.SmartObjects[UISmartObjectJoin.VCCameraDpad], true); // If the codec supports camera auto or off, we need to show the mode selector subpage ShowCameraModeControls = Codec is IHasCameraAutoMode || Codec is IHasCameraOff; if (ShowCameraModeControls) { CameraModeList = new SmartObjectDynamicList(TriList.SmartObjects[UISmartObjectJoin.VCCameraMode], true, 0); VCControlsInterlock.StatusChanged += new EventHandler(VCControlsInterlock_StatusChanged); var codecOffCameras = Codec as IHasCameraOff; var supportsCameraOffMode = Codec.SupportsCameraOff; var codecAutoCameras = Codec as IHasCameraAutoMode; var supportsAutoCameraMode = Codec.SupportsCameraAutoMode; if (codecAutoCameras != null && supportsAutoCameraMode) { CameraModeList.SetItemButtonAction(1,(b) => codecAutoCameras.CameraAutoModeOn()); TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 1 Visible"].BoolValue = true; codecAutoCameras.CameraAutoModeIsOnFeedback.LinkInputSig(CameraModeList.SmartObject.BooleanInput["Item 1 Selected"]); codecAutoCameras.CameraAutoModeIsOnFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.VCCameraAutoModeIsOnFb]); //TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanOutput["Item 1 Pressed"].SetSigFalseAction( //() => codecAutoCameras.CameraAutoModeOn()); codecAutoCameras.CameraAutoModeIsOnFeedback.OutputChange += (o, a) => { if (a.BoolValue) { SetCameraManualModeButtonFeedback(false); if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCCameraModeBarVisible) { VCCameraControlModeInterlock.ShowInterlocked(UIBoolJoin.VCCameraAutoVisible); } else { VCCameraControlModeInterlock.SetButDontShow(UIBoolJoin.VCCameraAutoVisible); } } else { ShowCameraManualMode(); } }; } // Manual button always visible CameraModeList.SetItemButtonAction(2, (b) => ShowCameraManualMode()); TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 2 Visible"].BoolValue = true; //TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanOutput["Item 2 Pressed"].SetSigFalseAction( // () => ShowCameraManualMode()); if (codecOffCameras != null && supportsCameraOffMode) { TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 3 Visible"].BoolValue = true; codecOffCameras.CameraIsOffFeedback.LinkInputSig(CameraModeList.SmartObject.BooleanInput["Item 3 Selected"]); CameraModeList.SetItemButtonAction(3, (b) => codecOffCameras.CameraOff()); //TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanOutput["Item 3 Pressed"].SetSigFalseAction( // () => codecOffCameras.CameraOff()); codecOffCameras.CameraIsOffFeedback.OutputChange += (o, a) => { if (a.BoolValue) { SetCameraManualModeButtonFeedback(false); if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCCameraModeBarVisible) { VCCameraControlModeInterlock.ShowInterlocked(UIBoolJoin.VCCameraOffVisible); } else { VCCameraControlModeInterlock.SetButDontShow(UIBoolJoin.VCCameraOffVisible); } } else { ShowCameraManualMode(); } }; } } var camerasCodec = Codec as IHasCameras; if(camerasCodec != null) { //CameraSelectList = new SmartObjectDynamicList(TriList.SmartObjects[UISmartObjectJoin.VCCameraSelect], true, 0); var so = TriList.SmartObjects[UISmartObjectJoin.VCCameraSelect]; so.SigChange += SmartObject_SigChange; for (uint i = 1; i <= camerasCodec.Cameras.Count; i++) { var cameraKey = camerasCodec.Cameras[(int)i - 1].Key; Debug.Console(1, "Setting up action for Camera {0} with Key: {1} for button Item {0} Pressed", i, cameraKey); //TODO: Fix camera selection action. For some reson this action doesn't execute when the buttons are pressed var sig = so.BooleanOutput[String.Format("Item {0} Pressed", i)]; so.BooleanOutput[string.Format("Item {0} Pressed", i)].SetSigFalseAction( () => camerasCodec.SelectCamera(cameraKey)); } so.UShortInput["Set Number of Items"].UShortValue = (ushort)camerasCodec.Cameras.Count; //TriList.SmartObjects[UISmartObjectJoin.VCCameraSelect].UShortOutput["Item Clicked"].SetUShortSigAction( // (u) => // { // var cameraKey = camerasCodec.Cameras[u - 1].Key; // Debug.Console(1, "Selecting Camera {0} with Key: {1}", u, cameraKey); // camerasCodec.SelectCamera(cameraKey); // }); // Set the names for the cameras for (int i = 1; i <= camerasCodec.Cameras.Count; i++) { so.StringInput[string.Format("Set Item {0} Text", i)].StringValue = camerasCodec.Cameras[i - 1].Name; } SetCameraSelectedFeedback(); camerasCodec.CameraSelected += camerasCodec_CameraSelected; MapCameraActions(); } SetupPresets(); } void SmartObject_SigChange(GenericBase currentDevice, SmartObjectEventArgs args) { var uo = args.Sig.UserObject; if (uo is Action) (uo as Action)(args.Sig.BoolValue); else if (uo is Action) (uo as Action)(args.Sig.UShortValue); else if (uo is Action) (uo as Action)(args.Sig.StringValue); } void VCControlsInterlock_StatusChanged(object sender, StatusChangedEventArgs e) { // Need to hide the camera mode interlock if the mode bar gets hidden if (e.PreviousJoin == UIBoolJoin.VCCameraModeBarVisible) VCCameraControlModeInterlock.Hide(); // These deal with hiding/showing the camera select bar if no mode controls are visible (tied to manual controls being visible) if(!ShowCameraModeControls) { if(e.PreviousJoin == UIBoolJoin.VCCameraManualVisible) TriList.SetBool(UIBoolJoin.VCCameraSelectBarWithoutModeVisible, false); if (e.NewJoin == UIBoolJoin.VCCameraManualVisible) TriList.SetBool(UIBoolJoin.VCCameraSelectBarWithoutModeVisible, true); } } /// /// Shows the preset saved label for 2 seconds /// void ShowPresetStoreFeedback() { TriList.BooleanInput[UIBoolJoin.VCCameraPresetSavedLabelVisible].BoolValue = true; var timer = new CTimer((o) => TriList.BooleanInput[UIBoolJoin.VCCameraPresetSavedLabelVisible].BoolValue = false, 2000); } void presetsCodec_CodecRoomPresetsListHasChanged(object sender, EventArgs e) { SetupPresets(); } void camerasCodec_CameraSelected(object sender, CameraSelectedEventArgs e) { MapCameraActions(); SetCameraSelectedFeedback(); } /// /// Set the feedback for the button of the selected camera /// void SetCameraSelectedFeedback() { var camerasCodec = Codec as IHasCameras; for (int i = 1; i <= camerasCodec.Cameras.Count; i++) { var cameraSelected = camerasCodec.SelectedCameraFeedback.StringValue; var state = false; if (cameraSelected == camerasCodec.Cameras[i - 1].Key) { state = true; } TriList.SmartObjects[UISmartObjectJoin.VCCameraSelect].BooleanInput[string.Format("Item {0} Selected", i)].BoolValue = state; } } void SetupPresets() { var presetsCodec = Codec as IHasCodecRoomPresets; if (presetsCodec != null) { uint holdTime = 5000; presetsCodec.CodecRoomPresetsListHasChanged += new EventHandler(presetsCodec_CodecRoomPresetsListHasChanged); var preset = 1; if (presetsCodec.NearEndPresets[preset - 1] != null && presetsCodec.NearEndPresets[preset - 1].Defined) { TriList.SetBool(UIBoolJoin.VCCameraPreset1Visible, true); TriList.BooleanOutput[UIBoolJoin.VCCameraPreset1].SetSigHeldAction( holdTime, ShowPresetStoreFeedback,() => presetsCodec.CodecRoomPresetStore(preset, presetsCodec.NearEndPresets[preset - 1].Description), () => presetsCodec.CodecRoomPresetSelect(preset)); TriList.StringInput[UIStringJoin.VCCameraPresetLabel1].StringValue = presetsCodec.NearEndPresets[preset - 1].Description; } else { TriList.SetBool(UIBoolJoin.VCCameraPreset1Visible, false); } if (presetsCodec.NearEndPresets[1] != null && presetsCodec.NearEndPresets[1].Defined) { TriList.SetBool(UIBoolJoin.VCCameraPreset2Visible, true); TriList.BooleanOutput[UIBoolJoin.VCCameraPreset2].SetSigHeldAction( holdTime, ShowPresetStoreFeedback, () => presetsCodec.CodecRoomPresetStore(preset, presetsCodec.NearEndPresets[preset - 1].Description), () => presetsCodec.CodecRoomPresetSelect(preset)); TriList.StringInput[UIStringJoin.VCCameraPresetLabel2].StringValue = presetsCodec.NearEndPresets[1].Description; } else { TriList.SetBool(UIBoolJoin.VCCameraPreset2Visible, false); } if (presetsCodec.NearEndPresets[2] != null && presetsCodec.NearEndPresets[2].Defined) { TriList.SetBool(UIBoolJoin.VCCameraPreset3Visible, true); TriList.BooleanOutput[UIBoolJoin.VCCameraPreset3].SetSigHeldAction( holdTime, ShowPresetStoreFeedback, () => presetsCodec.CodecRoomPresetStore(preset, presetsCodec.NearEndPresets[preset - 1].Description), () => presetsCodec.CodecRoomPresetSelect(preset)); TriList.StringInput[UIStringJoin.VCCameraPresetLabel3].StringValue = presetsCodec.NearEndPresets[2].Description; } else { TriList.SetBool(UIBoolJoin.VCCameraPreset3Visible, false); } } } /// /// Maps button actions to the selected camera /// void MapCameraActions() { // Now we setup the button actions for the manual controls var camerasCodec = Codec as IHasCameras; if (camerasCodec != null && camerasCodec.SelectedCamera != null) { Debug.Console(2, "Attempting to map camera actions to selected camera: '{0}'", camerasCodec.SelectedCamera.Key); var dpad = CameraPtzPad; var camera = camerasCodec.SelectedCamera as IHasCameraPtzControl; if (camera != null) { Debug.Console(2, "Selected camera is IHasCameraPtzControl"); if (camerasCodec.SelectedCamera.CanTilt) { dpad.SigUp.SetBoolSigAction((b) => { if (b) camera.TiltUp(); else camera.TiltStop(); }); dpad.SigDown.SetBoolSigAction((b) => { if (b) camera.TiltDown(); else camera.TiltStop(); }); } if (camerasCodec.SelectedCamera.CanPan) { dpad.SigLeft.SetBoolSigAction((b) => { if (b) camera.PanLeft(); else camera.PanStop(); }); dpad.SigRight.SetBoolSigAction((b) => { if (b) camera.PanRight(); else camera.PanStop(); }); } //dpad.SigCenter.SetSigFalseAction(() => camera.PositionHome()); //var homeButton = dpad.BooleanOutput["Home"]; //if (homeButton != null) //{ // homeButton.SetSigFalseAction(() => camera.PositionHome()); //} if (camerasCodec.SelectedCamera.CanZoom) { TriList.BooleanOutput[UIBoolJoin.VCCameraZoomIn].SetBoolSigAction((b) => { if (b) camera.ZoomIn(); else camera.ZoomStop(); }); TriList.BooleanOutput[UIBoolJoin.VCCameraZoomOut].SetBoolSigAction((b) => { if (b) camera.ZoomOut(); else camera.ZoomStop(); }); } } else { Debug.Console(2, "Selected Camera is not IHasCameraPtzControl. No controls to map"); } } else { Debug.Console(2, "Codec does not have cameras of selected camera is null"); } } // Determines if codec is in manual camera control mode and shows feedback void ShowCameraManualMode() { Debug.Console(2, "ShowCameraManualMode"); var inManualMode = true; var codecOffCameras = Codec as IHasCameraOff; var codecAutoCameras = Codec as IHasCameraAutoMode; var supportsAutoCameras = codecAutoCameras != null && Codec.SupportsCameraAutoMode; if (codecOffCameras != null && codecOffCameras.CameraIsOffFeedback.BoolValue) { inManualMode = false; var codecCameraMute = Codec as IHasCameraMute; if (codecCameraMute != null) { codecCameraMute.CameraMuteOff(); inManualMode = true; } } // Clear auto mode if (supportsAutoCameras) { if (codecAutoCameras.CameraAutoModeIsOnFeedback.BoolValue) { codecAutoCameras.CameraAutoModeOff(); inManualMode = true; } } if (inManualMode) { VCCameraControlModeInterlock.SetButDontShow(UIBoolJoin.VCCameraManualVisible); if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCCameraModeBarVisible) VCCameraControlModeInterlock.Show(); } SetCameraManualModeButtonFeedback(inManualMode); } void SetCameraManualModeButtonFeedback(bool state) { // Set button feedback for manual mode TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 2 Selected"].BoolValue = state; } /// /// /// void SetupDialKeypad() { if(TriList.SmartObjects.Contains(UISmartObjectJoin.VCDialKeypad)) { DialKeypad = new SmartObjectNumeric(TriList.SmartObjects[UISmartObjectJoin.VCDialKeypad], true); DialKeypad.Digit0.SetSigFalseAction(() => DialKeypadPress("0")); DialKeypad.Digit1.SetSigFalseAction(() => DialKeypadPress("1")); DialKeypad.Digit2.SetSigFalseAction(() => DialKeypadPress("2")); DialKeypad.Digit3.SetSigFalseAction(() => DialKeypadPress("3")); DialKeypad.Digit4.SetSigFalseAction(() => DialKeypadPress("4")); DialKeypad.Digit5.SetSigFalseAction(() => DialKeypadPress("5")); DialKeypad.Digit6.SetSigFalseAction(() => DialKeypadPress("6")); DialKeypad.Digit7.SetSigFalseAction(() => DialKeypadPress("7")); DialKeypad.Digit8.SetSigFalseAction(() => DialKeypadPress("8")); DialKeypad.Digit9.SetSigFalseAction(() => DialKeypadPress("9")); DialKeypad.Misc1SigName = "*"; DialKeypad.Misc1.SetSigFalseAction(() => DialKeypadPress("*")); DialKeypad.Misc2SigName = "#"; DialKeypad.Misc2.SetSigFalseAction(() => DialKeypadPress("#")); //TriList.SetSigFalseAction(UIBoolJoin.VCKeypadBackspacePress, DialKeypadBackspacePress); TriList.SetSigHeldAction(UIBoolJoin.VCKeypadBackspacePress, 500, StartBackspaceRepeat, StopBackspaceRepeat, DialKeypadBackspacePress); } else Debug.Console(0, "Trilist {0:x2}, VC dial keypad object {1} not found. Check SGD file or VTP", TriList.ID, UISmartObjectJoin.VCDialKeypad); } /// /// /// void SetupRecentCallsList() { var codec = Codec as IHasCallHistory; if (codec != null) { codec.CallHistory.RecentCallsListHasChanged += (o, a) => RefreshRecentCallsList(); // EVENT??????????????? Pointed at refresh RecentCallsList = new SmartObjectDynamicList(TriList.SmartObjects[UISmartObjectJoin.VCRecentsList], true, 1200); RefreshRecentCallsList(); } } /// /// /// void RefreshRecentCallsList() { var codec = Codec as IHasCallHistory; uint textOffset = 1200; uint timeTextOffset = 1230; if (codec != null) { ushort i = 0; foreach (var c in codec.CallHistory.RecentCalls) { i++; TriList.SetString(textOffset + i, c.Name); // if it's today, show a simpler string string timeText = null; if (c.StartTime.Date == DateTime.Now.Date) timeText = c.StartTime.ToString("t", Global.Culture); else if (c.StartTime == DateTime.MinValue) timeText = ""; else timeText = c.StartTime.ToString(); TriList.SetString(timeTextOffset + i, timeText); string iconName = null; if (c.OccurrenceType == eCodecOccurrenceType.Received) iconName = "Misc-18_Light"; else if (c.OccurrenceType == eCodecOccurrenceType.Placed) iconName = "Misc-17_Light"; else iconName = "Delete"; RecentCallsList.SetItemIcon(i, iconName); var call = c; // for lambda scope RecentCallsList.SetItemButtonAction(i, b => { if(!b) Codec.Dial(call.Number); }); } RecentCallsList.Count = i; } } /// /// /// void SetupFavorites() { var c = Codec as IHasCallFavorites; if (c != null && c.CallFavorites != null) { CodecHasFavorites = true; var favs = c.CallFavorites.Favorites; for (uint i = 0; i <= 3; i++) { if (i < favs.Count) { var fav = favs[(int)i]; TriList.SetString(UIStringJoin.VCFavoritesStart + i, fav.Name); TriList.SetBool(UIBoolJoin.VCFavoriteVisibleStart + i, true); TriList.SetSigFalseAction(UIBoolJoin.VCFavoritePressStart + i, () => { Codec.Dial(fav.Number); }); } else TriList.SetBool(UIBoolJoin.VCFavoriteVisibleStart + i, false); } } } /// /// /// void SetupDirectoryList() { var codec = Codec as IHasDirectory; if (codec == null) { return; } DirectoryList = new SmartObjectDynamicList(TriList.SmartObjects[UISmartObjectJoin.VCDirectoryList], true, 1300); codec.DirectoryResultReturned += dir_DirectoryResultReturned; if (codec.PhonebookSyncState.InitialSyncComplete) SetCurrentDirectoryToRoot(); else { codec.PhonebookSyncState.InitialSyncCompleted += PhonebookSyncState_InitialSyncCompleted; } } /// /// Sets the current directory results to the DirectoryRoot and updates Back Button visibiltiy /// void SetCurrentDirectoryToRoot() { var hasDirectory = Codec as IHasDirectory; if (hasDirectory == null) { return; } hasDirectory.SetCurrentDirectoryToRoot(); SearchKeypadClear(); } /// /// Setup the Directory list when notified that the initial phonebook sync is completed /// /// /// void PhonebookSyncState_InitialSyncCompleted(object sender, EventArgs e) { var codec = Codec as IHasDirectory; if (codec == null) { return; } if (!codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue) { return; } SetCurrentDirectoryToRoot(); } /// /// /// /// /// void dir_DirectoryResultReturned(object sender, DirectoryEventArgs e) { RefreshDirectory(e.Directory); } /// /// Helper method to retrieve directory folder contents and store last requested folder id /// /// void GetDirectoryFolderContents(DirectoryFolder folder) { (Codec as IHasDirectory).GetDirectoryFolderContents(folder.FolderId); } /// /// Request the parent folder contents or sets back to the root if no parent folder /// void GetDirectoryParentFolderContents() { var codec = Codec as IHasDirectory; if (codec != null) { codec.GetDirectoryParentFolderContents(); //RefreshDirectory(); } } /// /// /// void RefreshDirectory() { var codec = Codec as IHasDirectory; if (codec == null) { return; } RefreshDirectory(codec.CurrentDirectoryResult); } void RefreshDirectory(CodecDirectory directory) { if (directory.CurrentDirectoryResults.Count > 0) { ushort i = 0; foreach (var r in directory.CurrentDirectoryResults) { if (i == DirectoryList.MaxCount) { break; } i++; if (r is DirectoryContact) { DirectoryList.SetItemMainText(i, r.Name); var dc = r as DirectoryContact; if (dc.ContactMethods.Count > 1) { // If more than one contact method, show contact method modal dialog DirectoryList.SetItemButtonAction(i, b => { if (b) { return; } // Refresh the contact methods list RefreshContactMethodsModalList(dc); Parent.PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.MeetingsOrContacMethodsListVisible); }); } else if (dc.ContactMethods.Count == 1) { var invitableContact = dc as IInvitableContact; if (invitableContact != null) { DirectoryList.SetItemButtonAction(i, b => { if (!b) Codec.Dial(invitableContact); }); } else { // If only one contact method, just dial that method DirectoryList.SetItemButtonAction(i, b => { if (!b) Codec.Dial(dc.ContactMethods[0].Number); }); } } else { Debug.Console(1, "Unable to dial contact. No availble ContactMethod(s) specified"); } } else // is DirectoryFolder { DirectoryList.SetItemMainText(i, string.Format("[+] {0}", r.Name)); var df = r as DirectoryFolder; DirectoryList.SetItemButtonAction(i, b => { if (!b) { GetDirectoryFolderContents(df); // will later call event handler after folder contents retrieved } }); } } DirectoryList.Count = i; } else // No results in directory, display message to user { DirectoryList.Count = 1; DirectoryList.SetItemMainText(1, "No Results Found"); } } void RefreshContactMethodsModalList(DirectoryContact contact) { TriList.SetString(UIStringJoin.MeetingsOrContactMethodListIcon, "Users"); TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Contact Methods"); ushort i = 0; foreach (var c in contact.ContactMethods) { i++; Parent.MeetingOrContactMethodModalSrl.StringInputSig(i, 1).StringValue = c.Device.ToString(); Parent.MeetingOrContactMethodModalSrl.StringInputSig(i, 2).StringValue = c.CallType.ToString(); Parent.MeetingOrContactMethodModalSrl.StringInputSig(i, 3).StringValue = c.Number; Parent.MeetingOrContactMethodModalSrl.StringInputSig(i, 4).StringValue = ""; Parent.MeetingOrContactMethodModalSrl.StringInputSig(i, 5).StringValue = "Connect"; Parent.MeetingOrContactMethodModalSrl.BoolInputSig(i, 2).BoolValue = true; var cc = c; // to maintian lambda scope Parent.MeetingOrContactMethodModalSrl.GetBoolFeedbackSig(i, 1).SetSigFalseAction(() => { Parent.PopupInterlock.Hide(); var codec = Codec as VideoCodecBase; if (codec != null) codec.Dial(cc.Number); }); } Parent.MeetingOrContactMethodModalSrl.Count = i; } /// /// /// void SetupLayoutControls() { TriList.SetSigFalseAction(UIBoolJoin.VCStagingSelfViewLayoutPress, this.ShowSelfViewLayout); var svc = Codec as IHasCodecSelfView; if (svc != null) { TriList.SetSigFalseAction(UIBoolJoin.VCSelfViewTogglePress, svc.SelfViewModeToggle); svc.SelfviewIsOnFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.VCSelfViewTogglePress]); } var lc = Codec as IHasCodecLayouts; if (lc != null) { lc.LocalLayoutFeedback.LinkInputSig(TriList.StringInput[UIStringJoin.VCLayoutModeText]); lc.LocalLayoutFeedback.OutputChange += (o,a) => { TriList.BooleanInput[UIBoolJoin.VCLayoutTogglePress].BoolValue = lc.LocalLayoutFeedback.StringValue == "Prominent"; }; // attach to cisco special things to enable buttons var cisco = Codec as PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.CiscoSparkCodec; if (cisco != null) { TriList.SetSigFalseAction(UIBoolJoin.VCLayoutTogglePress, lc.LocalLayoutToggleSingleProminent); // Cisco has min/max buttons that need special sauce cisco.SharingContentIsOnFeedback.OutputChange += CiscoSharingAndPresentation_OutputChanges; //cisco.PresentationViewMaximizedFeedback.OutputChange += CiscoSharingAndPresentation_OutputChanges; TriList.SetSigFalseAction(UIBoolJoin.VCMinMaxPress, cisco.MinMaxLayoutToggle); } var zoomRoom = Codec as PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom.ZoomRoom; if (zoomRoom != null) { TriList.BooleanInput[UIBoolJoin.VCLayoutToggleEnable].BoolValue = true; TriList.SetSigFalseAction(UIBoolJoin.VCLayoutTogglePress, lc.LocalLayoutToggle); } } } /// /// This should only be linked by cisco classes (spark initially) /// /// /// void CiscoSharingAndPresentation_OutputChanges(object sender, EventArgs e) { var cisco = Codec as PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.CiscoSparkCodec; if (cisco != null) { var sharingNear = cisco.SharingContentIsOnFeedback.BoolValue; var sharingFar = cisco.FarEndIsSharingContentFeedback.BoolValue; //set feedback and enables TriList.BooleanInput[UIBoolJoin.VCMinMaxEnable].BoolValue = sharingNear; TriList.BooleanInput[UIBoolJoin.VCLayoutToggleEnable].BoolValue = sharingNear || sharingFar; TriList.BooleanInput[UIBoolJoin.VCMinMaxPress].BoolValue = sharingNear; } } /// /// /// void RevealKeyboard() { if (_passwordPromptDialogVisible) { Debug.Console(2, "Attaching Keyboard to PasswordPromptDialog"); DetachDialKeyboard(); DetachSearchKeyboard(); var kb = Parent.Keyboard; kb.KeyPress -= Keyboard_PasswordKeyPress; kb.KeyPress += Keyboard_PasswordKeyPress; kb.HideAction = this.DetachPasswordKeyboard; kb.GoButtonText = "Submit"; kb.GoButtonVisible = true; PasswordStringCheckEnables(); kb.Show(); } else if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCKeypadWithFavoritesVisible && KeypadMode == eKeypadMode.Dial) { var kb = Parent.Keyboard; kb.KeyPress -= Keyboard_DialKeyPress; kb.KeyPress += Keyboard_DialKeyPress; kb.HideAction = this.DetachDialKeyboard; kb.GoButtonText = "Connect"; kb.GoButtonVisible = true; DialStringTextCheckEnables(); kb.Show(); } else if(VCControlsInterlock.CurrentJoin == UIBoolJoin.VCDirectoryVisible) { var kb = Parent.Keyboard; kb.KeyPress -= Keyboard_SearchKeyPress; kb.KeyPress += Keyboard_SearchKeyPress; kb.HideAction = this.DetachSearchKeyboard; kb.GoButtonText = "Search"; kb.GoButtonVisible = true; SearchStringKeypadCheckEnables(); kb.Show(); } } /// /// Event handler for keyboard dialing /// void Keyboard_DialKeyPress(object sender, PepperDash.Essentials.Core.Touchpanels.Keyboards.KeyboardControllerPressEventArgs e) { if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCKeypadWithFavoritesVisible && KeypadMode == eKeypadMode.Dial) { if (e.Text != null) DialStringBuilder.Append(e.Text); else { if (e.SpecialKey == KeyboardSpecialKey.Backspace) DialKeypadBackspacePress(); else if (e.SpecialKey == KeyboardSpecialKey.Clear) DialKeypadClear(); else if (e.SpecialKey == KeyboardSpecialKey.GoButton) { ConnectPress(); } } DialStringFeedback.FireUpdate(); DialStringTextCheckEnables(); } } /// /// Event handler for keyboard directory searches /// /// /// void Keyboard_SearchKeyPress(object sender, KeyboardControllerPressEventArgs e) { if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCDirectoryVisible) { if (e.Text != null) SearchStringBuilder.Append(e.Text); else { if (e.SpecialKey == KeyboardSpecialKey.Backspace) SearchKeypadBackspacePress(); else if (e.SpecialKey == KeyboardSpecialKey.Clear) SearchKeypadClear(); else if (e.SpecialKey == KeyboardSpecialKey.GoButton) { SearchPress(); Parent.Keyboard.Hide(); } } SearchStringFeedback.FireUpdate(); SearchStringKeypadCheckEnables(); } } /// /// Event handler for keyboard dialing /// void Keyboard_PasswordKeyPress(object sender, PepperDash.Essentials.Core.Touchpanels.Keyboards.KeyboardControllerPressEventArgs e) { if (_passwordPromptDialogVisible) { if (e.Text != null) PasswordStringBuilder.Append(e.Text); else { if (e.SpecialKey == KeyboardSpecialKey.Backspace) PasswordKeypadBackspacePress(); else if (e.SpecialKey == KeyboardSpecialKey.Clear) PasswordKeypadClear(); else if (e.SpecialKey == KeyboardSpecialKey.GoButton) { (Codec as IPasswordPrompt).SubmitPassword(PasswordStringBuilder.ToString()); HidePasswordPrompt(); } } PasswordStringFeedback.FireUpdate(); PasswordStringCheckEnables(); } } /// /// Call /// void DetachDialKeyboard() { Parent.Keyboard.KeyPress -= Keyboard_DialKeyPress; } void DetachSearchKeyboard() { Parent.Keyboard.KeyPress -= Keyboard_SearchKeyPress; } void DetachPasswordKeyboard() { Parent.Keyboard.KeyPress -= Keyboard_PasswordKeyPress; } /// /// Shows the camera controls subpage /// void ShowCameraControls() { if (ShowCameraModeControls) { VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCCameraModeBarVisible); if (VCCameraControlModeInterlock.CurrentJoin != 0) { VCCameraControlModeInterlock.Show(); } else { var codecAutoCamera = Codec as IHasCameraAutoMode; if (codecAutoCamera != null) { ShowCameraManualMode(); VCCameraControlModeInterlock.Show(); } } } else { // Just show the manual camera control page VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCCameraManualVisible); } StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingCameraPress); } /// /// shows the directory subpage /// void ShowDirectory() { // populate directory VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCDirectoryVisible); StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingDirectoryPress); } /// /// shows the appropriate keypad depending on mode and whether visible /// void ShowKeypad() { uint join = Codec.IsInCall ? UIBoolJoin.VCKeypadVisible : UIBoolJoin.VCKeypadWithFavoritesVisible; if (IsVisible) VCControlsInterlock.ShowInterlocked(join); else VCControlsInterlock.SetButDontShow(join); StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingKeypadPress); } /// /// Shows the self-view layout controls subpage /// void ShowSelfViewLayout() { VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCCameraAutoVisible); StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingSelfViewLayoutPress); } /// /// Shows the recents subpage /// void ShowRecents() { //populate recents VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCRecentsVisible); StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingRecentsPress); } /// /// Meet Now button /// void MeetNowPress() { var startMeetingCodec = Codec as IHasStartMeeting; if (startMeetingCodec != null) { startMeetingCodec.StartMeeting(startMeetingCodec.DefaultMeetingDurationMin); } else { Debug.Console(2, "Codce does not implment IHasStartMeeting. Cannot meet now"); } } /// /// Connect call button /// void ConnectPress() { if (Parent.Keyboard != null) Parent.Keyboard.Hide(); Codec.Dial(DialStringBuilder.ToString()); } /// /// Stop Sharing button /// void CallStopSharingPress() { Codec.StopSharing(); Parent.CurrentRoom.RunRouteAction("codecOsd", Parent.CurrentRoom.SourceListKey); } /// /// /// /// void DialKeypadPress(string i) { if (KeypadMode == eKeypadMode.Dial) { DialStringBuilder.Append(i); DialStringFeedback.FireUpdate(); DialStringTextCheckEnables(); } else { Codec.SendDtmf(i); DialStringBuilder.Append(i); DialStringFeedback.FireUpdate(); // no delete key in this mode! } DialStringTextCheckEnables(); } /// /// Does what it says /// void StartBackspaceRepeat() { if (BackspaceTimer == null) { BackspaceTimer = new CTimer(o => DialKeypadBackspacePress(), null, 0, 175); } } /// /// Does what it says /// void StopBackspaceRepeat() { if (BackspaceTimer != null) { BackspaceTimer.Stop(); BackspaceTimer = null; } } /// /// /// void DialKeypadBackspacePress() { if (KeypadMode == eKeypadMode.Dial) { DialStringBuilder.Remove(DialStringBuilder.Length - 1, 1); DialStringFeedback.FireUpdate(); DialStringTextCheckEnables(); } else DialKeypadClear(); } /// /// Clears the dial keypad /// void DialKeypadClear() { DialStringBuilder.Remove(0, DialStringBuilder.Length); DialStringFeedback.FireUpdate(); DialStringTextCheckEnables(); } /// /// Checks the enabled states of various elements around the keypad /// void DialStringTextCheckEnables() { var textIsEntered = DialStringBuilder.Length > 0; TriList.SetBool(UIBoolJoin.VCKeypadBackspaceVisible, textIsEntered); TriList.SetBool(UIBoolJoin.VCStagingConnectEnable, textIsEntered); if (textIsEntered) Parent.Keyboard.EnableGoButton(); else Parent.Keyboard.DisableGoButton(); } /// /// /// void SearchPress() { (Codec as IHasDirectory).SearchDirectory(SearchStringBuilder.ToString()); } /// /// /// /// void SearchKeyboardPress(string i) { SearchStringBuilder.Append(i); SearchStringFeedback.FireUpdate(); SearchStringKeypadCheckEnables(); } /// /// Does what it says /// void StartSearchBackspaceRepeat() { if (BackspaceTimer == null) { BackspaceTimer = new CTimer(o => SearchKeypadBackspacePress(), null, 0, 175); } } /// /// Does what it says /// void StopSearchBackspaceRepeat() { if (BackspaceTimer != null) { BackspaceTimer.Stop(); BackspaceTimer = null; } } /// /// /// void SearchKeypadBackspacePress() { SearchStringBuilder.Remove(SearchStringBuilder.Length - 1, 1); if (SearchStringBuilder.Length == 0) SetCurrentDirectoryToRoot(); SearchStringFeedback.FireUpdate(); SearchStringKeypadCheckEnables(); } /// /// Clears the Search keypad /// void SearchKeypadClear() { SearchStringBuilder.Remove(0, SearchStringBuilder.Length); SearchStringFeedback.FireUpdate(); SearchStringKeypadCheckEnables(); if ((Codec as IHasDirectory).CurrentDirectoryResultIsNotDirectoryRoot.BoolValue) SetCurrentDirectoryToRoot(); } /// /// Checks the enabled states of various elements around the keypad /// void SearchStringKeypadCheckEnables() { var textIsEntered = SearchStringBuilder.Length > 0; TriList.SetBool(UIBoolJoin.VCDirectoryBackspaceVisible, textIsEntered); if (textIsEntered) Parent.Keyboard.EnableGoButton(); else Parent.Keyboard.DisableGoButton(); } /// /// Clears the Password keypad /// void PasswordKeypadClear() { PasswordStringBuilder.Remove(0, PasswordStringBuilder.Length); PasswordStringFeedback.FireUpdate(); PasswordStringCheckEnables(); } /// /// /// void PasswordKeypadBackspacePress() { PasswordStringBuilder.Remove(PasswordStringBuilder.Length - 1, 1); PasswordStringFeedback.FireUpdate(); PasswordStringCheckEnables(); } /// /// Checks the enabled states of various elements around the keypad /// void PasswordStringCheckEnables() { var textIsEntered = PasswordStringBuilder.Length > 0; if (textIsEntered) Parent.Keyboard.EnableGoButton(); else Parent.Keyboard.DisableGoButton(); } /// /// Returns the text value for the keypad dial entry field /// /// string GetFormattedDialString(string ds) { if (DialStringBuilder.Length == 0 && !Codec.IsInCall) { return "Tap for keyboard"; } return GetFormattedPhoneNumber(ds); } /// /// Formats a string of numbers as a North American phone number /// /// /// string GetFormattedPhoneNumber(string s) { if (Regex.Match(s, @"^\d{4,7}$").Success) // 456-7890 return string.Format("{0}-{1}", s.Substring(0, 3), s.Substring(3)); if (Regex.Match(s, @"^9\d{4,7}$").Success) // 456-7890 return string.Format("9 {0}-{1}", s.Substring(1, 3), s.Substring(4)); if (Regex.Match(s, @"^\d{8,10}$").Success) // 123-456-78 return string.Format("({0}) {1}-{2}", s.Substring(0, 3), s.Substring(3, 3), s.Substring(6)); if (Regex.Match(s, @"^\d{10}$").Success) // 123-456-7890 full return string.Format("({0}) {1}-{2}", s.Substring(0, 3), s.Substring(3, 3), s.Substring(6)); if (Regex.Match(s, @"^1\d{10}$").Success) return string.Format("+1 ({0}) {1}-{2}", s.Substring(1, 3), s.Substring(4, 3), s.Substring(7)); if (Regex.Match(s, @"^9\d{10}$").Success) return string.Format("9 ({0}) {1}-{2}", s.Substring(1, 3), s.Substring(4, 3), s.Substring(7)); if (Regex.Match(s, @"^91\d{10}$").Success) return string.Format("9 +1 ({0}) {1}-{2}", s.Substring(2, 3), s.Substring(5, 3), s.Substring(8)); return s; } enum eKeypadMode { Dial = 0, DTMF } void SetupPasswordPrompt() { var passwordPromptCodec = Codec as IPasswordPrompt; passwordPromptCodec.PasswordRequired += new EventHandler(passwordPromptCodec_PasswordRequired); TriList.SetSigFalseAction(UIBoolJoin.PasswordPromptCancelPress, HidePasswordPrompt); TriList.SetSigFalseAction(UIBoolJoin.PasswordPromptTextPress, RevealKeyboard); } void passwordPromptCodec_PasswordRequired(object sender, PasswordPromptEventArgs e) { if (e.LoginAttemptCancelled) { HidePasswordPrompt(); return; } if (!string.IsNullOrEmpty(e.Message)) { TriList.SetString(UIStringJoin.PasswordPromptMessageText, e.Message); } if (e.LoginAttemptFailed) { // TODO: Show a message modal to indicate the login attempt failed return; } TriList.SetBool(UIBoolJoin.PasswordPromptErrorVisible, e.LastAttemptWasIncorrect); ShowPasswordPrompt(); } private bool _passwordPromptDialogVisible; void ShowPasswordPrompt() { // Clear out any previous data PasswordKeypadClear(); _passwordPromptDialogVisible = true; TriList.SetBool(UIBoolJoin.PasswordPromptDialogVisible, _passwordPromptDialogVisible); RevealKeyboard(); } void HidePasswordPrompt() { if (_passwordPromptDialogVisible) { _passwordPromptDialogVisible = false; Parent.Keyboard.Hide(); TriList.SetBool(UIBoolJoin.PasswordPromptDialogVisible, _passwordPromptDialogVisible); PasswordKeypadClear(); } } } }