diff --git a/PepperDashEssentials/OTHER/Fusion/FusionCustomPropertiesBridge.cs b/PepperDashEssentials/OTHER/Fusion/FusionCustomPropertiesBridge.cs index c651604a..42b43f13 100644 --- a/PepperDashEssentials/OTHER/Fusion/FusionCustomPropertiesBridge.cs +++ b/PepperDashEssentials/OTHER/Fusion/FusionCustomPropertiesBridge.cs @@ -37,6 +37,8 @@ namespace PepperDash.Essentials.Fusion if (device is RoomOnToDefaultSourceWhenOccupied) { + Debug.Console(1, "Mapping Room on via Occupancy values from Fusion"); + var devProps = JsonConvert.DeserializeObject(deviceConfig.Properties.ToString()); var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupied")); @@ -84,13 +86,19 @@ namespace PepperDash.Essentials.Fusion else if (device is EssentialsRoomBase) { // Set the room name - deviceConfig.Name = roomInfo.Name; + if (!string.IsNullOrEmpty(roomInfo.Name)) + { + Debug.Console(1, "Current Room Name: {0}. New Room Name: {1}", deviceConfig.Name, roomInfo.Name); + deviceConfig.Name = roomInfo.Name; + Debug.Console(1, "Room Name Successfully Changed."); + } // Set the help message var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage")); if (helpMessage != null) { - deviceConfig.Properties["Help"]["Message"].Value(helpMessage.CustomFieldValue); + //Debug.Console(1, "Current Help Message: {0}. New Help Message: {1}", deviceConfig.Properties["help"]["message"].Value(ToString()), helpMessage.CustomFieldValue); + deviceConfig.Properties["helpMessage"] = (string)helpMessage.CustomFieldValue; } } diff --git a/PepperDashEssentials/Properties/AssemblyInfo.cs b/PepperDashEssentials/Properties/AssemblyInfo.cs index 36c70ef4..12d80072 100644 --- a/PepperDashEssentials/Properties/AssemblyInfo.cs +++ b/PepperDashEssentials/Properties/AssemblyInfo.cs @@ -4,5 +4,5 @@ [assembly: AssemblyCompany("PepperDash Technology Corp")] [assembly: AssemblyProduct("PepperDashEssentials")] [assembly: AssemblyCopyright("Copyright © PepperDash Technology Corp 2018")] -[assembly: AssemblyVersion("1.2.6.*")] +[assembly: AssemblyVersion("1.3.0.*")] diff --git a/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs b/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs index 57e78ead..b12fd2e5 100644 --- a/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs +++ b/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs @@ -146,7 +146,7 @@ namespace PepperDash.Essentials.Room.Behaviours var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); if(newPropertiesConfig != null) - PropertiesConfig = newPropertiesConfig; + PropertiesConfig = newPropertiesConfig; ConfigWriter.UpdateDeviceConfig(config); diff --git a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs index 049c15dc..1a2515db 100644 --- a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs @@ -24,64 +24,14 @@ namespace PepperDash.Essentials.Room.Config var typeName = roomConfig.Type.ToLower(); if (typeName == "huddle") { - var props = JsonConvert.DeserializeObject - (roomConfig.Properties.ToString()); - var disp = DeviceManager.GetDeviceForKey(props.DefaultDisplayKey) as IRoutingSinkWithSwitching; - var audio = DeviceManager.GetDeviceForKey(props.DefaultAudioKey) as IRoutingSinkNoSwitching; - var huddle = new EssentialsHuddleSpaceRoom(roomConfig.Key, roomConfig.Name, disp, audio, props); + var huddle = new EssentialsHuddleSpaceRoom(roomConfig); - if (props.Occupancy != null) - huddle.SetRoomOccupancy(DeviceManager.GetDeviceForKey(props.Occupancy.DeviceKey) as - PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, props.Occupancy.TimoutMinutes); - huddle.LogoUrl = props.Logo.GetUrl(); - huddle.SourceListKey = props.SourceListKey; - huddle.DefaultSourceItem = props.DefaultSourceItem; - huddle.DefaultVolume = (ushort)(props.Volumes.Master.Level * 65535 / 100); return huddle; } - //else if (typeName == "presentation") - //{ - // var props = JsonConvert.DeserializeObject - // (this.Properties.ToString()); - // var displaysDict = new Dictionary(); - // uint i = 1; - // foreach (var dispKey in props.DisplayKeys) // read in the ordered displays list - // { - // var disp = DeviceManager.GetDeviceForKey(dispKey) as IRoutingSinkWithSwitching; - // displaysDict.Add(i++, disp); - // } - - // // Get the master volume control - // IBasicVolumeWithFeedback masterVolumeControlDev = props.Volumes.Master.GetDevice(); - - - // var presRoom = new EssentialsPresentationRoom(Key, Name, displaysDict, masterVolumeControlDev, props); - // return presRoom; - //} else if (typeName == "huddlevtc1") { - var props = JsonConvert.DeserializeObject - (roomConfig.Properties.ToString()); - var disp = DeviceManager.GetDeviceForKey(props.DefaultDisplayKey) as IRoutingSinkWithSwitching; - - var codec = DeviceManager.GetDeviceForKey(props.VideoCodecKey) as - PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase; - - var rm = new EssentialsHuddleVtc1Room(roomConfig.Key, roomConfig.Name, disp, codec, codec, props); - // Add Occupancy object from config - - if (props.Occupancy != null) - rm.SetRoomOccupancy(DeviceManager.GetDeviceForKey(props.Occupancy.DeviceKey) as - PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, props.Occupancy.TimoutMinutes); - rm.LogoUrl = props.Logo.GetUrl(); - rm.SourceListKey = props.SourceListKey; - rm.DefaultSourceItem = props.DefaultSourceItem; - rm.DefaultVolume = (ushort)(props.Volumes.Master.Level * 65535 / 100); - - rm.MicrophonePrivacy = GetMicrophonePrivacy(props, rm); // Get Microphone Privacy object, if any - - rm.Emergency = GetEmergency(props, rm); // Get emergency object, if any - + var rm = new EssentialsHuddleVtc1Room(roomConfig); + return rm; } else if (typeName == "ddvc01Bridge") @@ -96,7 +46,7 @@ namespace PepperDash.Essentials.Room.Config /// Gets and operating, standalone emergegncy object that can be plugged into a room. /// Returns null if there is no emergency defined /// - static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, EssentialsRoomBase room) + public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, EssentialsRoomBase room) { // This emergency var emergency = props.Emergency; @@ -115,7 +65,7 @@ namespace PepperDash.Essentials.Room.Config /// /// /// - static PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController GetMicrophonePrivacy( + public static PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController GetMicrophonePrivacy( EssentialsRoomPropertiesConfig props, EssentialsHuddleVtc1Room room) { var microphonePrivacy = props.MicrophonePrivacy; diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs index ab1349f5..c701357d 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using Newtonsoft.Json; + using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; @@ -66,7 +68,7 @@ namespace PepperDash.Essentials } } - public EssentialsRoomPropertiesConfig PropertiesConfig { get; private set; } + public EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; private set; } public IRoutingSinkWithSwitching DefaultDisplay { get; private set; } public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; } @@ -147,22 +149,32 @@ namespace PepperDash.Essentials public string CurrentSourceInfoKey { get; private set; } - /// - /// - /// - /// - /// - public EssentialsHuddleSpaceRoom(string key, string name, IRoutingSinkWithSwitching defaultDisplay, - IRoutingSinkNoSwitching defaultAudio, EssentialsRoomPropertiesConfig config) - : base(key, name) + public EssentialsHuddleSpaceRoom(DeviceConfig config) + : base(config) + { + try + { + PropertiesConfig = JsonConvert.DeserializeObject + (config.Properties.ToString()); + DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching; + + + DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IRoutingSinkWithSwitching; + + Initialize(); + } + catch (Exception e) + { + Debug.Console(1, this, "Error building room: \n{0}", e); + } + } + + void Initialize() { - PropertiesConfig = config; - DefaultDisplay = defaultDisplay; - DefaultAudioDevice = defaultAudio; - if (defaultAudio is IBasicVolumeControls) - DefaultVolumeControls = defaultAudio as IBasicVolumeControls; - else if (defaultAudio is IHasVolumeDevice) - DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice; + if (DefaultAudioDevice is IBasicVolumeControls) + DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls; + else if (DefaultAudioDevice is IHasVolumeDevice) + DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice; CurrentVolumeControls = DefaultVolumeControls; var disp = DefaultDisplay as DisplayBase; @@ -195,6 +207,15 @@ namespace PepperDash.Essentials EnablePowerOnToLastSource = true; } + protected override void CustomSetConfig(DeviceConfig config) + { + var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); + + if (newPropertiesConfig != null) + PropertiesConfig = newPropertiesConfig; + + ConfigWriter.UpdateRoomConfig(config); + } /// /// @@ -225,6 +246,21 @@ namespace PepperDash.Essentials return true; } + public override bool CustomActivate() + { + // Add Occupancy object from config + if (PropertiesConfig.Occupancy != null) + this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as + PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimoutMinutes); + + this.LogoUrl = PropertiesConfig.Logo.GetUrl(); + this.SourceListKey = PropertiesConfig.SourceListKey; + this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem; + this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100); + + return base.CustomActivate(); + } + /// /// /// diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index f30519d6..28530c03 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using Newtonsoft.Json; + using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; @@ -195,26 +197,37 @@ namespace PepperDash.Essentials CCriticalSection SourceSelectLock = new CCriticalSection(); - /// - /// - /// - /// - /// - public EssentialsHuddleVtc1Room(string key, string name, IRoutingSinkWithSwitching defaultDisplay, - IBasicVolumeControls defaultAudio, VideoCodecBase codec, EssentialsHuddleVtc1PropertiesConfig config) - : base(key, name) - { - if (codec == null) - throw new ArgumentNullException("codec cannot be null"); - PropertiesConfig = config; - DefaultDisplay = defaultDisplay; - VideoCodec = codec; - DefaultAudioDevice = defaultAudio; - if (defaultAudio is IBasicVolumeControls) - DefaultVolumeControls = defaultAudio as IBasicVolumeControls; - else if (defaultAudio is IHasVolumeDevice) - DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice; + public EssentialsHuddleVtc1Room(DeviceConfig config) + : base(config) + { + try + { + PropertiesConfig = JsonConvert.DeserializeObject + (config.Properties.ToString()); + DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching; + + VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as + PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase; + if (VideoCodec == null) + throw new ArgumentNullException("codec cannot be null"); + + DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IBasicVolumeControls; + + Initialize(); + } + catch (Exception e) + { + Debug.Console(1, this, "Error building room: \n{0}", e); + } + } + + void Initialize() + { + if (DefaultAudioDevice is IBasicVolumeControls) + DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls; + else if (DefaultAudioDevice is IHasVolumeDevice) + DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice; CurrentVolumeControls = DefaultVolumeControls; @@ -264,6 +277,37 @@ namespace PepperDash.Essentials EnablePowerOnToLastSource = true; } + protected override void CustomSetConfig(DeviceConfig config) + { + var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); + + if (newPropertiesConfig != null) + PropertiesConfig = newPropertiesConfig; + + ConfigWriter.UpdateRoomConfig(config); + } + + public override bool CustomActivate() + { + // Add Occupancy object from config + if (PropertiesConfig.Occupancy != null) + this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as + PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimoutMinutes); + + this.LogoUrl = PropertiesConfig.Logo.GetUrl(); + this.SourceListKey = PropertiesConfig.SourceListKey; + this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem; + this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100); + + // Get Microphone Privacy object, if any + this.MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this); + + // Get emergency object, if any + this.Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this); + + return base.CustomActivate(); + } + /// /// diff --git a/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs b/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs index de0baccd..b61cbd37 100644 --- a/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs +++ b/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs @@ -7,6 +7,7 @@ using Crestron.SimplSharp.Scheduler; using PepperDash.Core; using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Devices.Common.Occupancy; @@ -122,50 +123,6 @@ namespace PepperDash.Essentials }); } - ///// - ///// - ///// - ///// - ///// - //public EssentialsRoomBase(string key, string name) : base(key, name) - //{ - // // Setup the ShutdownPromptTimer - // ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer"); - // ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) => - // { - // if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue) - // ShutdownType = eShutdownType.None; - // }; - // ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered - - // ShutdownPromptSeconds = 60; - // ShutdownVacancySeconds = 120; - // ShutdownType = eShutdownType.None; - - // RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer"); - // //RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) => - // //{ - // // if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue) - // // ShutdownType = ShutdownType.Vacancy; - // //}; - // RoomVacancyShutdownTimer.HasFinished += new EventHandler(RoomVacancyShutdownPromptTimer_HasFinished); // Shutdown is triggered - - // RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning - // RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt - // VacancyMode = eVacancyMode.None; - - // OnFeedback = new BoolFeedback(OnFeedbackFunc); - - // IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc); - // IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc); - - // AddPostActivationAction(() => - // { - // if (RoomOccupancy != null) - // OnRoomOccupancyIsSet(); - // }); - //} - void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e) { switch (VacancyMode) @@ -241,7 +198,7 @@ namespace PepperDash.Essentials /// /// public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes) - { + { if (statusProvider == null) { Debug.Console(0, this, "ERROR: Occupancy sensor device is null"); diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs index 1ef7b65b..b000cf42 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs @@ -1,1383 +1,1383 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.UI; - -using PepperDash.Core; +using System; +using System.Linq; +using System.Collections.Generic; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.UI; + +using PepperDash.Core; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.SmartObjects; -using PepperDash.Essentials.Core.PageManagers; -using PepperDash.Essentials.Room.Config; -using PepperDash.Essentials.Devices.Common.Codec; -using PepperDash.Essentials.Devices.Common.VideoCodec; - -namespace PepperDash.Essentials -{ - /// - /// - /// - public class EssentialsHuddleVtc1PanelAvFunctionsDriver : PanelDriverBase, IAVWithVCDriver - { - CrestronTouchpanelPropertiesConfig Config; - - public enum UiDisplayMode - { - Presentation, AudioSetup, Call, Start - } - - /// - /// Whether volume ramping from this panel will show the volume - /// gauge popup. - /// - public bool ShowVolumeGauge { get; set; } - - /// - /// - /// - public uint PowerOffTimeout { get; set; } - - /// - /// - /// - public string DefaultRoomKey { get; set; } - - - /// - /// - /// - public EssentialsHuddleVtc1Room CurrentRoom - { - get { return _CurrentRoom; } - set - { - SetCurrentRoom(value); - } - } - EssentialsHuddleVtc1Room _CurrentRoom; - - /// - /// For hitting feedbacks - /// - BoolInputSig CallButtonSig; - BoolInputSig ShareButtonSig; - BoolInputSig EndMeetingButtonSig; - - BoolFeedback CallSharingInfoVisibleFeedback; - - /// - /// The parent driver for this - /// - PanelDriverBase Parent; - - /// - /// All children attached to this driver. For hiding and showing as a group. - /// - List ChildDrivers = new List(); - - List CurrentDisplayModeSigsInUse = new List(); - - //// Important smart objects - - /// - /// Smart Object 3200 - /// - SubpageReferenceList SourceStagingSrl; - - /// - /// Smart Object 15022 - /// - SubpageReferenceList ActivityFooterSrl; - - /// - /// - /// - public SubpageReferenceList MeetingOrContactMethodModalSrl { get; set; } - - /// - /// The list of buttons on the header. Managed with visibility only - /// - //SmartObjectHeaderButtonList HeaderButtonsList; - - /// - /// The AV page mangagers that have been used, to keep them alive for later - /// - Dictionary PageManagers = new Dictionary(); - - /// - /// Current page manager running for a source - /// - PageManager CurrentSourcePageManager; - - /// - /// Will auto-timeout a power off - /// - CTimer PowerOffTimer; - - /// - /// - /// - ModalDialog PowerDownModal; - - /// - /// - /// - //ModalDialog WarmingCoolingModal; - - /// - /// Represents - /// - public JoinedSigInterlock PopupInterlock { get; private set; } - - /// - /// Interlock for various source, camera, call control bars. The bar above the activity footer. This is also - /// used to show start page - /// - JoinedSigInterlock StagingBarInterlock; - - /// - /// Interlocks the various call-related subpages - /// - JoinedSigInterlock CallPagesInterlock; - - /// - /// The Video codec driver - /// - PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver VCDriver; - - /// - /// The driver for the tech page. Lazy getter for memory usage - /// - PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver TechDriver - { - get - { - if (_TechDriver == null) - _TechDriver = new PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver(TriList, CurrentRoom.PropertiesConfig.Tech); - return _TechDriver; - } - } - PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver _TechDriver; - - /// - /// Controls timeout of notification ribbon timer - /// - CTimer RibbonTimer; - - /// - /// The keyboard - /// - public PepperDash.Essentials.Core.Touchpanels.Keyboards.HabaneroKeyboardController Keyboard { get; private set; } - - /// - /// The mode showing. Presentation or call. - /// - UiDisplayMode CurrentMode = UiDisplayMode.Start; - - CTimer NextMeetingTimer; - - /// - /// Tracks the last meeting that was cancelled - /// - string LastMeetingDismissedId; - - /// - /// Constructor - /// - public EssentialsHuddleVtc1PanelAvFunctionsDriver(PanelDriverBase parent, CrestronTouchpanelPropertiesConfig config) - : base(parent.TriList) - { - Config = config; - Parent = parent; - - PopupInterlock = new JoinedSigInterlock(TriList); - StagingBarInterlock = new JoinedSigInterlock(TriList); - CallPagesInterlock = new JoinedSigInterlock(TriList); - - SourceStagingSrl = new SubpageReferenceList(TriList, UISmartObjectJoin.SourceStagingSRL, 3, 3, 3); - - ActivityFooterSrl = new SubpageReferenceList(TriList, UISmartObjectJoin.ActivityFooterSRL, 3, 3, 3); - CallButtonSig = ActivityFooterSrl.BoolInputSig(2, 1); - ShareButtonSig = ActivityFooterSrl.BoolInputSig(1, 1); - EndMeetingButtonSig = ActivityFooterSrl.BoolInputSig(3, 1); - - MeetingOrContactMethodModalSrl = new SubpageReferenceList(TriList, UISmartObjectJoin.MeetingListSRL, 3, 3, 5); - - - // buttons are added in SetCurrentRoom - //HeaderButtonsList = new SmartObjectHeaderButtonList(TriList.SmartObjects[UISmartObjectJoin.HeaderButtonList]); - - SetupActivityFooterWhenRoomOff(); - - ShowVolumeGauge = true; - Keyboard = new PepperDash.Essentials.Core.Touchpanels.Keyboards.HabaneroKeyboardController(TriList); - } - - /// - /// Add a video codec driver to this - /// - /// - public void SetVideoCodecDriver(PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver vcd) - { - VCDriver = vcd; - } - - /// - /// - /// - public override void Show() - { - if (CurrentRoom == null) - { - Debug.Console(1, "ERROR: AVUIFunctionsDriver, Cannot show. No room assigned"); - return; - } - - var roomConf = CurrentRoom.PropertiesConfig; - - if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Habanero) - { - TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () => - PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderPageVisible)); - } - else if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose) - { - // room name on join 1, concat phone and sip on join 2, no button method - //var addr = roomConf.Addresses; - //if (addr == null) // protect from missing values by using default empties - // addr = new EssentialsRoomAddressPropertiesConfig(); - //// empty string when either missing, pipe when both showing - //TriList.SetString(UIStringJoin.RoomAddressPipeText, - // (string.IsNullOrEmpty(addr.PhoneNumber.Trim()) - // || string.IsNullOrEmpty(addr.SipAddress.Trim())) ? "" : " | "); - //TriList.SetString(UIStringJoin.RoomPhoneText, addr.PhoneNumber); - //TriList.SetString(UIStringJoin.RoomSipText, addr.SipAddress); - } - - TriList.SetBool(UIBoolJoin.DateAndTimeVisible, Config.ShowDate && Config.ShowTime); - TriList.SetBool(UIBoolJoin.DateOnlyVisible, Config.ShowDate && !Config.ShowTime); - TriList.SetBool(UIBoolJoin.TimeOnlyVisible, !Config.ShowDate && Config.ShowTime); - - TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true); - - TriList.SetBool(UIBoolJoin.ActivityFooterVisible, true); - - // Privacy mute button - TriList.SetSigFalseAction(UIBoolJoin.Volume1SpeechMutePressAndFB, CurrentRoom.PrivacyModeToggle); - CurrentRoom.PrivacyModeIsOnFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.Volume1SpeechMutePressAndFB]); - - // Default to showing rooms/sources now. - if (CurrentRoom.OnFeedback.BoolValue) - { - TriList.SetBool(UIBoolJoin.TapToBeginVisible, false); - SetupActivityFooterWhenRoomOn(); - } - else - { - TriList.SetBool(UIBoolJoin.StartPageVisible, true); - TriList.SetBool(UIBoolJoin.TapToBeginVisible, true); - SetupActivityFooterWhenRoomOff(); - } - ShowCurrentDisplayModeSigsInUse(); - - // *** Header Buttons *** - - // Generic "close" button for popup modals - TriList.SetSigFalseAction(UIBoolJoin.InterlockedModalClosePress, PopupInterlock.HideAndClear); - - // Volume related things - TriList.SetSigFalseAction(UIBoolJoin.VolumeDefaultPress, () => CurrentRoom.SetDefaultLevels()); - TriList.SetString(UIStringJoin.AdvancedVolumeSlider1Text, "Room"); - - //if (TriList is CrestronApp) - // TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = false; - //else - // TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = true; - - // power-related functions - // Note: some of these are not directly-related to the huddle space UI, but are held over - // in case - TriList.SetSigFalseAction(UIBoolJoin.ShowPowerOffPress, EndMeetingPress); - - TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () => - { - if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IPower) - (CurrentRoom.DefaultDisplay as IPower).PowerToggle(); - }); - - SetupNextMeetingTimer(); - - base.Show(); - } - - /// - /// Allows PopupInterlock to be toggled if the calls list is already visible, or if the codec is in a call - /// - public void ShowActiveCallsList() - { - TriList.SetBool(UIBoolJoin.CallEndAllConfirmVisible, true); - if(PopupInterlock.CurrentJoin == UIBoolJoin.HeaderActiveCallsListVisible) - PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HeaderActiveCallsListVisible); - else - { - if((CurrentRoom.ScheduleSource as VideoCodecBase).IsInCall) - PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HeaderActiveCallsListVisible); - } - } - - /// - /// - /// - void ShowLogo() - { - if (CurrentRoom.LogoUrl == null) - { - TriList.SetBool(UIBoolJoin.LogoDefaultVisible, true); - TriList.SetBool(UIBoolJoin.LogoUrlVisible, false); - } - else - { - TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false); - TriList.SetBool(UIBoolJoin.LogoUrlVisible, true); - TriList.SetString(UIStringJoin.LogoUrl, _CurrentRoom.LogoUrl); - } - } - - /// - /// - /// - void HideLogo() - { - TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false); - TriList.SetBool(UIBoolJoin.LogoUrlVisible, false); - } - - /// - /// - /// - public override void Hide() - { - HideAndClearCurrentDisplayModeSigsInUse(); - TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, false); - TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; - if (NextMeetingTimer != null) - NextMeetingTimer.Stop(); - HideNextMeetingPopup(); - base.Hide(); - } - - /// - /// Reveals a message on the notification ribbon until cleared - /// - /// Text to display - /// Time in ms to display. 0 to keep on screen - public void ShowNotificationRibbon(string message, int timeout) - { - TriList.SetString(UIStringJoin.NotificationRibbonText, message); - TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, true); - if (timeout > 0) - { - if (RibbonTimer != null) - RibbonTimer.Stop(); - RibbonTimer = new CTimer(o => { - TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false); - RibbonTimer = null; - }, timeout); - } - } - - /// - /// Hides the notification ribbon - /// - public void HideNotificationRibbon() - { - TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false); - if (RibbonTimer != null) - { - RibbonTimer.Stop(); - RibbonTimer = null; - } - } - - void SetupNextMeetingTimer() - { - var ss = CurrentRoom.ScheduleSource; - if (ss != null) - { - NextMeetingTimer = new CTimer(o => ShowNextMeetingTimerCallback(), null, 0, 60000); - } - } - - /// - /// - /// - void ShowNextMeetingTimerCallback() - { - // Every 60 seconds, refresh the calendar - RefreshMeetingsList(); - // check meetings list for the closest, joinable meeting - var ss = CurrentRoom.ScheduleSource; - var meetings = ss.CodecSchedule.Meetings; - - if (meetings.Count > 0) - { - // If the room is off pester the user - // If the room is on, and the meeting is joinable - // and the LastMeetingDismissed != this meeting - - var lastMeetingDismissed = meetings.FirstOrDefault(m => m.Id == LastMeetingDismissedId); - Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*", - CurrentRoom.OnFeedback.BoolValue, - LastMeetingDismissedId, - lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToShortTimeString() : ""); - - var meeting = meetings.LastOrDefault(m => m.Joinable); - if (CurrentRoom.OnFeedback.BoolValue - && lastMeetingDismissed == meeting) - { - return; - } - - LastMeetingDismissedId = null; - // Clear the popup when we run out of meetings - if (meeting == null) - { - HideNextMeetingPopup(); - } - else - { - TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Upcoming meeting"); - TriList.SetString(UIStringJoin.NextMeetingStartTimeText, meeting.StartTime.ToShortTimeString()); - TriList.SetString(UIStringJoin.NextMeetingEndTimeText, meeting.EndTime.ToShortTimeString()); - TriList.SetString(UIStringJoin.NextMeetingTitleText, meeting.Title); - TriList.SetString(UIStringJoin.NextMeetingNameText, meeting.Organizer); - TriList.SetString(UIStringJoin.NextMeetingButtonLabel, "Join"); - TriList.SetSigFalseAction(UIBoolJoin.NextMeetingJoinPress, () => - { - HideNextMeetingPopup(); - PopupInterlock.Hide(); - RoomOnAndDialMeeting(meeting); - }); - TriList.SetString(UIStringJoin.NextMeetingSecondaryButtonLabel, "Show Schedule"); - TriList.SetSigFalseAction(UIBoolJoin.CalendarHeaderButtonPress, () => - { - HideNextMeetingPopup(); - //CalendarPress(); - RefreshMeetingsList(); - PopupInterlock.ShowInterlocked(UIBoolJoin.MeetingsOrContacMethodsListVisible); - }); - var indexOfNext = meetings.IndexOf(meeting) + 1; - - // indexOf = 3, 4 meetings : - if (indexOfNext < meetings.Count) - TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, - meetings[indexOfNext].StartTime.ToShortTimeString()); - else - TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, "No more meetings today"); - - TriList.SetSigFalseAction(UIBoolJoin.NextMeetingModalClosePress, () => - { - // Mark the meeting to not re-harass the user - if(CurrentRoom.OnFeedback.BoolValue) - LastMeetingDismissedId = meeting.Id; - HideNextMeetingPopup(); - }); - - TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, true); - } - } - } - - /// - /// - /// - void HideNextMeetingPopup() - { - TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, false); - - } - - /// - /// Calendar should only be visible when it's supposed to - /// - public void CalendarPress() - { - //RefreshMeetingsList(); // List should be up-to-date - PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.MeetingsOrContacMethodsListVisible); - } - - /// - /// Dials a meeting after turning on room (if necessary) - /// - void RoomOnAndDialMeeting(Meeting meeting) - { - Action dialAction = () => - { - var d = CurrentRoom.ScheduleSource as VideoCodecBase; - if (d != null) - { - d.Dial(meeting); - LastMeetingDismissedId = meeting.Id; // To prevent prompts for already-joined call - } - }; - if (CurrentRoom.OnFeedback.BoolValue) - dialAction(); - else - { - // Rig a one-time handler to catch when the room is warmed and then dial call - EventHandler oneTimeHandler = null; - oneTimeHandler = (o, a) => - { - if (!CurrentRoom.IsWarmingUpFeedback.BoolValue) - { - CurrentRoom.IsWarmingUpFeedback.OutputChange -= oneTimeHandler; - dialAction(); - } - }; - CurrentRoom.IsWarmingUpFeedback.OutputChange += oneTimeHandler; - ActivityCallButtonPressed(); - } - } - - /// - /// Reveals the tech page and puts away anything that's in the way. - /// - public void ShowTech() - { - PopupInterlock.HideAndClear(); - TechDriver.Show(); - } - - /// - /// When the room is off, set the footer SRL - /// - void SetupActivityFooterWhenRoomOff() - { - ActivityFooterSrl.Clear(); - ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 0, - b => { if (!b) ActivityShareButtonPressed(); })); - ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl, 3, - b => { if (!b) ActivityCallButtonPressed(); })); - ActivityFooterSrl.Count = 2; - TriList.SetUshort(UIUshortJoin.PresentationStagingCaretMode, 1); // right one slot - TriList.SetUshort(UIUshortJoin.CallStagingCaretMode, 5); // left one slot - } - - /// - /// Sets up the footer SRL for when the room is on - /// - void SetupActivityFooterWhenRoomOn() - { - ActivityFooterSrl.Clear(); - ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 0, - b => { if (!b) ActivityShareButtonPressed(); })); - ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl, 3, - b => { if (!b) ActivityCallButtonPressed(); })); - ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(3, ActivityFooterSrl, 4, - b => { if (!b) EndMeetingPress(); })); - ActivityFooterSrl.Count = 3; - TriList.SetUshort(UIUshortJoin.PresentationStagingCaretMode, 2); // center - TriList.SetUshort(UIUshortJoin.CallStagingCaretMode, 0); // left -2 - } - - /// - /// Single point call for setting the feedbacks on the activity buttons - /// - void SetActivityFooterFeedbacks() - { - CallButtonSig.BoolValue = CurrentMode == UiDisplayMode.Call - && CurrentRoom.ShutdownType == eShutdownType.None; - ShareButtonSig.BoolValue = CurrentMode == UiDisplayMode.Presentation - && CurrentRoom.ShutdownType == eShutdownType.None; - EndMeetingButtonSig.BoolValue = CurrentRoom.ShutdownType != eShutdownType.None; - } - - /// - /// - /// - public void ActivityCallButtonPressed() - { - if (VCDriver.IsVisible) - return; - HideLogo(); - HideNextMeetingPopup(); - TriList.SetBool(UIBoolJoin.StartPageVisible, false); - TriList.SetBool(UIBoolJoin.SourceStagingBarVisible, false); - TriList.SetBool(UIBoolJoin.SelectASourceVisible, false); - if (CurrentSourcePageManager != null) - CurrentSourcePageManager.Hide(); - PowerOnFromCall(); - CurrentMode = UiDisplayMode.Call; - SetActivityFooterFeedbacks(); - VCDriver.Show(); - } - - /// - /// Attached to activity list share button - /// - void ActivityShareButtonPressed() - { - SetupSourceList(); - if (VCDriver.IsVisible) - VCDriver.Hide(); - HideNextMeetingPopup(); - TriList.SetBool(UIBoolJoin.StartPageVisible, false); - TriList.SetBool(UIBoolJoin.CallStagingBarVisible, false); - TriList.SetBool(UIBoolJoin.SourceStagingBarVisible, true); - // Run default source when room is off and share is pressed - if (!CurrentRoom.OnFeedback.BoolValue) - { - if (!CurrentRoom.OnFeedback.BoolValue) - { - // If there's no default, show UI elements - if (!CurrentRoom.RunDefaultPresentRoute()) - TriList.SetBool(UIBoolJoin.SelectASourceVisible, true); - } - } - else // room is on show what's active or select a source if nothing is yet active - { - if(CurrentRoom.CurrentSourceInfo == null || CurrentRoom.CurrentSourceInfoKey == CurrentRoom.DefaultCodecRouteString) - TriList.SetBool(UIBoolJoin.SelectASourceVisible, true); - else if (CurrentSourcePageManager != null) - CurrentSourcePageManager.Show(); - } - CurrentMode = UiDisplayMode.Presentation; - SetupSourceList(); - SetActivityFooterFeedbacks(); - } - - /// - /// Powers up the system to the codec route, if not already on. - /// - void PowerOnFromCall() - { - if (!CurrentRoom.OnFeedback.BoolValue) - { - CurrentRoom.RunDefaultCallRoute(); - } - } - - /// - /// Shows all sigs that are in CurrentDisplayModeSigsInUse - /// - void ShowCurrentDisplayModeSigsInUse() - { - foreach (var sig in CurrentDisplayModeSigsInUse) - sig.BoolValue = true; - } - - /// - /// Hides all CurrentDisplayModeSigsInUse sigs and clears the array - /// - void HideAndClearCurrentDisplayModeSigsInUse() - { - foreach (var sig in CurrentDisplayModeSigsInUse) - sig.BoolValue = false; - CurrentDisplayModeSigsInUse.Clear(); - } - - - /// - /// Loads the appropriate Sigs into CurrentDisplayModeSigsInUse and shows them - /// - void ShowCurrentSource() - { - if (CurrentRoom.CurrentSourceInfo == null) - return; - - if (CurrentRoom.CurrentSourceInfo.SourceDevice == null) - { - TriList.SetBool(UIBoolJoin.SelectASourceVisible, true); - return; - } - - var uiDev = CurrentRoom.CurrentSourceInfo.SourceDevice as IUiDisplayInfo; - PageManager pm = null; - // If we need a page manager, get an appropriate one - if (uiDev != null) - { - TriList.SetBool(UIBoolJoin.SelectASourceVisible, false); - // Got an existing page manager, get it - if (PageManagers.ContainsKey(uiDev)) - pm = PageManagers[uiDev]; - // Otherwise make an apporiate one - else if (uiDev is ISetTopBoxControls) - pm = new SetTopBoxThreePanelPageManager(uiDev as ISetTopBoxControls, TriList); - else if (uiDev is IDiscPlayerControls) - pm = new DiscPlayerMediumPageManager(uiDev as IDiscPlayerControls, TriList); - else - pm = new DefaultPageManager(uiDev, TriList); - PageManagers[uiDev] = pm; - CurrentSourcePageManager = pm; - pm.Show(); - } - } - - /// - /// Called from button presses on source, where We can assume we want - /// to change to the proper screen. - /// - /// The key name of the route to run - void UiSelectSource(string key) - { - // Run the route and when it calls back, show the source - CurrentRoom.RunRouteAction(key, null); - } - - /// - /// - /// - public void EndMeetingPress() - { - if (!CurrentRoom.OnFeedback.BoolValue - || CurrentRoom.ShutdownPromptTimer.IsRunningFeedback.BoolValue) - return; - - CurrentRoom.StartShutdown(eShutdownType.Manual); - } - - /// - /// Puts away modals and things that might be up when call comes in - /// - public void PrepareForCodecIncomingCall() - { - if (PowerDownModal != null && PowerDownModal.ModalIsVisible) - PowerDownModal.CancelDialog(); - PopupInterlock.Hide(); - } - - /// - /// - /// - /// - /// - void ShutdownPromptTimer_HasStarted(object sender, EventArgs e) - { - // Do we need to check where the UI is? No? - var timer = CurrentRoom.ShutdownPromptTimer; - SetActivityFooterFeedbacks(); - - if (CurrentRoom.ShutdownType == eShutdownType.Manual || CurrentRoom.ShutdownType == eShutdownType.Vacancy) - { - PowerDownModal = new ModalDialog(TriList); - var message = string.Format("Meeting will end in {0} seconds", CurrentRoom.ShutdownPromptSeconds); - - // Attach timer things to modal - CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; - CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange += ShutdownPromptTimer_PercentFeedback_OutputChange; - - // respond to offs by cancelling dialog - var onFb = CurrentRoom.OnFeedback; - EventHandler offHandler = null; - offHandler = (o, a) => - { - if (!onFb.BoolValue) - { - PowerDownModal.HideDialog(); - SetActivityFooterFeedbacks(); - onFb.OutputChange -= offHandler; - } - }; - onFb.OutputChange += offHandler; - - PowerDownModal.PresentModalDialog(2, "End Meeting", "Power", message, "Cancel", "End Meeting Now", true, true, - but => - { - if (but != 2) // any button except for End cancels - timer.Cancel(); - else - timer.Finish(); - }); - } - } - - /// - /// - /// - /// - /// - void ShutdownPromptTimer_HasFinished(object sender, EventArgs e) - { - SetActivityFooterFeedbacks(); - CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange -= ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; - CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; - } - - /// - /// - /// - /// - /// - void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e) - { - if (PowerDownModal != null) - PowerDownModal.HideDialog(); - SetActivityFooterFeedbacks(); - - CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; - CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; - } - - /// - /// Event handler for countdown timer on power off modal - /// - void ShutdownPromptTimer_TimeRemainingFeedback_OutputChange(object sender, EventArgs e) - { - - var message = string.Format("Meeting will end in {0} seconds", (sender as StringFeedback).StringValue); - TriList.StringInput[ModalDialog.MessageTextJoin].StringValue = message; - } - - /// - /// Event handler for percentage on power off countdown - /// - void ShutdownPromptTimer_PercentFeedback_OutputChange(object sender, EventArgs e) - { - var value = (ushort)((sender as IntFeedback).UShortValue * 65535 / 100); - TriList.UShortInput[ModalDialog.TimerGaugeJoin].UShortValue = value; - } - - /// - /// - /// - void CancelPowerOffTimer() - { - if (PowerOffTimer != null) - { - PowerOffTimer.Stop(); - PowerOffTimer = null; - } - } - - /// - /// - /// - /// - public void VolumeUpPress(bool state) - { - if (CurrentRoom.CurrentVolumeControls != null) - CurrentRoom.CurrentVolumeControls.VolumeUp(state); - } - - /// - /// - /// - /// - public void VolumeDownPress(bool state) - { - if (CurrentRoom.CurrentVolumeControls != null) - CurrentRoom.CurrentVolumeControls.VolumeDown(state); - } - - /// - /// Helper for property setter. Sets the panel to the given room, latching up all functionality - /// - void SetCurrentRoom(EssentialsHuddleVtc1Room room) - { - if (_CurrentRoom == room) return; - // Disconnect current (probably never called) - if (_CurrentRoom != null) - { - // Disconnect current room - _CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange; - ClearAudioDeviceConnections(); - _CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange; - DisconnectSource(_CurrentRoom.CurrentSourceInfo); - _CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted; - _CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished; - _CurrentRoom.ShutdownPromptTimer.WasCancelled -= ShutdownPromptTimer_WasCancelled; - - _CurrentRoom.OnFeedback.OutputChange -= CurrentRoom_OnFeedback_OutputChange; - _CurrentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange; - _CurrentRoom.IsCoolingDownFeedback.OutputChange -= CurrentRoom_IsCoolingDownFeedback_OutputChange; - _CurrentRoom.InCallFeedback.OutputChange -= CurrentRoom_InCallFeedback_OutputChange; - } - - _CurrentRoom = room; - - if (_CurrentRoom != null) - { - // get the source list config and set up the source list - - SetupSourceList(); - - // Name and logo - TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name; - ShowLogo(); - - // Shutdown timer - _CurrentRoom.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted; - _CurrentRoom.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished; - _CurrentRoom.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled; - - // Link up all the change events from the room - _CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange; - CurrentRoom_SyncOnFeedback(); - _CurrentRoom.IsWarmingUpFeedback.OutputChange += CurrentRoom_IsWarmingFeedback_OutputChange; - _CurrentRoom.IsCoolingDownFeedback.OutputChange += CurrentRoom_IsCoolingDownFeedback_OutputChange; - _CurrentRoom.InCallFeedback.OutputChange += CurrentRoom_InCallFeedback_OutputChange; - - - _CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange; - RefreshAudioDeviceConnections(); - _CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange; - RefreshSourceInfo(); - - (_CurrentRoom.VideoCodec as IHasScheduleAwareness).CodecSchedule.MeetingsListHasChanged += CodecSchedule_MeetingsListHasChanged; - - CallSharingInfoVisibleFeedback = new BoolFeedback(() => _CurrentRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue); - _CurrentRoom.VideoCodec.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange; - CallSharingInfoVisibleFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.CallSharedSourceInfoVisible]); - - SetActiveCallListSharingContentStatus(); - - if (_CurrentRoom != null) - _CurrentRoom.CurrentSingleSourceChange += new SourceInfoChangeHandler(CurrentRoom_CurrentSingleSourceChange); - - TriList.SetSigFalseAction(UIBoolJoin.CallStopSharingPress, () => _CurrentRoom.RunRouteAction("codecOsd")); - - (Parent as EssentialsPanelMainInterfaceDriver).HeaderDriver.SetupHeaderButtons(this, CurrentRoom); - } - else - { - // Clear sigs that need to be - TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = "Select a room"; - } - } - - /// - /// - /// - /// - /// - void CurrentRoom_InCallFeedback_OutputChange(object sender, EventArgs e) - { - var inCall = CurrentRoom.InCallFeedback.BoolValue; - if (inCall) - { - // Check if transitioning to in call - and non-sharable source is in use - if (CurrentRoom.CurrentSourceInfo != null && CurrentRoom.CurrentSourceInfo.DisableCodecSharing) - { - Debug.Console(1, CurrentRoom, "Transitioning to in-call, cancelling non-sharable source"); - CurrentRoom.RunRouteAction("codecOsd"); - } - } - - SetupSourceList(); - } - - /// - /// - /// - void SetupSourceList() - { - - var inCall = CurrentRoom.InCallFeedback.BoolValue; - var config = ConfigReader.ConfigObject.SourceLists; - if (config.ContainsKey(_CurrentRoom.SourceListKey)) - { - var srcList = config[_CurrentRoom.SourceListKey].OrderBy(kv => kv.Value.Order); - - // Setup sources list - SourceStagingSrl.Clear(); - uint i = 1; // counter for UI list - foreach (var kvp in srcList) - { - var srcConfig = kvp.Value; - Debug.Console(1, "**** {0}, {1}, {2}, {3}, {4}", srcConfig.PreferredName, srcConfig.IncludeInSourceList, - srcConfig.DisableCodecSharing, inCall, this.CurrentMode); - // Skip sources marked as not included, and filter list of non-sharable sources when in call - // or on share screen - if (!srcConfig.IncludeInSourceList || (inCall && srcConfig.DisableCodecSharing) - || this.CurrentMode == UiDisplayMode.Call && srcConfig.DisableCodecSharing) - { - Debug.Console(1, "Skipping {0}", srcConfig.PreferredName); - continue; - } - - var routeKey = kvp.Key; - var item = new SubpageReferenceListSourceItem(i++, SourceStagingSrl, srcConfig, - b => { if (!b) UiSelectSource(routeKey); }); - SourceStagingSrl.AddItem(item); // add to the SRL - item.RegisterForSourceChange(_CurrentRoom); - } - SourceStagingSrl.Count = (ushort)(i - 1); - } - - } - - /// - /// If the schedule changes, this event will fire - /// - /// - /// - void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) - { - RefreshMeetingsList(); - } - - /// - /// Updates the current shared source label on the call list when the source changes - /// - /// - /// - /// - void CurrentRoom_CurrentSingleSourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) - { - if (_CurrentRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && _CurrentRoom.CurrentSourceInfo != null) - TriList.StringInput[UIStringJoin.CallSharedSourceNameText].StringValue = _CurrentRoom.CurrentSourceInfo.PreferredName; - } - - /// - /// Fires when the sharing source feedback of the codec changes - /// - /// - /// - void SharingContentIsOnFeedback_OutputChange(object sender, EventArgs e) - { - SetActiveCallListSharingContentStatus(); - } - - /// - /// Sets the values for the text and button visibilty for the active call list source sharing info - /// - void SetActiveCallListSharingContentStatus() - { - CallSharingInfoVisibleFeedback.FireUpdate(); - - string callListSharedSourceLabel; - - if (_CurrentRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && _CurrentRoom.CurrentSourceInfo != null) - { - Debug.Console(0, "*#* CurrentRoom.CurrentSourceInfo = {0}", - _CurrentRoom.CurrentSourceInfo != null ? _CurrentRoom.CurrentSourceInfo.SourceKey : "Nada!"); - callListSharedSourceLabel = _CurrentRoom.CurrentSourceInfo.PreferredName; - } - else - callListSharedSourceLabel = "None"; - - TriList.StringInput[UIStringJoin.CallSharedSourceNameText].StringValue = callListSharedSourceLabel; - } - - /// - /// - /// - void RefreshMeetingsList() - { - // See if this is helpful or if the callback response in the codec class maybe doesn't come it time? - // Let's build list from event - // CurrentRoom.ScheduleSource.GetSchedule(); - - TriList.SetString(UIStringJoin.MeetingsOrContactMethodListIcon, "Calendar"); - TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Today's Meetings"); - - ushort i = 0; - foreach (var m in CurrentRoom.ScheduleSource.CodecSchedule.Meetings) - { - i++; - MeetingOrContactMethodModalSrl.StringInputSig(i, 1).StringValue = m.StartTime.ToShortTimeString(); - MeetingOrContactMethodModalSrl.StringInputSig(i, 2).StringValue = m.EndTime.ToShortTimeString(); - MeetingOrContactMethodModalSrl.StringInputSig(i, 3).StringValue = m.Title; - MeetingOrContactMethodModalSrl.StringInputSig(i, 4).StringValue = string.Format("
{0}",m.Organizer); - MeetingOrContactMethodModalSrl.StringInputSig(i, 5).StringValue = "Join"; - MeetingOrContactMethodModalSrl.BoolInputSig(i, 2).BoolValue = m.Joinable; - var mm = m; // lambda scope - MeetingOrContactMethodModalSrl.GetBoolFeedbackSig(i, 1).SetSigFalseAction(() => - { - PopupInterlock.Hide(); - ActivityCallButtonPressed(); - var d = CurrentRoom.ScheduleSource as VideoCodecBase; - if (d != null) - RoomOnAndDialMeeting(mm); - }); - } - MeetingOrContactMethodModalSrl.Count = i; - - if (i == 0) // Show item indicating no meetings are booked for rest of day - { - MeetingOrContactMethodModalSrl.Count = 1; - - MeetingOrContactMethodModalSrl.StringInputSig(1, 1).StringValue = string.Empty; - MeetingOrContactMethodModalSrl.StringInputSig(1, 2).StringValue = string.Empty; - MeetingOrContactMethodModalSrl.StringInputSig(1, 3).StringValue = "No Meetings are booked for the remainder of the day."; - MeetingOrContactMethodModalSrl.StringInputSig(1, 4).StringValue = string.Empty; - MeetingOrContactMethodModalSrl.StringInputSig(1, 5).StringValue = string.Empty; - } - } - - /// - /// For room on/off changes - /// - void CurrentRoom_OnFeedback_OutputChange(object sender, EventArgs e) - { - CurrentRoom_SyncOnFeedback(); - } - - /// - /// - /// - void CurrentRoom_SyncOnFeedback() - { - var value = _CurrentRoom.OnFeedback.BoolValue; - TriList.BooleanInput[UIBoolJoin.RoomIsOn].BoolValue = value; - - TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = !value; - - if (value) //ON - { - SetupActivityFooterWhenRoomOn(); - TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.VolumeDualMute1Visible].BoolValue = true; - - } - else - { - CurrentMode = UiDisplayMode.Start; - if (VCDriver.IsVisible) - VCDriver.Hide(); - SetupActivityFooterWhenRoomOff(); - ShowLogo(); - SetActivityFooterFeedbacks(); - TriList.BooleanInput[UIBoolJoin.VolumeDualMute1Visible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.SourceStagingBarVisible].BoolValue = false; - // Clear this so that the pesky meeting warning can resurface every minute when off - LastMeetingDismissedId = null; - } - } - - /// - /// - /// - void CurrentRoom_IsWarmingFeedback_OutputChange(object sender, EventArgs e) - { - if (CurrentRoom.IsWarmingUpFeedback.BoolValue) - { - ShowNotificationRibbon("Room is powering on. Please wait...", 0); - } - else - { - ShowNotificationRibbon("Room is powered on. Welcome.", 2000); - } - } - - /// - /// - /// - /// - /// - void CurrentRoom_IsCoolingDownFeedback_OutputChange(object sender, EventArgs e) - { - if (CurrentRoom.IsCoolingDownFeedback.BoolValue) - { - ShowNotificationRibbon("Room is powering off. Please wait.", 0); - } - else - { - HideNotificationRibbon(); - } - } - - /// - /// Hides source for provided source info - /// - /// - void DisconnectSource(SourceListItem previousInfo) - { - if (previousInfo == null) return; - - // Hide whatever is showing - if (IsVisible) - { - if (CurrentSourcePageManager != null) - { - CurrentSourcePageManager.Hide(); - CurrentSourcePageManager = null; - } - } - - if (previousInfo == null) return; - var previousDev = previousInfo.SourceDevice; - - // device type interfaces - if (previousDev is ISetTopBoxControls) - (previousDev as ISetTopBoxControls).UnlinkButtons(TriList); - // common interfaces - if (previousDev is IChannel) - (previousDev as IChannel).UnlinkButtons(TriList); - if (previousDev is IColor) - (previousDev as IColor).UnlinkButtons(TriList); - if (previousDev is IDPad) - (previousDev as IDPad).UnlinkButtons(TriList); - if (previousDev is IDvr) - (previousDev as IDvr).UnlinkButtons(TriList); - if (previousDev is INumericKeypad) - (previousDev as INumericKeypad).UnlinkButtons(TriList); - if (previousDev is IPower) - (previousDev as IPower).UnlinkButtons(TriList); - if (previousDev is ITransport) - (previousDev as ITransport).UnlinkButtons(TriList); - } - - /// - /// Refreshes and shows the room's current source - /// - void RefreshSourceInfo() - { - var routeInfo = CurrentRoom.CurrentSourceInfo; - // This will show off popup too - if (this.IsVisible && !VCDriver.IsVisible) - ShowCurrentSource(); - - if (routeInfo == null)// || !CurrentRoom.OnFeedback.BoolValue) - { - // Check for power off and insert "Room is off" - TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "Room is off"; - TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Power"; - this.Hide(); - Parent.Show(); - return; - } - else if (routeInfo != null) - { - TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = routeInfo.PreferredName; - TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = routeInfo.Icon; // defaults to "blank" - } - else // This never gets hit???!!! - { - TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "---"; - TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Blank"; - } - - // Connect controls - if (routeInfo.SourceDevice != null) - ConnectControlDeviceMethods(routeInfo.SourceDevice); - } - - /// - /// Attach the source to the buttons and things - /// - void ConnectControlDeviceMethods(Device dev) - { - if (dev is ISetTopBoxControls) - (dev as ISetTopBoxControls).LinkButtons(TriList); - if (dev is IChannel) - (dev as IChannel).LinkButtons(TriList); - if (dev is IColor) - (dev as IColor).LinkButtons(TriList); - if (dev is IDPad) - (dev as IDPad).LinkButtons(TriList); - if (dev is IDvr) - (dev as IDvr).LinkButtons(TriList); - if (dev is INumericKeypad) - (dev as INumericKeypad).LinkButtons(TriList); - if (dev is IPower) - (dev as IPower).LinkButtons(TriList); - if (dev is ITransport) - (dev as ITransport).LinkButtons(TriList); - } - - /// - /// Detaches the buttons and feedback from the room's current audio device - /// - void ClearAudioDeviceConnections() - { - TriList.ClearBoolSigAction(UIBoolJoin.VolumeUpPress); - TriList.ClearBoolSigAction(UIBoolJoin.VolumeDownPress); - TriList.ClearBoolSigAction(UIBoolJoin.Volume1ProgramMutePressAndFB); - - var fDev = CurrentRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; - if (fDev != null) - { - TriList.ClearUShortSigAction(UIUshortJoin.VolumeSlider1Value); - fDev.VolumeLevelFeedback.UnlinkInputSig( - TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); - } - } - - /// - /// Attaches the buttons and feedback to the room's current audio device - /// - void RefreshAudioDeviceConnections() - { - var dev = CurrentRoom.CurrentVolumeControls; - if (dev != null) // connect buttons - { - TriList.SetBoolSigAction(UIBoolJoin.VolumeUpPress, VolumeUpPress); - TriList.SetBoolSigAction(UIBoolJoin.VolumeDownPress, VolumeDownPress); - TriList.SetSigFalseAction(UIBoolJoin.Volume1ProgramMutePressAndFB, dev.MuteToggle); - } - - var fbDev = dev as IBasicVolumeWithFeedback; - if (fbDev == null) // this should catch both IBasicVolume and IBasicVolumeWithFeeback - TriList.UShortInput[UIUshortJoin.VolumeSlider1Value].UShortValue = 0; - else - { - // slider - TriList.SetUShortSigAction(UIUshortJoin.VolumeSlider1Value, fbDev.SetVolume); - // feedbacks - fbDev.MuteFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.Volume1ProgramMutePressAndFB]); - fbDev.VolumeLevelFeedback.LinkInputSig( - TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); - } - } - - /// - /// Handler for when the room's volume control device changes - /// - void CurrentRoom_CurrentAudioDeviceChange(object sender, VolumeDeviceChangeEventArgs args) - { - if (args.Type == ChangeType.WillChange) - ClearAudioDeviceConnections(); - else // did change - RefreshAudioDeviceConnections(); - } - - /// - /// Handles source change - /// - void CurrentRoom_SourceInfoChange(EssentialsRoomBase room, - SourceListItem info, ChangeType change) - { - if (change == ChangeType.WillChange) - DisconnectSource(info); - else - RefreshSourceInfo(); - } - } - - /// - /// For hanging off various common AV things that child drivers might need from a parent AV driver - /// - public interface IAVDriver - { - JoinedSigInterlock PopupInterlock { get; } - void ShowNotificationRibbon(string message, int timeout); - void HideNotificationRibbon(); - void ShowTech(); - } - - /// - /// For hanging off various common VC things that child drivers might need from a parent AV driver - /// - public interface IAVWithVCDriver : IAVDriver - { - EssentialsHuddleVtc1Room CurrentRoom { get; } - - PepperDash.Essentials.Core.Touchpanels.Keyboards.HabaneroKeyboardController Keyboard { get; } - /// - /// Exposes the ability to switch into call mode - /// - void ActivityCallButtonPressed(); - /// - /// Allows the codec to trigger the main UI to clear up if call is coming in. - /// - void PrepareForCodecIncomingCall(); - - SubpageReferenceList MeetingOrContactMethodModalSrl { get; } - } -} +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.SmartObjects; +using PepperDash.Essentials.Core.PageManagers; +using PepperDash.Essentials.Room.Config; +using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.VideoCodec; + +namespace PepperDash.Essentials +{ + /// + /// + /// + public class EssentialsHuddleVtc1PanelAvFunctionsDriver : PanelDriverBase, IAVWithVCDriver + { + CrestronTouchpanelPropertiesConfig Config; + + public enum UiDisplayMode + { + Presentation, AudioSetup, Call, Start + } + + /// + /// Whether volume ramping from this panel will show the volume + /// gauge popup. + /// + public bool ShowVolumeGauge { get; set; } + + /// + /// + /// + public uint PowerOffTimeout { get; set; } + + /// + /// + /// + public string DefaultRoomKey { get; set; } + + + /// + /// + /// + public EssentialsHuddleVtc1Room CurrentRoom + { + get { return _CurrentRoom; } + set + { + SetCurrentRoom(value); + } + } + EssentialsHuddleVtc1Room _CurrentRoom; + + /// + /// For hitting feedbacks + /// + BoolInputSig CallButtonSig; + BoolInputSig ShareButtonSig; + BoolInputSig EndMeetingButtonSig; + + BoolFeedback CallSharingInfoVisibleFeedback; + + /// + /// The parent driver for this + /// + PanelDriverBase Parent; + + /// + /// All children attached to this driver. For hiding and showing as a group. + /// + List ChildDrivers = new List(); + + List CurrentDisplayModeSigsInUse = new List(); + + //// Important smart objects + + /// + /// Smart Object 3200 + /// + SubpageReferenceList SourceStagingSrl; + + /// + /// Smart Object 15022 + /// + SubpageReferenceList ActivityFooterSrl; + + /// + /// + /// + public SubpageReferenceList MeetingOrContactMethodModalSrl { get; set; } + + /// + /// The list of buttons on the header. Managed with visibility only + /// + //SmartObjectHeaderButtonList HeaderButtonsList; + + /// + /// The AV page mangagers that have been used, to keep them alive for later + /// + Dictionary PageManagers = new Dictionary(); + + /// + /// Current page manager running for a source + /// + PageManager CurrentSourcePageManager; + + /// + /// Will auto-timeout a power off + /// + CTimer PowerOffTimer; + + /// + /// + /// + ModalDialog PowerDownModal; + + /// + /// + /// + //ModalDialog WarmingCoolingModal; + + /// + /// Represents + /// + public JoinedSigInterlock PopupInterlock { get; private set; } + + /// + /// Interlock for various source, camera, call control bars. The bar above the activity footer. This is also + /// used to show start page + /// + JoinedSigInterlock StagingBarInterlock; + + /// + /// Interlocks the various call-related subpages + /// + JoinedSigInterlock CallPagesInterlock; + + /// + /// The Video codec driver + /// + PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver VCDriver; + + /// + /// The driver for the tech page. Lazy getter for memory usage + /// + PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver TechDriver + { + get + { + if (_TechDriver == null) + _TechDriver = new PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver(TriList, CurrentRoom.PropertiesConfig.Tech); + return _TechDriver; + } + } + PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver _TechDriver; + + /// + /// Controls timeout of notification ribbon timer + /// + CTimer RibbonTimer; + + /// + /// The keyboard + /// + public PepperDash.Essentials.Core.Touchpanels.Keyboards.HabaneroKeyboardController Keyboard { get; private set; } + + /// + /// The mode showing. Presentation or call. + /// + UiDisplayMode CurrentMode = UiDisplayMode.Start; + + CTimer NextMeetingTimer; + + /// + /// Tracks the last meeting that was cancelled + /// + string LastMeetingDismissedId; + + /// + /// Constructor + /// + public EssentialsHuddleVtc1PanelAvFunctionsDriver(PanelDriverBase parent, CrestronTouchpanelPropertiesConfig config) + : base(parent.TriList) + { + Config = config; + Parent = parent; + + PopupInterlock = new JoinedSigInterlock(TriList); + StagingBarInterlock = new JoinedSigInterlock(TriList); + CallPagesInterlock = new JoinedSigInterlock(TriList); + + SourceStagingSrl = new SubpageReferenceList(TriList, UISmartObjectJoin.SourceStagingSRL, 3, 3, 3); + + ActivityFooterSrl = new SubpageReferenceList(TriList, UISmartObjectJoin.ActivityFooterSRL, 3, 3, 3); + CallButtonSig = ActivityFooterSrl.BoolInputSig(2, 1); + ShareButtonSig = ActivityFooterSrl.BoolInputSig(1, 1); + EndMeetingButtonSig = ActivityFooterSrl.BoolInputSig(3, 1); + + MeetingOrContactMethodModalSrl = new SubpageReferenceList(TriList, UISmartObjectJoin.MeetingListSRL, 3, 3, 5); + + + // buttons are added in SetCurrentRoom + //HeaderButtonsList = new SmartObjectHeaderButtonList(TriList.SmartObjects[UISmartObjectJoin.HeaderButtonList]); + + SetupActivityFooterWhenRoomOff(); + + ShowVolumeGauge = true; + Keyboard = new PepperDash.Essentials.Core.Touchpanels.Keyboards.HabaneroKeyboardController(TriList); + } + + /// + /// Add a video codec driver to this + /// + /// + public void SetVideoCodecDriver(PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver vcd) + { + VCDriver = vcd; + } + + /// + /// + /// + public override void Show() + { + if (CurrentRoom == null) + { + Debug.Console(1, "ERROR: AVUIFunctionsDriver, Cannot show. No room assigned"); + return; + } + + var roomConf = CurrentRoom.PropertiesConfig; + + if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Habanero) + { + TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () => + PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderPageVisible)); + } + else if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose) + { + // room name on join 1, concat phone and sip on join 2, no button method + //var addr = roomConf.Addresses; + //if (addr == null) // protect from missing values by using default empties + // addr = new EssentialsRoomAddressPropertiesConfig(); + //// empty string when either missing, pipe when both showing + //TriList.SetString(UIStringJoin.RoomAddressPipeText, + // (string.IsNullOrEmpty(addr.PhoneNumber.Trim()) + // || string.IsNullOrEmpty(addr.SipAddress.Trim())) ? "" : " | "); + //TriList.SetString(UIStringJoin.RoomPhoneText, addr.PhoneNumber); + //TriList.SetString(UIStringJoin.RoomSipText, addr.SipAddress); + } + + TriList.SetBool(UIBoolJoin.DateAndTimeVisible, Config.ShowDate && Config.ShowTime); + TriList.SetBool(UIBoolJoin.DateOnlyVisible, Config.ShowDate && !Config.ShowTime); + TriList.SetBool(UIBoolJoin.TimeOnlyVisible, !Config.ShowDate && Config.ShowTime); + + TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true); + + TriList.SetBool(UIBoolJoin.ActivityFooterVisible, true); + + // Privacy mute button + TriList.SetSigFalseAction(UIBoolJoin.Volume1SpeechMutePressAndFB, CurrentRoom.PrivacyModeToggle); + CurrentRoom.PrivacyModeIsOnFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.Volume1SpeechMutePressAndFB]); + + // Default to showing rooms/sources now. + if (CurrentRoom.OnFeedback.BoolValue) + { + TriList.SetBool(UIBoolJoin.TapToBeginVisible, false); + SetupActivityFooterWhenRoomOn(); + } + else + { + TriList.SetBool(UIBoolJoin.StartPageVisible, true); + TriList.SetBool(UIBoolJoin.TapToBeginVisible, true); + SetupActivityFooterWhenRoomOff(); + } + ShowCurrentDisplayModeSigsInUse(); + + // *** Header Buttons *** + + // Generic "close" button for popup modals + TriList.SetSigFalseAction(UIBoolJoin.InterlockedModalClosePress, PopupInterlock.HideAndClear); + + // Volume related things + TriList.SetSigFalseAction(UIBoolJoin.VolumeDefaultPress, () => CurrentRoom.SetDefaultLevels()); + TriList.SetString(UIStringJoin.AdvancedVolumeSlider1Text, "Room"); + + //if (TriList is CrestronApp) + // TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = false; + //else + // TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = true; + + // power-related functions + // Note: some of these are not directly-related to the huddle space UI, but are held over + // in case + TriList.SetSigFalseAction(UIBoolJoin.ShowPowerOffPress, EndMeetingPress); + + TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () => + { + if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IPower) + (CurrentRoom.DefaultDisplay as IPower).PowerToggle(); + }); + + SetupNextMeetingTimer(); + + base.Show(); + } + + /// + /// Allows PopupInterlock to be toggled if the calls list is already visible, or if the codec is in a call + /// + public void ShowActiveCallsList() + { + TriList.SetBool(UIBoolJoin.CallEndAllConfirmVisible, true); + if(PopupInterlock.CurrentJoin == UIBoolJoin.HeaderActiveCallsListVisible) + PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HeaderActiveCallsListVisible); + else + { + if((CurrentRoom.ScheduleSource as VideoCodecBase).IsInCall) + PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HeaderActiveCallsListVisible); + } + } + + /// + /// + /// + void ShowLogo() + { + if (CurrentRoom.LogoUrl == null) + { + TriList.SetBool(UIBoolJoin.LogoDefaultVisible, true); + TriList.SetBool(UIBoolJoin.LogoUrlVisible, false); + } + else + { + TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false); + TriList.SetBool(UIBoolJoin.LogoUrlVisible, true); + TriList.SetString(UIStringJoin.LogoUrl, _CurrentRoom.LogoUrl); + } + } + + /// + /// + /// + void HideLogo() + { + TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false); + TriList.SetBool(UIBoolJoin.LogoUrlVisible, false); + } + + /// + /// + /// + public override void Hide() + { + HideAndClearCurrentDisplayModeSigsInUse(); + TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, false); + TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + if (NextMeetingTimer != null) + NextMeetingTimer.Stop(); + HideNextMeetingPopup(); + base.Hide(); + } + + /// + /// Reveals a message on the notification ribbon until cleared + /// + /// Text to display + /// Time in ms to display. 0 to keep on screen + public void ShowNotificationRibbon(string message, int timeout) + { + TriList.SetString(UIStringJoin.NotificationRibbonText, message); + TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, true); + if (timeout > 0) + { + if (RibbonTimer != null) + RibbonTimer.Stop(); + RibbonTimer = new CTimer(o => { + TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false); + RibbonTimer = null; + }, timeout); + } + } + + /// + /// Hides the notification ribbon + /// + public void HideNotificationRibbon() + { + TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false); + if (RibbonTimer != null) + { + RibbonTimer.Stop(); + RibbonTimer = null; + } + } + + void SetupNextMeetingTimer() + { + var ss = CurrentRoom.ScheduleSource; + if (ss != null) + { + NextMeetingTimer = new CTimer(o => ShowNextMeetingTimerCallback(), null, 0, 60000); + } + } + + /// + /// + /// + void ShowNextMeetingTimerCallback() + { + // Every 60 seconds, refresh the calendar + RefreshMeetingsList(); + // check meetings list for the closest, joinable meeting + var ss = CurrentRoom.ScheduleSource; + var meetings = ss.CodecSchedule.Meetings; + + if (meetings.Count > 0) + { + // If the room is off pester the user + // If the room is on, and the meeting is joinable + // and the LastMeetingDismissed != this meeting + + var lastMeetingDismissed = meetings.FirstOrDefault(m => m.Id == LastMeetingDismissedId); + Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*", + CurrentRoom.OnFeedback.BoolValue, + LastMeetingDismissedId, + lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToShortTimeString() : ""); + + var meeting = meetings.LastOrDefault(m => m.Joinable); + if (CurrentRoom.OnFeedback.BoolValue + && lastMeetingDismissed == meeting) + { + return; + } + + LastMeetingDismissedId = null; + // Clear the popup when we run out of meetings + if (meeting == null) + { + HideNextMeetingPopup(); + } + else + { + TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Upcoming meeting"); + TriList.SetString(UIStringJoin.NextMeetingStartTimeText, meeting.StartTime.ToShortTimeString()); + TriList.SetString(UIStringJoin.NextMeetingEndTimeText, meeting.EndTime.ToShortTimeString()); + TriList.SetString(UIStringJoin.NextMeetingTitleText, meeting.Title); + TriList.SetString(UIStringJoin.NextMeetingNameText, meeting.Organizer); + TriList.SetString(UIStringJoin.NextMeetingButtonLabel, "Join"); + TriList.SetSigFalseAction(UIBoolJoin.NextMeetingJoinPress, () => + { + HideNextMeetingPopup(); + PopupInterlock.Hide(); + RoomOnAndDialMeeting(meeting); + }); + TriList.SetString(UIStringJoin.NextMeetingSecondaryButtonLabel, "Show Schedule"); + TriList.SetSigFalseAction(UIBoolJoin.CalendarHeaderButtonPress, () => + { + HideNextMeetingPopup(); + //CalendarPress(); + RefreshMeetingsList(); + PopupInterlock.ShowInterlocked(UIBoolJoin.MeetingsOrContacMethodsListVisible); + }); + var indexOfNext = meetings.IndexOf(meeting) + 1; + + // indexOf = 3, 4 meetings : + if (indexOfNext < meetings.Count) + TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, + meetings[indexOfNext].StartTime.ToShortTimeString()); + else + TriList.SetString(UIStringJoin.NextMeetingFollowingMeetingText, "No more meetings today"); + + TriList.SetSigFalseAction(UIBoolJoin.NextMeetingModalClosePress, () => + { + // Mark the meeting to not re-harass the user + if(CurrentRoom.OnFeedback.BoolValue) + LastMeetingDismissedId = meeting.Id; + HideNextMeetingPopup(); + }); + + TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, true); + } + } + } + + /// + /// + /// + void HideNextMeetingPopup() + { + TriList.SetBool(UIBoolJoin.NextMeetingModalVisible, false); + + } + + /// + /// Calendar should only be visible when it's supposed to + /// + public void CalendarPress() + { + //RefreshMeetingsList(); // List should be up-to-date + PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.MeetingsOrContacMethodsListVisible); + } + + /// + /// Dials a meeting after turning on room (if necessary) + /// + void RoomOnAndDialMeeting(Meeting meeting) + { + Action dialAction = () => + { + var d = CurrentRoom.ScheduleSource as VideoCodecBase; + if (d != null) + { + d.Dial(meeting); + LastMeetingDismissedId = meeting.Id; // To prevent prompts for already-joined call + } + }; + if (CurrentRoom.OnFeedback.BoolValue) + dialAction(); + else + { + // Rig a one-time handler to catch when the room is warmed and then dial call + EventHandler oneTimeHandler = null; + oneTimeHandler = (o, a) => + { + if (!CurrentRoom.IsWarmingUpFeedback.BoolValue) + { + CurrentRoom.IsWarmingUpFeedback.OutputChange -= oneTimeHandler; + dialAction(); + } + }; + CurrentRoom.IsWarmingUpFeedback.OutputChange += oneTimeHandler; + ActivityCallButtonPressed(); + } + } + + /// + /// Reveals the tech page and puts away anything that's in the way. + /// + public void ShowTech() + { + PopupInterlock.HideAndClear(); + TechDriver.Show(); + } + + /// + /// When the room is off, set the footer SRL + /// + void SetupActivityFooterWhenRoomOff() + { + ActivityFooterSrl.Clear(); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 0, + b => { if (!b) ActivityShareButtonPressed(); })); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl, 3, + b => { if (!b) ActivityCallButtonPressed(); })); + ActivityFooterSrl.Count = 2; + TriList.SetUshort(UIUshortJoin.PresentationStagingCaretMode, 1); // right one slot + TriList.SetUshort(UIUshortJoin.CallStagingCaretMode, 5); // left one slot + } + + /// + /// Sets up the footer SRL for when the room is on + /// + void SetupActivityFooterWhenRoomOn() + { + ActivityFooterSrl.Clear(); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 0, + b => { if (!b) ActivityShareButtonPressed(); })); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl, 3, + b => { if (!b) ActivityCallButtonPressed(); })); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(3, ActivityFooterSrl, 4, + b => { if (!b) EndMeetingPress(); })); + ActivityFooterSrl.Count = 3; + TriList.SetUshort(UIUshortJoin.PresentationStagingCaretMode, 2); // center + TriList.SetUshort(UIUshortJoin.CallStagingCaretMode, 0); // left -2 + } + + /// + /// Single point call for setting the feedbacks on the activity buttons + /// + void SetActivityFooterFeedbacks() + { + CallButtonSig.BoolValue = CurrentMode == UiDisplayMode.Call + && CurrentRoom.ShutdownType == eShutdownType.None; + ShareButtonSig.BoolValue = CurrentMode == UiDisplayMode.Presentation + && CurrentRoom.ShutdownType == eShutdownType.None; + EndMeetingButtonSig.BoolValue = CurrentRoom.ShutdownType != eShutdownType.None; + } + + /// + /// + /// + public void ActivityCallButtonPressed() + { + if (VCDriver.IsVisible) + return; + HideLogo(); + HideNextMeetingPopup(); + TriList.SetBool(UIBoolJoin.StartPageVisible, false); + TriList.SetBool(UIBoolJoin.SourceStagingBarVisible, false); + TriList.SetBool(UIBoolJoin.SelectASourceVisible, false); + if (CurrentSourcePageManager != null) + CurrentSourcePageManager.Hide(); + PowerOnFromCall(); + CurrentMode = UiDisplayMode.Call; + SetActivityFooterFeedbacks(); + VCDriver.Show(); + } + + /// + /// Attached to activity list share button + /// + void ActivityShareButtonPressed() + { + SetupSourceList(); + if (VCDriver.IsVisible) + VCDriver.Hide(); + HideNextMeetingPopup(); + TriList.SetBool(UIBoolJoin.StartPageVisible, false); + TriList.SetBool(UIBoolJoin.CallStagingBarVisible, false); + TriList.SetBool(UIBoolJoin.SourceStagingBarVisible, true); + // Run default source when room is off and share is pressed + if (!CurrentRoom.OnFeedback.BoolValue) + { + if (!CurrentRoom.OnFeedback.BoolValue) + { + // If there's no default, show UI elements + if (!CurrentRoom.RunDefaultPresentRoute()) + TriList.SetBool(UIBoolJoin.SelectASourceVisible, true); + } + } + else // room is on show what's active or select a source if nothing is yet active + { + if(CurrentRoom.CurrentSourceInfo == null || CurrentRoom.CurrentSourceInfoKey == CurrentRoom.DefaultCodecRouteString) + TriList.SetBool(UIBoolJoin.SelectASourceVisible, true); + else if (CurrentSourcePageManager != null) + CurrentSourcePageManager.Show(); + } + CurrentMode = UiDisplayMode.Presentation; + SetupSourceList(); + SetActivityFooterFeedbacks(); + } + + /// + /// Powers up the system to the codec route, if not already on. + /// + void PowerOnFromCall() + { + if (!CurrentRoom.OnFeedback.BoolValue) + { + CurrentRoom.RunDefaultCallRoute(); + } + } + + /// + /// Shows all sigs that are in CurrentDisplayModeSigsInUse + /// + void ShowCurrentDisplayModeSigsInUse() + { + foreach (var sig in CurrentDisplayModeSigsInUse) + sig.BoolValue = true; + } + + /// + /// Hides all CurrentDisplayModeSigsInUse sigs and clears the array + /// + void HideAndClearCurrentDisplayModeSigsInUse() + { + foreach (var sig in CurrentDisplayModeSigsInUse) + sig.BoolValue = false; + CurrentDisplayModeSigsInUse.Clear(); + } + + + /// + /// Loads the appropriate Sigs into CurrentDisplayModeSigsInUse and shows them + /// + void ShowCurrentSource() + { + if (CurrentRoom.CurrentSourceInfo == null) + return; + + if (CurrentRoom.CurrentSourceInfo.SourceDevice == null) + { + TriList.SetBool(UIBoolJoin.SelectASourceVisible, true); + return; + } + + var uiDev = CurrentRoom.CurrentSourceInfo.SourceDevice as IUiDisplayInfo; + PageManager pm = null; + // If we need a page manager, get an appropriate one + if (uiDev != null) + { + TriList.SetBool(UIBoolJoin.SelectASourceVisible, false); + // Got an existing page manager, get it + if (PageManagers.ContainsKey(uiDev)) + pm = PageManagers[uiDev]; + // Otherwise make an apporiate one + else if (uiDev is ISetTopBoxControls) + pm = new SetTopBoxThreePanelPageManager(uiDev as ISetTopBoxControls, TriList); + else if (uiDev is IDiscPlayerControls) + pm = new DiscPlayerMediumPageManager(uiDev as IDiscPlayerControls, TriList); + else + pm = new DefaultPageManager(uiDev, TriList); + PageManagers[uiDev] = pm; + CurrentSourcePageManager = pm; + pm.Show(); + } + } + + /// + /// Called from button presses on source, where We can assume we want + /// to change to the proper screen. + /// + /// The key name of the route to run + void UiSelectSource(string key) + { + // Run the route and when it calls back, show the source + CurrentRoom.RunRouteAction(key, null); + } + + /// + /// + /// + public void EndMeetingPress() + { + if (!CurrentRoom.OnFeedback.BoolValue + || CurrentRoom.ShutdownPromptTimer.IsRunningFeedback.BoolValue) + return; + + CurrentRoom.StartShutdown(eShutdownType.Manual); + } + + /// + /// Puts away modals and things that might be up when call comes in + /// + public void PrepareForCodecIncomingCall() + { + if (PowerDownModal != null && PowerDownModal.ModalIsVisible) + PowerDownModal.CancelDialog(); + PopupInterlock.Hide(); + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_HasStarted(object sender, EventArgs e) + { + // Do we need to check where the UI is? No? + var timer = CurrentRoom.ShutdownPromptTimer; + SetActivityFooterFeedbacks(); + + if (CurrentRoom.ShutdownType == eShutdownType.Manual || CurrentRoom.ShutdownType == eShutdownType.Vacancy) + { + PowerDownModal = new ModalDialog(TriList); + var message = string.Format("Meeting will end in {0} seconds", CurrentRoom.ShutdownPromptSeconds); + + // Attach timer things to modal + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange += ShutdownPromptTimer_PercentFeedback_OutputChange; + + // respond to offs by cancelling dialog + var onFb = CurrentRoom.OnFeedback; + EventHandler offHandler = null; + offHandler = (o, a) => + { + if (!onFb.BoolValue) + { + PowerDownModal.HideDialog(); + SetActivityFooterFeedbacks(); + onFb.OutputChange -= offHandler; + } + }; + onFb.OutputChange += offHandler; + + PowerDownModal.PresentModalDialog(2, "End Meeting", "Power", message, "Cancel", "End Meeting Now", true, true, + but => + { + if (but != 2) // any button except for End cancels + timer.Cancel(); + else + timer.Finish(); + }); + } + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_HasFinished(object sender, EventArgs e) + { + SetActivityFooterFeedbacks(); + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange -= ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e) + { + if (PowerDownModal != null) + PowerDownModal.HideDialog(); + SetActivityFooterFeedbacks(); + + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; + } + + /// + /// Event handler for countdown timer on power off modal + /// + void ShutdownPromptTimer_TimeRemainingFeedback_OutputChange(object sender, EventArgs e) + { + + var message = string.Format("Meeting will end in {0} seconds", (sender as StringFeedback).StringValue); + TriList.StringInput[ModalDialog.MessageTextJoin].StringValue = message; + } + + /// + /// Event handler for percentage on power off countdown + /// + void ShutdownPromptTimer_PercentFeedback_OutputChange(object sender, EventArgs e) + { + var value = (ushort)((sender as IntFeedback).UShortValue * 65535 / 100); + TriList.UShortInput[ModalDialog.TimerGaugeJoin].UShortValue = value; + } + + /// + /// + /// + void CancelPowerOffTimer() + { + if (PowerOffTimer != null) + { + PowerOffTimer.Stop(); + PowerOffTimer = null; + } + } + + /// + /// + /// + /// + public void VolumeUpPress(bool state) + { + if (CurrentRoom.CurrentVolumeControls != null) + CurrentRoom.CurrentVolumeControls.VolumeUp(state); + } + + /// + /// + /// + /// + public void VolumeDownPress(bool state) + { + if (CurrentRoom.CurrentVolumeControls != null) + CurrentRoom.CurrentVolumeControls.VolumeDown(state); + } + + /// + /// Helper for property setter. Sets the panel to the given room, latching up all functionality + /// + void SetCurrentRoom(EssentialsHuddleVtc1Room room) + { + if (_CurrentRoom == room) return; + // Disconnect current (probably never called) + if (_CurrentRoom != null) + { + // Disconnect current room + _CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange; + ClearAudioDeviceConnections(); + _CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange; + DisconnectSource(_CurrentRoom.CurrentSourceInfo); + _CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted; + _CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished; + _CurrentRoom.ShutdownPromptTimer.WasCancelled -= ShutdownPromptTimer_WasCancelled; + + _CurrentRoom.OnFeedback.OutputChange -= CurrentRoom_OnFeedback_OutputChange; + _CurrentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange; + _CurrentRoom.IsCoolingDownFeedback.OutputChange -= CurrentRoom_IsCoolingDownFeedback_OutputChange; + _CurrentRoom.InCallFeedback.OutputChange -= CurrentRoom_InCallFeedback_OutputChange; + } + + _CurrentRoom = room; + + if (_CurrentRoom != null) + { + // get the source list config and set up the source list + + SetupSourceList(); + + // Name and logo + TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name; + ShowLogo(); + + // Shutdown timer + _CurrentRoom.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted; + _CurrentRoom.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished; + _CurrentRoom.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled; + + // Link up all the change events from the room + _CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange; + CurrentRoom_SyncOnFeedback(); + _CurrentRoom.IsWarmingUpFeedback.OutputChange += CurrentRoom_IsWarmingFeedback_OutputChange; + _CurrentRoom.IsCoolingDownFeedback.OutputChange += CurrentRoom_IsCoolingDownFeedback_OutputChange; + _CurrentRoom.InCallFeedback.OutputChange += CurrentRoom_InCallFeedback_OutputChange; + + + _CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange; + RefreshAudioDeviceConnections(); + _CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange; + RefreshSourceInfo(); + + (_CurrentRoom.VideoCodec as IHasScheduleAwareness).CodecSchedule.MeetingsListHasChanged += CodecSchedule_MeetingsListHasChanged; + + CallSharingInfoVisibleFeedback = new BoolFeedback(() => _CurrentRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue); + _CurrentRoom.VideoCodec.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange; + CallSharingInfoVisibleFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.CallSharedSourceInfoVisible]); + + SetActiveCallListSharingContentStatus(); + + if (_CurrentRoom != null) + _CurrentRoom.CurrentSingleSourceChange += new SourceInfoChangeHandler(CurrentRoom_CurrentSingleSourceChange); + + TriList.SetSigFalseAction(UIBoolJoin.CallStopSharingPress, () => _CurrentRoom.RunRouteAction("codecOsd")); + + (Parent as EssentialsPanelMainInterfaceDriver).HeaderDriver.SetupHeaderButtons(this, CurrentRoom); + } + else + { + // Clear sigs that need to be + TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = "Select a room"; + } + } + + /// + /// + /// + /// + /// + void CurrentRoom_InCallFeedback_OutputChange(object sender, EventArgs e) + { + var inCall = CurrentRoom.InCallFeedback.BoolValue; + if (inCall) + { + // Check if transitioning to in call - and non-sharable source is in use + if (CurrentRoom.CurrentSourceInfo != null && CurrentRoom.CurrentSourceInfo.DisableCodecSharing) + { + Debug.Console(1, CurrentRoom, "Transitioning to in-call, cancelling non-sharable source"); + CurrentRoom.RunRouteAction("codecOsd"); + } + } + + SetupSourceList(); + } + + /// + /// + /// + void SetupSourceList() + { + + var inCall = CurrentRoom.InCallFeedback.BoolValue; + var config = ConfigReader.ConfigObject.SourceLists; + if (config.ContainsKey(_CurrentRoom.SourceListKey)) + { + var srcList = config[_CurrentRoom.SourceListKey].OrderBy(kv => kv.Value.Order); + + // Setup sources list + SourceStagingSrl.Clear(); + uint i = 1; // counter for UI list + foreach (var kvp in srcList) + { + var srcConfig = kvp.Value; + Debug.Console(1, "**** {0}, {1}, {2}, {3}, {4}", srcConfig.PreferredName, srcConfig.IncludeInSourceList, + srcConfig.DisableCodecSharing, inCall, this.CurrentMode); + // Skip sources marked as not included, and filter list of non-sharable sources when in call + // or on share screen + if (!srcConfig.IncludeInSourceList || (inCall && srcConfig.DisableCodecSharing) + || this.CurrentMode == UiDisplayMode.Call && srcConfig.DisableCodecSharing) + { + Debug.Console(1, "Skipping {0}", srcConfig.PreferredName); + continue; + } + + var routeKey = kvp.Key; + var item = new SubpageReferenceListSourceItem(i++, SourceStagingSrl, srcConfig, + b => { if (!b) UiSelectSource(routeKey); }); + SourceStagingSrl.AddItem(item); // add to the SRL + item.RegisterForSourceChange(_CurrentRoom); + } + SourceStagingSrl.Count = (ushort)(i - 1); + } + + } + + /// + /// If the schedule changes, this event will fire + /// + /// + /// + void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) + { + RefreshMeetingsList(); + } + + /// + /// Updates the current shared source label on the call list when the source changes + /// + /// + /// + /// + void CurrentRoom_CurrentSingleSourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) + { + if (_CurrentRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && _CurrentRoom.CurrentSourceInfo != null) + TriList.StringInput[UIStringJoin.CallSharedSourceNameText].StringValue = _CurrentRoom.CurrentSourceInfo.PreferredName; + } + + /// + /// Fires when the sharing source feedback of the codec changes + /// + /// + /// + void SharingContentIsOnFeedback_OutputChange(object sender, EventArgs e) + { + SetActiveCallListSharingContentStatus(); + } + + /// + /// Sets the values for the text and button visibilty for the active call list source sharing info + /// + void SetActiveCallListSharingContentStatus() + { + CallSharingInfoVisibleFeedback.FireUpdate(); + + string callListSharedSourceLabel; + + if (_CurrentRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && _CurrentRoom.CurrentSourceInfo != null) + { + Debug.Console(0, "*#* CurrentRoom.CurrentSourceInfo = {0}", + _CurrentRoom.CurrentSourceInfo != null ? _CurrentRoom.CurrentSourceInfo.SourceKey : "Nada!"); + callListSharedSourceLabel = _CurrentRoom.CurrentSourceInfo.PreferredName; + } + else + callListSharedSourceLabel = "None"; + + TriList.StringInput[UIStringJoin.CallSharedSourceNameText].StringValue = callListSharedSourceLabel; + } + + /// + /// + /// + void RefreshMeetingsList() + { + // See if this is helpful or if the callback response in the codec class maybe doesn't come it time? + // Let's build list from event + // CurrentRoom.ScheduleSource.GetSchedule(); + + TriList.SetString(UIStringJoin.MeetingsOrContactMethodListIcon, "Calendar"); + TriList.SetString(UIStringJoin.MeetingsOrContactMethodListTitleText, "Today's Meetings"); + + ushort i = 0; + foreach (var m in CurrentRoom.ScheduleSource.CodecSchedule.Meetings) + { + i++; + MeetingOrContactMethodModalSrl.StringInputSig(i, 1).StringValue = m.StartTime.ToShortTimeString(); + MeetingOrContactMethodModalSrl.StringInputSig(i, 2).StringValue = m.EndTime.ToShortTimeString(); + MeetingOrContactMethodModalSrl.StringInputSig(i, 3).StringValue = m.Title; + MeetingOrContactMethodModalSrl.StringInputSig(i, 4).StringValue = string.Format("
{0}",m.Organizer); + MeetingOrContactMethodModalSrl.StringInputSig(i, 5).StringValue = "Join"; + MeetingOrContactMethodModalSrl.BoolInputSig(i, 2).BoolValue = m.Joinable; + var mm = m; // lambda scope + MeetingOrContactMethodModalSrl.GetBoolFeedbackSig(i, 1).SetSigFalseAction(() => + { + PopupInterlock.Hide(); + ActivityCallButtonPressed(); + var d = CurrentRoom.ScheduleSource as VideoCodecBase; + if (d != null) + RoomOnAndDialMeeting(mm); + }); + } + MeetingOrContactMethodModalSrl.Count = i; + + if (i == 0) // Show item indicating no meetings are booked for rest of day + { + MeetingOrContactMethodModalSrl.Count = 1; + + MeetingOrContactMethodModalSrl.StringInputSig(1, 1).StringValue = string.Empty; + MeetingOrContactMethodModalSrl.StringInputSig(1, 2).StringValue = string.Empty; + MeetingOrContactMethodModalSrl.StringInputSig(1, 3).StringValue = "No Meetings are booked for the remainder of the day."; + MeetingOrContactMethodModalSrl.StringInputSig(1, 4).StringValue = string.Empty; + MeetingOrContactMethodModalSrl.StringInputSig(1, 5).StringValue = string.Empty; + } + } + + /// + /// For room on/off changes + /// + void CurrentRoom_OnFeedback_OutputChange(object sender, EventArgs e) + { + CurrentRoom_SyncOnFeedback(); + } + + /// + /// + /// + void CurrentRoom_SyncOnFeedback() + { + var value = _CurrentRoom.OnFeedback.BoolValue; + TriList.BooleanInput[UIBoolJoin.RoomIsOn].BoolValue = value; + + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = !value; + + if (value) //ON + { + SetupActivityFooterWhenRoomOn(); + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.VolumeDualMute1Visible].BoolValue = true; + + } + else + { + CurrentMode = UiDisplayMode.Start; + if (VCDriver.IsVisible) + VCDriver.Hide(); + SetupActivityFooterWhenRoomOff(); + ShowLogo(); + SetActivityFooterFeedbacks(); + TriList.BooleanInput[UIBoolJoin.VolumeDualMute1Visible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.SourceStagingBarVisible].BoolValue = false; + // Clear this so that the pesky meeting warning can resurface every minute when off + LastMeetingDismissedId = null; + } + } + + /// + /// + /// + void CurrentRoom_IsWarmingFeedback_OutputChange(object sender, EventArgs e) + { + if (CurrentRoom.IsWarmingUpFeedback.BoolValue) + { + ShowNotificationRibbon("Room is powering on. Please wait...", 0); + } + else + { + ShowNotificationRibbon("Room is powered on. Welcome.", 2000); + } + } + + /// + /// + /// + /// + /// + void CurrentRoom_IsCoolingDownFeedback_OutputChange(object sender, EventArgs e) + { + if (CurrentRoom.IsCoolingDownFeedback.BoolValue) + { + ShowNotificationRibbon("Room is powering off. Please wait.", 0); + } + else + { + HideNotificationRibbon(); + } + } + + /// + /// Hides source for provided source info + /// + /// + void DisconnectSource(SourceListItem previousInfo) + { + if (previousInfo == null) return; + + // Hide whatever is showing + if (IsVisible) + { + if (CurrentSourcePageManager != null) + { + CurrentSourcePageManager.Hide(); + CurrentSourcePageManager = null; + } + } + + if (previousInfo == null) return; + var previousDev = previousInfo.SourceDevice; + + // device type interfaces + if (previousDev is ISetTopBoxControls) + (previousDev as ISetTopBoxControls).UnlinkButtons(TriList); + // common interfaces + if (previousDev is IChannel) + (previousDev as IChannel).UnlinkButtons(TriList); + if (previousDev is IColor) + (previousDev as IColor).UnlinkButtons(TriList); + if (previousDev is IDPad) + (previousDev as IDPad).UnlinkButtons(TriList); + if (previousDev is IDvr) + (previousDev as IDvr).UnlinkButtons(TriList); + if (previousDev is INumericKeypad) + (previousDev as INumericKeypad).UnlinkButtons(TriList); + if (previousDev is IPower) + (previousDev as IPower).UnlinkButtons(TriList); + if (previousDev is ITransport) + (previousDev as ITransport).UnlinkButtons(TriList); + } + + /// + /// Refreshes and shows the room's current source + /// + void RefreshSourceInfo() + { + var routeInfo = CurrentRoom.CurrentSourceInfo; + // This will show off popup too + if (this.IsVisible && !VCDriver.IsVisible) + ShowCurrentSource(); + + if (routeInfo == null)// || !CurrentRoom.OnFeedback.BoolValue) + { + // Check for power off and insert "Room is off" + TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "Room is off"; + TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Power"; + this.Hide(); + Parent.Show(); + return; + } + else if (routeInfo != null) + { + TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = routeInfo.PreferredName; + TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = routeInfo.Icon; // defaults to "blank" + } + else // This never gets hit???!!! + { + TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "---"; + TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Blank"; + } + + // Connect controls + if (routeInfo.SourceDevice != null) + ConnectControlDeviceMethods(routeInfo.SourceDevice); + } + + /// + /// Attach the source to the buttons and things + /// + void ConnectControlDeviceMethods(Device dev) + { + if (dev is ISetTopBoxControls) + (dev as ISetTopBoxControls).LinkButtons(TriList); + if (dev is IChannel) + (dev as IChannel).LinkButtons(TriList); + if (dev is IColor) + (dev as IColor).LinkButtons(TriList); + if (dev is IDPad) + (dev as IDPad).LinkButtons(TriList); + if (dev is IDvr) + (dev as IDvr).LinkButtons(TriList); + if (dev is INumericKeypad) + (dev as INumericKeypad).LinkButtons(TriList); + if (dev is IPower) + (dev as IPower).LinkButtons(TriList); + if (dev is ITransport) + (dev as ITransport).LinkButtons(TriList); + } + + /// + /// Detaches the buttons and feedback from the room's current audio device + /// + void ClearAudioDeviceConnections() + { + TriList.ClearBoolSigAction(UIBoolJoin.VolumeUpPress); + TriList.ClearBoolSigAction(UIBoolJoin.VolumeDownPress); + TriList.ClearBoolSigAction(UIBoolJoin.Volume1ProgramMutePressAndFB); + + var fDev = CurrentRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; + if (fDev != null) + { + TriList.ClearUShortSigAction(UIUshortJoin.VolumeSlider1Value); + fDev.VolumeLevelFeedback.UnlinkInputSig( + TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); + } + } + + /// + /// Attaches the buttons and feedback to the room's current audio device + /// + void RefreshAudioDeviceConnections() + { + var dev = CurrentRoom.CurrentVolumeControls; + if (dev != null) // connect buttons + { + TriList.SetBoolSigAction(UIBoolJoin.VolumeUpPress, VolumeUpPress); + TriList.SetBoolSigAction(UIBoolJoin.VolumeDownPress, VolumeDownPress); + TriList.SetSigFalseAction(UIBoolJoin.Volume1ProgramMutePressAndFB, dev.MuteToggle); + } + + var fbDev = dev as IBasicVolumeWithFeedback; + if (fbDev == null) // this should catch both IBasicVolume and IBasicVolumeWithFeeback + TriList.UShortInput[UIUshortJoin.VolumeSlider1Value].UShortValue = 0; + else + { + // slider + TriList.SetUShortSigAction(UIUshortJoin.VolumeSlider1Value, fbDev.SetVolume); + // feedbacks + fbDev.MuteFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.Volume1ProgramMutePressAndFB]); + fbDev.VolumeLevelFeedback.LinkInputSig( + TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); + } + } + + /// + /// Handler for when the room's volume control device changes + /// + void CurrentRoom_CurrentAudioDeviceChange(object sender, VolumeDeviceChangeEventArgs args) + { + if (args.Type == ChangeType.WillChange) + ClearAudioDeviceConnections(); + else // did change + RefreshAudioDeviceConnections(); + } + + /// + /// Handles source change + /// + void CurrentRoom_SourceInfoChange(EssentialsRoomBase room, + SourceListItem info, ChangeType change) + { + if (change == ChangeType.WillChange) + DisconnectSource(info); + else + RefreshSourceInfo(); + } + } + + /// + /// For hanging off various common AV things that child drivers might need from a parent AV driver + /// + public interface IAVDriver + { + JoinedSigInterlock PopupInterlock { get; } + void ShowNotificationRibbon(string message, int timeout); + void HideNotificationRibbon(); + void ShowTech(); + } + + /// + /// For hanging off various common VC things that child drivers might need from a parent AV driver + /// + public interface IAVWithVCDriver : IAVDriver + { + EssentialsHuddleVtc1Room CurrentRoom { get; } + + PepperDash.Essentials.Core.Touchpanels.Keyboards.HabaneroKeyboardController Keyboard { get; } + /// + /// Exposes the ability to switch into call mode + /// + void ActivityCallButtonPressed(); + /// + /// Allows the codec to trigger the main UI to clear up if call is coming in. + /// + void PrepareForCodecIncomingCall(); + + SubpageReferenceList MeetingOrContactMethodModalSrl { get; } + } +} diff --git a/Release Package/PepperDashEssentials.cpz b/Release Package/PepperDashEssentials.cpz index e0a109e4..e5e96c8f 100644 Binary files a/Release Package/PepperDashEssentials.cpz and b/Release Package/PepperDashEssentials.cpz differ diff --git a/Release Package/PepperDashEssentials.dll b/Release Package/PepperDashEssentials.dll index cf210480..5046c694 100644 Binary files a/Release Package/PepperDashEssentials.dll and b/Release Package/PepperDashEssentials.dll differ diff --git a/essentials-framework b/essentials-framework index d351b879..7422e08b 160000 --- a/essentials-framework +++ b/essentials-framework @@ -1 +1 @@ -Subproject commit d351b879c21418a7754d99041e0e33d954124335 +Subproject commit 7422e08b5d09d7156a4f68848e9f24c3382b77db