/// <summary> /// Fires OnPanelAvailable on the UI thread. /// </summary> /// <param name="host"></param> /// <param name="panel"></param> private async void FireOnPanelAvailable(IContentPanelHost host, IContentPanelBase panelBase) { await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () => { try { // First tell the post it has a host panelBase.OnHostAdded(host); // Then tell the host it has a panel. host.OnPanelAvailable(panelBase); } catch (Exception e) { App.BaconMan.MessageMan.DebugDia("FireOnPanelAvailable failed", e); App.BaconMan.TelemetryMan.ReportUnexpectedEvent(this, "FireOnPanelAvailableFailed", e); } }); }
/// <summary> /// Fires FireOnPanelStolen on the UI thread. /// </summary> /// <param name="host"></param> /// <param name="panel"></param> private async Task FireOnRemovePanel(IContentPanelHost host, IContentPanelBase panelBase) { await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () => { try { // Tell the panel the host is gone panelBase.OnHostRemoved(); // And remove the panel. host.OnRemovePanel(panelBase); } catch (Exception e) { App.BaconMan.MessageMan.DebugDia("FireOnRemovePanel failed", e); App.BaconMan.TelemetryMan.ReportUnexpectedEvent(this, "FireOnRemovePanelFailed", e); } }); }
/// <summary> /// When fired the source given should fall back to a web /// browser instead of a complex control. /// </summary> public async void FallbackToWebrowser(ContentPanelSource source) { IContentPanelHost hostToReport = null; IContentPanelBase panelToKill = null; // Fire on load complete so if someone else was waiting on us they will // move on. OnContentLoadComplete(source.Id); // Lock lock (m_currentPanelList) { // Make sure we have it. if (m_currentPanelList.ContainsKey(source.Id)) { // Grab the panel to kill and the host to tell. ContentListElement element = m_currentPanelList[source.Id]; hostToReport = element.Host; panelToKill = element.PanelBase; // Null the post and update our state element.PanelBase = null; element.State = ContentState.Unloaded; } else { return; } } // Remove the panel if (hostToReport != null && panelToKill != null) { await FireOnRemovePanel(hostToReport, panelToKill); } // Kill the panel if (panelToKill != null) { await FireOnDestroyContent(panelToKill); panelToKill = null; } ContentPanelSource sourceToCreate = null; bool isVisible = false; // Now lock again lock (m_currentPanelList) { // Make sure we still have it. if (m_currentPanelList.ContainsKey(source.Id)) { ContentListElement element = m_currentPanelList[source.Id]; if (element.State == ContentState.Unloaded) { // Grab the element again and set the new state. isVisible = element.IsVisible; element.Source.ForceWeb = true; sourceToCreate = element.Source; element.State = ContentState.PendingCreation; } else { // if we are not in the same state get out of here. return; } } else { return; } } if (sourceToCreate != null) { BeginLoadContent(sourceToCreate, isVisible); } }
/// <summary> /// Fires FireOnDestroyContnet on the UI thread. /// </summary> /// <param name="host"></param> /// <param name="panel"></param> private async Task FireOnDestroyContent(IContentPanelBase panelBase) { await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () => { try { panelBase.OnDestroyContent(); } catch (Exception e) { App.BaconMan.MessageMan.DebugDia("FireOnRemovePanel failed", e); App.BaconMan.TelemetryMan.ReportUnexpectedEvent(this, "FireOnRemovePanelFailed", e); } }); }
/// <summary> /// Called by hosts when they want to get a panel /// </summary> /// <param name="panelId"></param> public async void RegisterForPanel(IContentPanelHost host, string panelId) { // Indicates if we should fire content loading. IContentPanelHost fireContentLoadingHost = null; // Used to fire the on panel available event. IContentPanelBase returnPanelBase = null; // Used to hold a past host if there is one. IContentPanelHost pastHost = null; // Used to hold the host we will tell is unloaded. IContentPanelHost fireUnloadedHost = null; // Check to see if the panel exists lock (m_currentPanelList) { // We already have it if (m_currentPanelList.ContainsKey(panelId)) { ContentListElement element = m_currentPanelList[panelId]; if (element.Host == null) { // We don't have a host, add ourselves. element.Host = host; if (element.State == ContentState.Created) { // If the control is already created fire the on control available right now. returnPanelBase = element.PanelBase; } else if (element.State == ContentState.PendingCreation) { // If the content is being created tell the panel that. fireContentLoadingHost = element.Host; } else if (element.State == ContentState.Unloaded) { fireUnloadedHost = element.Host; } } else { // We already have a host, grab the host so we can kill it // but make sure to null it so the post doesn't load while we are killing it. pastHost = element.Host; element.Host = null; // If the control is already created remove it from the old host. if (element.State == ContentState.Created) { // If the control is already created fire the on control available right now. returnPanelBase = element.PanelBase; } } } else { // We don't have it, make an entry so when we get it // we will be called back if one is created. ContentListElement element = new ContentListElement() { Host = host, State = ContentState.NotAllowed }; m_currentPanelList.Add(panelId, element); } } // If we have a past host we are transferring. if (pastHost != null) { // If we have a panel already we need to remove it. if (returnPanelBase != null) { await FireOnRemovePanel(pastHost, returnPanelBase); } // Now that the old host is gone, register again. RegisterForPanel(host, panelId); return; } // Out of lock, fire the event if we have a panel if (returnPanelBase != null) { FireOnPanelAvailable(host, returnPanelBase); } // Or if we have content loading. if (fireContentLoadingHost != null) { FireOnContentPreloading(fireContentLoadingHost); } // Or if we have unloaded content. if (fireUnloadedHost != null) { FireOnPanelUnloaded(fireUnloadedHost); } }
/// <summary> /// Fired when the current panel should be cleared. /// </summary> /// <param name="panel"></param> public void OnRemovePanel(IContentPanelBase panelBase) { lock(this) { // Release the panel m_currentPanelBase = null; } // Clear out the UI ui_contentRoot.Children.Clear(); // Set loading. ToggleProgress(true, false); }
/// <summary> /// Called when we have a panel. /// </summary> /// <param name="panel"></param> public void OnPanelAvailable(IContentPanelBase panelBase) { lock(this) { // Capture the panel m_currentPanelBase = panelBase; } // Setup loading. SetupLoading(); // Setup error text SetupGenericMessage(); // Setup NSFW SetupNsfwBlock(); // Add the panel to the UI. UserControl userControl = (UserControl)panelBase.Panel; ui_contentRoot.Children.Add(userControl); }
/// <summary> /// If the content is allowed it will be unloaded. It will remain in this state until /// a panel that wasn't it becomes visible. /// </summary> public async void UnloadContent(string sourceId) { string idToCallLoadCompleteOn = null; IContentPanelHost hostToTakeFrom = null; IContentPanelBase panelToDestory = null; // Lock the list. lock (m_currentPanelList) { // Make sure we have the id if (!m_currentPanelList.ContainsKey(sourceId)) { return; } // Get the element. ContentListElement element = m_currentPanelList[sourceId]; // Make sure we have something to do here. if (element.State == ContentState.NotAllowed || element.State == ContentState.Unloaded) { return; } if (element.State == ContentState.PendingCreation) { // The object is either being created or delay loaded. If we set the status to // unloaded this will kill the object when created. element.State = ContentState.Unloaded; // Make sure it isn't in the delay load list m_delayLoadQueue.Remove(element.Source); // Grab the id so we can call load complete on the id. // This will ensure if this is the post we are waiting on // the delay load will move on. idToCallLoadCompleteOn = element.Source.Id; } else { // We are created, grab the panel panelToDestory = element.PanelBase; element.PanelBase = null; // Set our state to unloaded. element.State = ContentState.Unloaded; // If we have a host we need to remove it from the host. It is safe to steal // the panel and host from the list because this panel will not be reset into // the UI until it is created again (which won't be this panel) if (element.Host != null) { hostToTakeFrom = element.Host; } } } // If we have an id call on load complete. This will cause delay load // to move on if this was the elemet it was waiting on. if (idToCallLoadCompleteOn != null) { OnContentLoadComplete(idToCallLoadCompleteOn); } // If we have a source and a panel, take it from the host. if (hostToTakeFrom != null && panelToDestory != null) { await FireOnRemovePanel(hostToTakeFrom, panelToDestory); // #todo tell the host it was unloaded so they can put up UI. } // If we have a panel destroy it. if (panelToDestory != null) { await FireOnDestroyContent(panelToDestory); } }
public async void UnRegisterForPanel(IContentPanelHost host, string panelId) { // Fist we need to see if there was a panel. IContentPanelBase removePanelBase = null; lock (m_currentPanelList) { // Make sure we have an entry. if (!m_currentPanelList.ContainsKey(panelId)) { return; } ContentListElement element = m_currentPanelList[panelId]; // Important! Make sure this host is the correct host for the panel! // This can happen if two hosts register for the same id, but the newer will // replace the older one. But we don't want the older to unregister and kill // the entry for the newer host. // The host can also be null if we are in the process of switching. if (element.Host == null || !element.Host.Id.Equals(host.Id)) { // Try to find the panel in our back stack. IContentPanelHost removeStackHost = null; foreach (IContentPanelHost stackHost in element.PastHosts) { if (stackHost.Id.Equals(host.Id)) { removeStackHost = stackHost; break; } } // If found remove it, if it is in this stack it isn't registered anywhere. if (removeStackHost != null) { element.PastHosts.Remove(removeStackHost); } else { // This is odd, report it. App.BaconMan.MessageMan.DebugDia("panel removed that wasn't active or in the panel stack"); if (Debugger.IsAttached) { Debugger.Break(); } } // Get out of here. return; } removePanelBase = m_currentPanelList[panelId].PanelBase; } // If we got a panel back clear it out if (removePanelBase != null) { await FireOnRemovePanel(host, removePanelBase); } IContentPanelHost restoreHost = null; // Now actually clear the host lock (m_currentPanelList) { // Make sure we have an entry. if (!m_currentPanelList.ContainsKey(panelId)) { return; } // Remove the current host. ContentListElement element = m_currentPanelList[panelId]; element.Host = null; // If we have a past host restore it. if (element.PastHosts.Count > 0) { // Get the host restoreHost = element.PastHosts[0]; element.PastHosts.RemoveAt(0); } // If we the state isn't allowed and we don't have a host to restore // delete this entry because no one wants it. if (element.State == ContentState.NotAllowed && restoreHost == null) { m_currentPanelList.Remove(panelId); } } // If we have a panel to restore call register on it. if (restoreHost != null) { RegisterForPanel(restoreHost, panelId); } }