From f0b546f97df2a764f2d98e1e9e6176b2c3dcd7fd Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 10 Jul 2026 10:05:49 -0600 Subject: [PATCH] feat: add custom logo URL feedback for light and dark backgrounds --- .../MobileControlTouchpanelController.cs | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs index 55d298d6..d640f22e 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Linq; using System.Text.RegularExpressions; using Crestron.SimplSharp; @@ -41,6 +42,25 @@ namespace PepperDash.Essentials.Touchpanel private readonly StringFeedback McServerUrlFeedback; private readonly StringFeedback UserCodeFeedback; + private string _customLogoUrlLightBkgnd; + private string _customLogoUrlDarkBkgnd; + + /// + /// Gets the CustomLogoUrlLightBkgndFeedback. Reports the absolute URL of the room's custom logo + /// meant to be displayed on a light background (as configured on the room device via + /// , served from the program's own slot-specific + /// logo folder), or an empty string if none is configured. + /// + public StringFeedback CustomLogoUrlLightBkgndFeedback { get; private set; } + + /// + /// Gets the CustomLogoUrlDarkBkgndFeedback. Reports the absolute URL of the room's custom logo + /// meant to be displayed on a dark background (as configured on the room device via + /// , served from the program's own slot-specific + /// logo folder), or an empty string if none is configured. + /// + public StringFeedback CustomLogoUrlDarkBkgndFeedback { get; private set; } + private readonly BoolFeedback _appOpenFeedback; /// @@ -135,6 +155,8 @@ namespace PepperDash.Essentials.Touchpanel QrCodeUrlFeedback = new StringFeedback($"{Key}-qrCodeUrl", () => _bridge?.QrCodeUrl); McServerUrlFeedback = new StringFeedback($"{Key}-mcServerUrl", () => _bridge?.McServerUrl); UserCodeFeedback = new StringFeedback($"{Key}-userCode", () => _bridge?.UserCode); + CustomLogoUrlLightBkgndFeedback = new StringFeedback($"{Key}-customLogoUrlLightBkgnd", () => _customLogoUrlLightBkgnd); + CustomLogoUrlDarkBkgndFeedback = new StringFeedback($"{Key}-customLogoUrlDarkBkgnd", () => _customLogoUrlDarkBkgnd); _appOpenFeedback = new BoolFeedback($"{Key}-appOpen", () => { @@ -185,7 +207,7 @@ namespace PepperDash.Essentials.Touchpanel Feedbacks = new FeedbackCollection { - AppUrlFeedback, QrCodeUrlFeedback, McServerUrlFeedback, UserCodeFeedback + AppUrlFeedback, QrCodeUrlFeedback, McServerUrlFeedback, UserCodeFeedback, CustomLogoUrlLightBkgndFeedback, CustomLogoUrlDarkBkgndFeedback }; ZoomFeedbacks = new FeedbackCollection { @@ -413,6 +435,8 @@ namespace PepperDash.Essentials.Touchpanel QrCodeUrlFeedback.LinkInputSig(Panel.StringInput[2]); McServerUrlFeedback.LinkInputSig(Panel.StringInput[3]); UserCodeFeedback.LinkInputSig(Panel.StringInput[4]); + CustomLogoUrlLightBkgndFeedback.LinkInputSig(Panel.StringInput[5]); + CustomLogoUrlDarkBkgndFeedback.LinkInputSig(Panel.StringInput[6]); Panel.IpInformationChange -= Panel_IpInformationChange; Panel.IpInformationChange += Panel_IpInformationChange; @@ -438,6 +462,8 @@ namespace PepperDash.Essentials.Touchpanel Panel.StringInput[2].StringValue = QrCodeUrlFeedback.StringValue; Panel.StringInput[3].StringValue = McServerUrlFeedback.StringValue; Panel.StringInput[4].StringValue = UserCodeFeedback.StringValue; + Panel.StringInput[5].StringValue = CustomLogoUrlLightBkgndFeedback.StringValue; + Panel.StringInput[6].StringValue = CustomLogoUrlDarkBkgndFeedback.StringValue; if (Panel is TswXX70Base x70Panel) { @@ -568,10 +594,57 @@ namespace PepperDash.Essentials.Touchpanel { this.LogInformation("AppURL changed: {appURL}", _bridge.AppUrl); SetAppUrl(_bridge.AppUrl); + UpdateCustomLogoUrls(); UpdateFeedbacks(s, a); }; SetAppUrl(_bridge.AppUrl); + UpdateCustomLogoUrls(); + } + + /// + /// Resolves the room's configured custom logos (light and dark background variants, if any) into + /// absolute URLs served from this processor's own slot-specific logo folder, and updates + /// CustomLogoUrlLightBkgndFeedback / CustomLogoUrlDarkBkgndFeedback accordingly. + /// + private void UpdateCustomLogoUrls() + { + var room = DeviceManager.AllDevices.OfType() + .FirstOrDefault(r => r.Key == _config.DefaultRoomKey); + + _customLogoUrlLightBkgnd = ResolveLogoUrl(room?.LogoUrlLightBkgnd); + _customLogoUrlDarkBkgnd = ResolveLogoUrl(room?.LogoUrlDarkBkgnd); + + CustomLogoUrlLightBkgndFeedback.FireUpdate(); + CustomLogoUrlDarkBkgndFeedback.FireUpdate(); + } + + /// + /// Resolves a room-configured logo file path into an absolute URL served from this processor's own + /// slot-specific logo folder (e.g. http://{ip}:{port}/mc/app/logo/{filename}). Returns an empty + /// string if is null/empty, or the app URL can't be determined. + /// + private string ResolveLogoUrl(string customLogoPath) + { + if (string.IsNullOrEmpty(customLogoPath) || string.IsNullOrEmpty(_bridge?.AppUrl)) + { + return string.Empty; + } + + var originMatch = Regex.Match(_bridge.AppUrl, @"^(https?://[^/]+)"); + + if (!originMatch.Success) + { + this.LogWarning("Could not determine origin from AppUrl '{appUrl}', cannot build custom logo URL", _bridge.AppUrl); + return string.Empty; + } + + // Path.GetFileName strips any directory components, matching the server's own image + // request handler, which only ever resolves a bare filename within its logo folder. + var filename = Path.GetFileName(customLogoPath); + var logoUrl = $"{originMatch.Groups[1].Value}/mc/app/logo/{filename}"; + + return GetUrlWithCorrectIp(logoUrl); } ///