/// <summary> /// Creates a new navigation data structure for a new media navigation step. /// </summary> /// <param name="parent">Parent navigation data, this navigation data is derived from.</param> /// <param name="navigationContextName">Name, which is used for the corresponding workflow navigation context.</param> /// <param name="currentWorkflowStateId">Id of the workflow state which corresponds to the new media navigation step.</param> /// <param name="parentWorkflowStateId">Id of the workflow state to which the workflow navigation should be reverted when /// another filter is choosen.</param> /// <param name="baseViewSpecification">View specification for the media items of the new media navigation step.</param> /// <param name="defaultScreen">Screen which should present the new navigation step by default.</param> /// <param name="availableScreens">Available set of screen descriptions which can present the new media navigation step.</param> /// <param name="currentSorting">Denotes the current sorting for the items to be shown. If this is set to <c>null</c>, /// default sorting will be applied.</param> public NavigationData(NavigationData parent, string navigationContextName, Guid parentWorkflowStateId, Guid currentWorkflowStateId, ViewSpecification baseViewSpecification, AbstractScreenData defaultScreen, ICollection<AbstractScreenData> availableScreens, Sorting.Sorting currentSorting) : this(parent, navigationContextName, parentWorkflowStateId, currentWorkflowStateId, baseViewSpecification, defaultScreen, availableScreens, currentSorting, false) { }
// If the suppressActions parameter is set to <c>true</c>, no actions will be built. Instead, they will be inherited from // the parent navigation step. That is used for subview navigation where the navigation step doesn't produce own // workflow actions. protected NavigationData(NavigationData parent, string navigationContextName, Guid parentWorkflowStateId, Guid currentWorkflowStateId, ViewSpecification baseViewSpecification, AbstractScreenData defaultScreen, ICollection<AbstractScreenData> availableScreens, Sorting.Sorting currentSorting, bool suppressActions) { _parent = parent; _navigationContextName = navigationContextName; _currentWorkflowStateId = currentWorkflowStateId; _baseWorkflowStateId = parentWorkflowStateId; _baseViewSpecification = baseViewSpecification; _currentScreenData = defaultScreen; _availableScreens = availableScreens ?? new List<AbstractScreenData>(); _currentSorting = currentSorting; if (suppressActions) _dynamicWorkflowActions = null; else BuildWorkflowActions(); }
/// <summary> /// Enters a new media navigation context by inheriting all currently available screens. This is used for /// presenting the contents of a media items or filter group, where the current menu should remain available. /// Only the currently visible screen can be exchanged to configure another presentation mode for the group to /// be stepped-in. /// </summary> /// <remarks> /// Actually, we mix two different concerns in this method: /// <list type="number"> /// <item>The setting that the new navigation context will be subordinated, i.e. it will be removed/exchanged by a filter action</item> /// <item>The setting that all menu actions will be adopted from the parent navigation context</item> /// </list> /// But in fact, filter actions are only used together with the concept that there exist two different kind of navigation contexts; /// autonomous contexts and subordinated contexts. /// If there are no filter actions present (like in the browse media navigation modes), the only difference between the methods /// <see cref="StackSubordinateNavigationContext"/> and <see cref="StackAutonomousNavigationContext"/> is the inheritance of the menu. /// </remarks> /// <param name="subViewSpecification">Specification for the sub view to be shown in the new navigation context.</param> /// <param name="visibleScreen">Screen which should be visible in the new navigation context.</param> /// <param name="navbarDisplayLabel">Display label to be shown in the navigation bar for the new navigation context.</param> /// <returns>Newly created navigation data.</returns> public NavigationData StackSubordinateNavigationContext(ViewSpecification subViewSpecification, AbstractScreenData visibleScreen, string navbarDisplayLabel) { WorkflowState newState = WorkflowState.CreateTransientState( "View: " + subViewSpecification.ViewDisplayName, subViewSpecification.ViewDisplayName, false, null, true, WorkflowType.Workflow); NavigationData newNavigationData = new NavigationData(this, subViewSpecification.ViewDisplayName, _baseWorkflowStateId, newState.StateId, subViewSpecification, visibleScreen, _availableScreens, _currentSorting, true); PushNewNavigationWorkflowState(newState, navbarDisplayLabel, newNavigationData); return newNavigationData; }
protected void BuildWorkflowActions() { _dynamicWorkflowActions = new List<WorkflowAction>(_availableScreens.Count); int ct = 0; foreach (AbstractScreenData screen in _availableScreens) { AbstractScreenData newScreen = screen; // Necessary to be used in closure WorkflowAction action = new MethodDelegateAction(Guid.NewGuid(), _navigationContextName + "->" + newScreen.MenuItemLabel, new Guid[] {_currentWorkflowStateId}, LocalizationHelper.CreateResourceString(newScreen.MenuItemLabel), () => { _currentScreenData.ReleaseScreenData(); _currentScreenData = newScreen; IWorkflowManager workflowManager = ServiceRegistration.Get<IWorkflowManager>(); // The last screen could have stepped into a deeper media navigation context when it had produced // sub views. So we first have to revert our workflow to the base workflow id before moving to the new screen. if (workflowManager.CurrentNavigationContext.WorkflowState.StateId == _baseWorkflowStateId) { // If we're already in the correct the state, update the screen manually _currentScreenData.CreateScreenData(this); SwitchToCurrentScreen(); } else // WF-Manager updates the screen for us workflowManager.NavigatePopToState(_baseWorkflowStateId, false); }) { DisplayCategory = Consts.FILTERS_WORKFLOW_CATEGORY, SortOrder = ct++.ToString(), // Sort in the order we have built up the filters }; _dynamicWorkflowActions.Add(action); } }
/// <summary> /// Gets a list of available screens ("filters") of the current <see cref="NavigationData"/>. This method can return either filtering screens that are showing /// results of predefined query (<paramref name="onlySearchScreens"/>=<c>false</c>), or custom search screens that allow user input for searching (<paramref name="onlySearchScreens"/>=<c>true</c>). /// </summary> /// <param name="onlySearchScreens"><c>true</c> to return only search screens.</param> /// <returns>List of workflow actions</returns> public IList<WorkflowAction> GetWorkflowActions(bool onlySearchScreens = false) { IList<WorkflowAction> actions = new List<WorkflowAction>(_availableScreens.Count); int ct = 0; foreach (AbstractScreenData screen in _availableScreens) { if (onlySearchScreens && !(screen is AbstractSearchScreenData)) continue; if (!onlySearchScreens && (screen is AbstractSearchScreenData)) continue; AbstractScreenData newScreen = screen; // Necessary to be used in closure WorkflowAction action = new MethodDelegateAction(Guid.NewGuid(), _navigationContextName + "->" + newScreen.MenuItemLabel, new Guid[] { _currentWorkflowStateId }, LocalizationHelper.CreateResourceString(newScreen.MenuItemLabel), () => { _currentScreenData.ReleaseScreenData(); _currentScreenData = newScreen; string parent = Parent == null ? _navigationContextName : Parent.CurrentScreenData.GetType().ToString(); // Do not save search screens as selection, they are only a "transient" state. if (!(newScreen is AbstractSearchScreenData)) SaveScreenHierarchy(parent, newScreen.GetType().ToString()); IWorkflowManager workflowManager = ServiceRegistration.Get<IWorkflowManager>(); // The last screen could have stepped into a deeper media navigation context when it had produced // sub views. So we first have to revert our workflow to the base workflow id before moving to the new screen. if (workflowManager.CurrentNavigationContext.WorkflowState.StateId == _baseWorkflowStateId) { // If we're already in the correct the state, update the screen manually _currentScreenData.CreateScreenData(this); SwitchToCurrentScreen(); } else // WF-Manager updates the screen for us workflowManager.NavigatePopToState(_baseWorkflowStateId, false); }) { DisplayCategory = Consts.FILTERS_WORKFLOW_CATEGORY, SortOrder = ct++.ToString(), // Sort in the order we have built up the filters }; actions.Add(action); } return actions; }
/// <summary> /// Enters a new media navigation context by inheriting all currently available screens. This is used for /// presenting the contents of a media items or filter group, where the current menu should remain available. /// Only the currently visible screen can be exchanged to configure another presentation mode for the group to /// be stepped-in. /// </summary> /// <remarks> /// Actually, we mix two different concerns in this method: /// <list type="number"> /// <item>The setting that the new navigation context will be subordinated, i.e. it will be removed/exchanged by a filter action</item> /// <item>The setting that all menu actions will be adopted from the parent navigation context</item> /// </list> /// But in fact, filter actions are only used together with the concept that there exist two different kind of navigation contexts; /// autonomous contexts and subordinated contexts. /// If there are no filter actions present (like in the browse media navigation modes), the only difference between the methods /// <see cref="StackSubordinateNavigationContext"/> and <see cref="StackAutonomousNavigationContext"/> is the inheritance of the menu. /// </remarks> /// <param name="subViewSpecification">Specification for the sub view to be shown in the new navigation context.</param> /// <param name="visibleScreen">Screen which should be visible in the new navigation context.</param> /// <param name="navbarDisplayLabel">Display label to be shown in the navigation bar for the new navigation context.</param> /// <returns>Newly created navigation data.</returns> public NavigationData StackSubordinateNavigationContext(ViewSpecification subViewSpecification, AbstractScreenData visibleScreen, string navbarDisplayLabel) { WorkflowState newState = WorkflowState.CreateTransientState( "View: " + subViewSpecification.ViewDisplayName, subViewSpecification.ViewDisplayName, false, null, true, WorkflowType.Workflow); ScreenConfig nextScreenConfig; LoadLayoutSettings(visibleScreen.ToString(), out nextScreenConfig); Sorting.Sorting nextSortingMode = AvailableSortings.FirstOrDefault(sorting => sorting.GetType().ToString() == nextScreenConfig.Sorting) ?? _currentSorting; NavigationData newNavigationData = new NavigationData(this, subViewSpecification.ViewDisplayName, _baseWorkflowStateId, newState.StateId, subViewSpecification, visibleScreen, _availableScreens, nextSortingMode, true) { LayoutType = nextScreenConfig.LayoutType, LayoutSize = nextScreenConfig.LayoutSize }; PushNewNavigationWorkflowState(newState, navbarDisplayLabel, newNavigationData); return newNavigationData; }
/// <summary> /// Whether this screen can filter items shown by the <paramref name="parentScreen"/>. /// The default implementation checks whether at least one of the <see cref="FilteredMias"/> is present in the <paramref name="parentScreen"/>'s <see cref="FilteredMias"/> /// or whether <see cref="FilteredMias"/> is null on this or the parent screen. /// Can be overriden in derived classes. /// </summary> /// <param name="parentScreen">The screen that is currently shown.</param> /// <returns>True if this screen can handle items shown by the <paramref name="parentScreen"/></returns> public virtual bool CanFilter(AbstractScreenData parentScreen) { return(_filteredMias == null || parentScreen == null || parentScreen.FilteredMias == null || _filteredMias.Intersect(parentScreen.FilteredMias).Count() > 0); }
//Special case for series screen, it can support series filters and episode filters public override bool CanFilter(AbstractScreenData parentScreen) { return(base.CanFilter(parentScreen) || parentScreen.FilteredMias.Contains(SeriesAspect.ASPECT_ID)); }
/// <summary> /// Switches to browsing by MediaLibray shares, limited to restricted MediaCategories. /// </summary> protected void SetBrowseMode() { _availableScreens = null; _defaultScreen = new BrowseMediaNavigationScreenData(_genericPlayableItemCreatorDelegate); _customRootViewSpecification = new BrowseMediaRootProxyViewSpecification(_viewName, _necessaryMias, null, _restrictedMediaCategories); }