示例#1
0
 /// <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)
 {
 }
        public virtual void InitMediaNavigation(out string mediaNavigationMode, out NavigationData navigationData)
        {
            Prepare();

            string             nextScreenName;
            AbstractScreenData nextScreen = null;

            // Try to load the prefered next screen from settings.
            if (NavigationData.LoadScreenHierarchy(_viewName, out nextScreenName))
            {
                // Support for browsing mode.
                if (nextScreenName == Consts.USE_BROWSE_MODE)
                {
                    SetBrowseMode();
                }

                if (_availableScreens != null)
                {
                    nextScreen = _availableScreens.FirstOrDefault(s => s.GetType().ToString() == nextScreenName);
                }
            }

            IEnumerable <Guid> optionalMIATypeIDs = MediaNavigationModel.GetMediaSkinOptionalMIATypes(MediaNavigationMode);

            if (_optionalMias != null)
            {
                optionalMIATypeIDs = optionalMIATypeIDs.Union(_optionalMias);
                optionalMIATypeIDs = optionalMIATypeIDs.Except(_necessaryMias);
            }
            // Prefer custom view specification.
            ViewSpecification rootViewSpecification = _customRootViewSpecification ??
                                                      new MediaLibraryQueryViewSpecification(_viewName, _filter, _necessaryMias, optionalMIATypeIDs, true, _necessaryMias)
            {
                MaxNumItems = Consts.MAX_NUM_ITEMS_VISIBLE
            };

            if (nextScreen == null)
            {
                nextScreen = _defaultScreen;
            }

            ScreenConfig nextScreenConfig;

            NavigationData.LoadLayoutSettings(nextScreen.GetType().ToString(), out nextScreenConfig);

            Sorting.Sorting nextSortingMode  = _availableSortings.FirstOrDefault(sorting => sorting.GetType().ToString() == nextScreenConfig.Sorting) ?? _defaultSorting;
            Sorting.Sorting nextGroupingMode = _availableGroupings == null || String.IsNullOrEmpty(nextScreenConfig.Grouping) ? null : _availableGroupings.FirstOrDefault(grouping => grouping.GetType().ToString() == nextScreenConfig.Grouping) ?? _defaultGrouping;

            navigationData = new NavigationData(null, _viewName, MediaNavigationRootState,
                                                MediaNavigationRootState, rootViewSpecification, nextScreen, _availableScreens, nextSortingMode, nextGroupingMode)
            {
                AvailableSortings  = _availableSortings,
                AvailableGroupings = _availableGroupings,
                LayoutType         = nextScreenConfig.LayoutType,
                LayoutSize         = nextScreenConfig.LayoutSize
            };
            mediaNavigationMode = MediaNavigationMode;
        }
        /// <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);
            AbstractScreenData               parentScreen = _parent != null ? _parent.CurrentScreenData : null;
            IEnumerable <AbstractScreenData> screens      = parentScreen != null?_availableScreens.Where(s => s.CanFilter(parentScreen)) : _availableScreens;

            int ct = 0;

            foreach (AbstractScreenData screen in screens)
            {
                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 modifying the list of available screens. This is used for
        /// presenting the result of a filter, where the menu must be changed.
        /// </summary>
        /// <param name="subViewSpecification">Specification for the sub view to be shown in the new navigation context.</param>
        /// <param name="currentMenuItemLabel">Current menu item label needed for distinction of available screens.</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 StackAutonomousNavigationContext(ViewSpecification subViewSpecification, string currentMenuItemLabel, string navbarDisplayLabel)
        {
            AbstractScreenData currentScreen = AvailableScreens.FirstOrDefault(screen => screen.MenuItemLabel == currentMenuItemLabel);
            ICollection <AbstractScreenData> remainingScreens = new List <AbstractScreenData>(AvailableScreens.Where(screen => screen != currentScreen));

            WorkflowState newState = WorkflowState.CreateTransientState(
                "View: " + subViewSpecification.ViewDisplayName, subViewSpecification.ViewDisplayName,
                false, null, false, WorkflowType.Workflow, null);

            string             nextScreenName;
            AbstractScreenData nextScreen = null;

            // Try to load the prefered next screen from settings.
            if (LoadScreenHierarchy(CurrentScreenData.GetType().ToString(), out nextScreenName))
            {
                nextScreen = remainingScreens.FirstOrDefault(s => s.GetType().ToString() == nextScreenName);
            }

            // Default way: always take the first of the available screens.
            if (nextScreen == null)
            {
                nextScreen = remainingScreens.First(s => s != currentScreen);
            }

            ScreenConfig nextScreenConfig;

            LoadLayoutSettings(nextScreen.GetType().ToString(), out nextScreenConfig);

            Sorting.Sorting nextSortingMode = AvailableSortings.FirstOrDefault(
                sorting => sorting.GetType().ToString() == nextScreenConfig.Sorting && sorting.IsAvailable(nextScreen)) ?? _currentSorting;
            Sorting.Sorting nextGroupingMode = String.IsNullOrEmpty(nextScreenConfig.Grouping) ? null : AvailableGroupings.FirstOrDefault(
                grouping => grouping.GetType().ToString() == nextScreenConfig.Grouping && grouping.IsAvailable(nextScreen)) ?? _currentGrouping;

            NavigationData newNavigationData = new NavigationData(this, subViewSpecification.ViewDisplayName,
                                                                  newState.StateId, newState.StateId, subViewSpecification, nextScreen, remainingScreens,
                                                                  nextSortingMode, nextGroupingMode)
            {
                LayoutType = nextScreenConfig.LayoutType, LayoutSize = nextScreenConfig.LayoutSize
            };

            PushNewNavigationWorkflowState(newState, navbarDisplayLabel, newNavigationData);
            return(newNavigationData);
        }
示例#5
0
 // 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, null);

            ScreenConfig nextScreenConfig;

            LoadLayoutSettings(visibleScreen.ToString(), out nextScreenConfig);

            Sorting.Sorting nextSortingMode = AvailableSortings.FirstOrDefault(
                sorting => sorting.GetType().ToString() == nextScreenConfig.Sorting && sorting.IsAvailable(visibleScreen)) ?? _currentSorting;
            Sorting.Sorting nextGroupingMode = string.IsNullOrEmpty(nextScreenConfig.Grouping) ? null : AvailableGroupings.FirstOrDefault(
                grouping => grouping.GetType().ToString() == nextScreenConfig.Grouping && grouping.IsAvailable(visibleScreen)) ?? _currentGrouping;

            NavigationData newNavigationData = new NavigationData(this, subViewSpecification.ViewDisplayName,
                                                                  _baseWorkflowStateId, newState.StateId, subViewSpecification, visibleScreen, _availableScreens, nextSortingMode, nextGroupingMode, true)
            {
                LayoutType = nextScreenConfig.LayoutType,
                LayoutSize = nextScreenConfig.LayoutSize
            };

            PushNewNavigationWorkflowState(newState, navbarDisplayLabel, newNavigationData);
            return(newNavigationData);
        }
 /// <summary>
 /// Switches to browsing by MediaLibray shares, limited to restricted MediaCategories.
 /// </summary>
 /// <param name="optionalMIATypeIDs">Optional MIAs to use.</param>
 protected void SetBrowseMode(IEnumerable <Guid> optionalMIATypeIDs)
 {
     _availableScreens            = null;
     _defaultScreen               = new BrowseMediaNavigationScreenData(_genericPlayableItemCreatorDelegate);
     _customRootViewSpecification = new BrowseMediaRootProxyViewSpecification(_viewName, _necessaryMias, optionalMIATypeIDs, _restrictedMediaCategories);
 }
        public virtual void InitMediaNavigation(MediaNavigationConfig config, out string mediaNavigationMode, out NavigationData navigationData)
        {
            PrepareAsync().Wait();

            IFilterTree filterTree = _customFilterTree ?? (_rootRole.HasValue ? new RelationshipFilterTree(_rootRole.Value) : (IFilterTree) new SimpleFilterTree());

            if (_filter != null)
            {
                filterTree.AddFilter(_filter);
            }

            //Default configuration
            string viewName = _viewName;

            AbstractScreenData nextScreen = null;

            //Apply any custom configuration
            if (config != null)
            {
                if (_availableScreens != null)
                {
                    //Use the configured root screen to load the next screen from the hierarchy
                    //and remove it from the list of available screens
                    AbstractScreenData configRoot = config.RootScreenType != null?_availableScreens.FirstOrDefault(s => s.GetType() == config.RootScreenType) : null;

                    if (configRoot != null)
                    {
                        viewName = configRoot.GetType().ToString();
                        _availableScreens.Remove(configRoot);
                    }

                    //Use the configured default screen if there is no saved screen hierarchy
                    AbstractScreenData configDefault = config.DefaultScreenType != null?_availableScreens.FirstOrDefault(s => s.GetType() == config.DefaultScreenType) : null;

                    if (configDefault != null)
                    {
                        _defaultScreen = configDefault;
                        // If we want to force the default screen to be shown, set the next screen
                        // here to avoid loading it from the screen hierarchy below.
                        if (config.AlwaysUseDefaultScreen)
                        {
                            nextScreen = configDefault;
                        }
                    }
                }

                //Apply any additional filters
                if (config.LinkedId.HasValue)
                {
                    filterTree.AddLinkedId(config.LinkedId.Value, config.FilterPath);
                }
                if (config.Filter != null)
                {
                    filterTree.AddFilter(config.Filter, config.FilterPath);
                }
            }

            IEnumerable <Guid> optionalMIATypeIDs = MediaNavigationModel.GetMediaSkinOptionalMIATypes(MediaNavigationMode);

            if (_optionalMias != null)
            {
                optionalMIATypeIDs = optionalMIATypeIDs.Union(_optionalMias).Except(_necessaryMias);
            }

            // Try to load the prefered next screen from settings if not already set.
            if (nextScreen == null && NavigationData.LoadScreenHierarchy(viewName, out string nextScreenName))
            {
                // Support for browsing mode.
                if (nextScreenName == Consts.USE_BROWSE_MODE)
                {
                    SetBrowseMode(optionalMIATypeIDs);
                }

                if (_availableScreens != null)
                {
                    nextScreen = _availableScreens.FirstOrDefault(s => s.GetType().ToString() == nextScreenName);
                }
            }

            if (_applyUserFilter)
            {
                var userFilter = UserHelper.GetUserRestrictionFilter(_necessaryMias.ToList());
                if (userFilter != null)
                {
                    filterTree.AddFilter(userFilter);
                }
            }

            // Prefer custom view specification.
            ViewSpecification rootViewSpecification = _customRootViewSpecification ??
                                                      // Always use the default view name for the root view specification, not any custom name that may
                                                      // have been specified in a navigation config, otherwise toggling browse mode won't work correctly.
                                                      // To switch to browse mode we update the root screen hierarchy to point to the browse screen and
                                                      // then navigate to the root wf state. The name of the root screen hierarchy is determined by the
                                                      // name specified here so it should always point to the actual root view name.
                                                      new MediaLibraryQueryViewSpecification(_viewName, filterTree, _necessaryMias, optionalMIATypeIDs, true)
            {
                MaxNumItems = Consts.MAX_NUM_ITEMS_VISIBLE,
            };

            if (nextScreen == null)
            {
                nextScreen = _defaultScreen;
            }

            ScreenConfig nextScreenConfig;

            NavigationData.LoadLayoutSettings(nextScreen.GetType().ToString(), out nextScreenConfig);

            Sorting.Sorting nextSortingMode  = _availableSortings.FirstOrDefault(sorting => sorting.GetType().ToString() == nextScreenConfig.Sorting) ?? _defaultSorting;
            Sorting.Sorting nextGroupingMode = _availableGroupings == null || String.IsNullOrEmpty(nextScreenConfig.Grouping) ? null : _availableGroupings.FirstOrDefault(grouping => grouping.GetType().ToString() == nextScreenConfig.Grouping) ?? _defaultGrouping;

            navigationData = new NavigationData(null, viewName, MediaNavigationRootState,
                                                MediaNavigationRootState, rootViewSpecification, nextScreen, _availableScreens, nextSortingMode, nextGroupingMode)
            {
                AvailableSortings  = _availableSortings,
                AvailableGroupings = _availableGroupings,
                LayoutType         = nextScreenConfig.LayoutType,
                LayoutSize         = nextScreenConfig.LayoutSize
            };
            mediaNavigationMode = MediaNavigationMode;
        }
示例#9
0
 public virtual bool IsAvailable(AbstractScreenData visibleScreen)
 {
     return(visibleScreen == null || visibleScreen.AvailableMias == null ||
            (_excludeMias != null && _excludeMias.Intersect(visibleScreen.AvailableMias).Count() > 0 ? false :
             (_includeMias != null && _includeMias.Intersect(visibleScreen.AvailableMias).Count() > 0)));
 }
示例#10
0
        /// <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);
        }
示例#11
0
        /// <summary>
        /// Returns context variables to be set for the given workflow state id.
        /// </summary>
        /// <param name="workflowStateId">Workflow state which determines the root media navigation state.</param>
        /// <returns>Mapping of context variable keys to values.</returns>
        protected static IDictionary <string, object> PrepareRootState(Guid workflowStateId)
        {
            IDictionary <string, object> result = new Dictionary <string, object>();
            // The initial state ID determines the media model "part" to initialize: Browse local media, browse media library, audio, videos or images.
            // The media model part determines the media navigation mode and the view contents to be set.
            NavigationData navigationData;
            string         mode;

            if (_initializers.ContainsKey(workflowStateId))
            {
                // Use the IMediaNavigationInitializer that is associated with our root workflow state.
                IMediaNavigationInitializer initializer = _initializers[workflowStateId];
                initializer.InitMediaNavigation(out mode, out navigationData);
            }
            else
            {
                // If we were called with a supported root state, we should be either in state WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT
                // or WF_STATE_ID_MEDIA_BROWSE_NAVIGATION_ROOT here
                if (workflowStateId != Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT &&
                    workflowStateId != Consts.WF_STATE_ID_BROWSE_MEDIA_NAVIGATION_ROOT)
                {
                    // Error case: We cannot handle the given state
                    ServiceRegistration.Get <ILogger>().Warn("MediaNavigationModel: Unknown root workflow state with ID '{0}', initializing local media navigation", workflowStateId);
                    // We simply use the local media mode as fallback for this case, so we go on
                    workflowStateId = Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT;
                }
                mode = workflowStateId == Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT ? MediaNavigationMode.BrowseLocalMedia :
                       MediaNavigationMode.BrowseMediaLibrary;
                IEnumerable <Guid> skinDependentOptionalMIATypeIDs       = GetMediaSkinOptionalMIATypes(mode);
                AbstractItemsScreenData.PlayableItemCreatorDelegate picd = mi =>
                {
                    if (mi.Aspects.ContainsKey(AudioAspect.ASPECT_ID))
                    {
                        return new AudioItem(mi)
                               {
                                   Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                               }
                    }
                    ;
                    if (mi.Aspects.ContainsKey(VideoAspect.ASPECT_ID))
                    {
                        return new VideoItem(mi)
                               {
                                   Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                               }
                    }
                    ;
                    if (mi.Aspects.ContainsKey(ImageAspect.ASPECT_ID))
                    {
                        return new ImageItem(mi)
                               {
                                   Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                               }
                    }
                    ;
                    return(null);
                };
                IEnumerable <Guid> necessaryMIATypeIDs = new Guid[]
                {
                    ProviderResourceAspect.ASPECT_ID,
                    MediaAspect.ASPECT_ID,
                };
                IEnumerable <Guid> optionalMIATypeIDs = new Guid[]
                {
                    AudioAspect.ASPECT_ID,
                    VideoAspect.ASPECT_ID,
                    ImageAspect.ASPECT_ID,
                }.Union(skinDependentOptionalMIATypeIDs);
                string viewName = workflowStateId == Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT ?
                                  Consts.RES_LOCAL_MEDIA_ROOT_VIEW_NAME : Consts.RES_BROWSE_MEDIA_ROOT_VIEW_NAME;
                ViewSpecification rootViewSpecification = workflowStateId == Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT ?
                                                          new AddedRemovableMediaViewSpecificationFacade(new LocalMediaRootProxyViewSpecification(viewName, necessaryMIATypeIDs, optionalMIATypeIDs)) :
                                                          new AddedRemovableMediaViewSpecificationFacade(new BrowseMediaRootProxyViewSpecification(viewName, necessaryMIATypeIDs, optionalMIATypeIDs));
                // Dynamic screens remain null - browse media states don't provide dynamic filters
                AbstractScreenData screenData = workflowStateId == Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT ?
                                                (AbstractScreenData) new LocalMediaNavigationScreenData(picd) : new BrowseMediaNavigationScreenData(picd);
                Sorting.Sorting browseDefaultSorting            = new BrowseDefaultSorting();
                ICollection <Sorting.Sorting> availableSortings = new List <Sorting.Sorting>
                {
                    browseDefaultSorting,
                    new SortByTitle(),
                    new SortByDate(),
                    // We could offer sortings here which are specific for one media item type but which will cope with all three item types (and sort items of the three types in a defined order)
                };
                navigationData = new NavigationData(null, viewName, workflowStateId,
                                                    workflowStateId, rootViewSpecification, screenData, null, browseDefaultSorting)
                {
                    AvailableSortings = availableSortings
                };
            }
            result.Add(Consts.KEY_NAVIGATION_MODE, mode);
            result.Add(Consts.KEY_NAVIGATION_DATA, navigationData);
            return(result);
        }
        /// <summary>
        /// Returns context variables to be set for the given workflow state id.
        /// </summary>
        /// <param name="workflowStateId">Workflow state which determines the root media navigation state.</param>
        /// <returns>Mapping of context variable keys to values.</returns>
        protected static IDictionary <string, object> PrepareRootState(Guid workflowStateId)
        {
            IDictionary <string, object> result = new Dictionary <string, object>();
            // The initial state ID determines the media model "part" to initialize: Browse local media, browse media library, audio, videos or images.
            // The media model part determines the media navigation mode and the view contents to be set.
            NavigationData      navigationData;
            MediaNavigationMode mode;

            if (workflowStateId == Consts.WF_STATE_ID_AUDIO_NAVIGATION_ROOT)
            {
                mode = MediaNavigationMode.Audio;
                IEnumerable <Guid> skinDependentOptionalMIATypeIDs       = GetMediaSkinOptionalMIATypes(mode);
                AbstractItemsScreenData.PlayableItemCreatorDelegate picd = mi => new AudioItem(mi)
                {
                    Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                };
                ViewSpecification rootViewSpecification = new MediaLibraryQueryViewSpecification(Consts.RES_AUDIO_VIEW_NAME,
                                                                                                 null, Consts.NECESSARY_AUDIO_MIAS, skinDependentOptionalMIATypeIDs, true)
                {
                    MaxNumItems = Consts.MAX_NUM_ITEMS_VISIBLE
                };
                AbstractScreenData filterByAlbum = new AudioFilterByAlbumScreenData();
                ICollection <AbstractScreenData> availableScreens = new List <AbstractScreenData>
                {
                    new AudioShowItemsScreenData(picd),
                    new AudioFilterByArtistScreenData(),
                    filterByAlbum, // C# doesn't like it to have an assignment inside a collection initializer
                    new AudioFilterByGenreScreenData(),
                    new AudioFilterByDecadeScreenData(),
                    new AudioFilterBySystemScreenData(),
                    new AudioSimpleSearchScreenData(picd),
                };
                Sorting.Sorting sortByAlbumTrack = new AudioSortByAlbumTrack();
                ICollection <Sorting.Sorting> availableSortings = new List <Sorting.Sorting>
                {
                    sortByAlbumTrack,
                    new SortByTitle(),
                    new AudioSortByFirstGenre(),
                    new AudioSortByFirstArtist(),
                    new AudioSortByAlbum(),
                    new AudioSortByTrack(),
                    new SortByYear(),
                    new SortBySystem(),
                };
                navigationData = new NavigationData(null, Consts.RES_AUDIO_VIEW_NAME, workflowStateId,
                                                    workflowStateId, rootViewSpecification, filterByAlbum, availableScreens, sortByAlbumTrack)
                {
                    AvailableSortings = availableSortings
                };
            }
            else if (workflowStateId == Consts.WF_STATE_ID_VIDEOS_NAVIGATION_ROOT)
            {
                mode = MediaNavigationMode.Videos;
                IEnumerable <Guid> skinDependentOptionalMIATypeIDs       = GetMediaSkinOptionalMIATypes(mode);
                AbstractItemsScreenData.PlayableItemCreatorDelegate picd = mi => new VideoItem(mi)
                {
                    Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                };
                ViewSpecification rootViewSpecification = new MediaLibraryQueryViewSpecification(Consts.RES_VIDEOS_VIEW_NAME,
                                                                                                 null, Consts.NECESSARY_VIDEO_MIAS, skinDependentOptionalMIATypeIDs, true)
                {
                    MaxNumItems = Consts.MAX_NUM_ITEMS_VISIBLE
                };
                AbstractScreenData filterByGenre = new VideosFilterByGenreScreenData();
                ICollection <AbstractScreenData> availableScreens = new List <AbstractScreenData>
                {
                    new VideosShowItemsScreenData(picd),
                    new VideosFilterByLanguageScreenData(),
                    new VideosFilterByActorScreenData(),
                    filterByGenre, // C# doesn't like it to have an assignment inside a collection initializer
                    new VideosFilterByYearScreenData(),
                    new VideosFilterBySystemScreenData(),
                    new VideosSimpleSearchScreenData(picd),
                };
                Sorting.Sorting sortByTitle = new SortByTitle();
                ICollection <Sorting.Sorting> availableSortings = new List <Sorting.Sorting>
                {
                    sortByTitle,
                    new SortByYear(),
                    new VideoSortByFirstGenre(),
                    new VideoSortByDuration(),
                    new VideoSortByDirector(),
                    new VideoSortByFirstActor(),
                    new VideoSortBySize(),
                    new VideoSortByAspectRatio(),
                    new SortBySystem(),
                };
                navigationData = new NavigationData(null, Consts.RES_VIDEOS_VIEW_NAME, workflowStateId,
                                                    workflowStateId, rootViewSpecification, filterByGenre, availableScreens, sortByTitle)
                {
                    AvailableSortings = availableSortings
                };
            }
            else if (workflowStateId == Consts.WF_STATE_ID_SERIES_NAVIGATION_ROOT)
            {
                mode = MediaNavigationMode.Videos;
                IEnumerable <Guid> skinDependentOptionalMIATypeIDs       = GetMediaSkinOptionalMIATypes(mode);
                AbstractItemsScreenData.PlayableItemCreatorDelegate picd = mi => new SeriesItem(mi)
                {
                    Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                };
                ViewSpecification rootViewSpecification = new MediaLibraryQueryViewSpecification(Consts.RES_SERIES_VIEW_NAME,
                                                                                                 null, Consts.NECESSARY_SERIES_MIAS, skinDependentOptionalMIATypeIDs, true)
                {
                    MaxNumItems = Consts.MAX_NUM_ITEMS_VISIBLE
                };
                AbstractScreenData filterBySeries = new SeriesFilterByNameScreenData();
                ICollection <AbstractScreenData> availableScreens = new List <AbstractScreenData>
                {
                    new SeriesShowItemsScreenData(picd),
                    filterBySeries, // C# doesn't like it to have an assignment inside a collection initializer
                    new VideosFilterByLanguageScreenData(),
                    new SeriesFilterBySeasonScreenData(),
                    new VideosFilterByGenreScreenData(),
                    new VideosSimpleSearchScreenData(picd),
                };
                Sorting.Sorting sortByEpisode = new SeriesSortByEpisode();
                ICollection <Sorting.Sorting> availableSortings = new List <Sorting.Sorting>
                {
                    sortByEpisode,
                    new SortByTitle(),
                    new SortByDate(),
                    new SortBySystem(),
                };
                navigationData = new NavigationData(null, Consts.RES_SERIES_VIEW_NAME, workflowStateId,
                                                    workflowStateId, rootViewSpecification, filterBySeries, availableScreens, sortByEpisode)
                {
                    AvailableSortings = availableSortings
                };
            }
            else if (workflowStateId == Consts.WF_STATE_ID_MOVIES_NAVIGATION_ROOT)
            {
                mode = MediaNavigationMode.Movies;
                IEnumerable <Guid> skinDependentOptionalMIATypeIDs       = GetMediaSkinOptionalMIATypes(mode);
                AbstractItemsScreenData.PlayableItemCreatorDelegate picd = mi => new MovieItem(mi)
                {
                    Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                };
                ViewSpecification rootViewSpecification = new MediaLibraryQueryViewSpecification(Consts.RES_MOVIES_VIEW_NAME,
                                                                                                 null, Consts.NECESSARY_MOVIES_MIAS, skinDependentOptionalMIATypeIDs, true)
                {
                    MaxNumItems = Consts.MAX_NUM_ITEMS_VISIBLE
                };
                AbstractScreenData filterByGenre = new VideosFilterByGenreScreenData();
                ICollection <AbstractScreenData> availableScreens = new List <AbstractScreenData>
                {
                    new MoviesShowItemsScreenData(picd),
                    new VideosFilterByActorScreenData(),
                    filterByGenre, // C# doesn't like it to have an assignment inside a collection initializer
                    new VideosFilterByYearScreenData(),
                    new VideosFilterBySystemScreenData(),
                    new VideosSimpleSearchScreenData(picd),
                };
                Sorting.Sorting sortByTitle = new SortByTitle();
                ICollection <Sorting.Sorting> availableSortings = new List <Sorting.Sorting>
                {
                    sortByTitle,
                    new SortByYear(),
                    new VideoSortByFirstGenre(),
                    new VideoSortByDuration(),
                    new VideoSortByDirector(),
                    new VideoSortByFirstActor(),
                    new VideoSortBySize(),
                    new VideoSortByAspectRatio(),
                    new SortBySystem(),
                };

                navigationData = new NavigationData(null, Consts.RES_MOVIES_VIEW_NAME, workflowStateId,
                                                    workflowStateId, rootViewSpecification, filterByGenre, availableScreens, sortByTitle)
                {
                    AvailableSortings = availableSortings
                };
            }
            else if (workflowStateId == Consts.WF_STATE_ID_IMAGES_NAVIGATION_ROOT)
            {
                mode = MediaNavigationMode.Images;
                IEnumerable <Guid> skinDependentOptionalMIATypeIDs       = GetMediaSkinOptionalMIATypes(mode);
                AbstractItemsScreenData.PlayableItemCreatorDelegate picd = mi => new ImageItem(mi)
                {
                    Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                };
                ViewSpecification rootViewSpecification = new MediaLibraryQueryViewSpecification(Consts.RES_IMAGES_VIEW_NAME,
                                                                                                 null, Consts.NECESSARY_IMAGE_MIAS, skinDependentOptionalMIATypeIDs, true)
                {
                    MaxNumItems = Consts.MAX_NUM_ITEMS_VISIBLE
                };
                AbstractScreenData filterByYear = new ImagesFilterByYearScreenData();
                ICollection <AbstractScreenData> availableScreens = new List <AbstractScreenData>
                {
                    new ImagesShowItemsScreenData(picd),
                    filterByYear, // C# doesn't like it to have an assignment inside a collection initializer
                    new ImagesFilterBySizeScreenData(),
                    new ImagesFilterBySystemScreenData(),
                    new ImagesSimpleSearchScreenData(picd),
                };
                Sorting.Sorting sortByYear = new SortByYear();
                ICollection <Sorting.Sorting> availableSortings = new List <Sorting.Sorting>
                {
                    new SortByYear(),
                    new SortByTitle(),
                    new ImageSortBySize(),
                    new SortBySystem(),
                };
                navigationData = new NavigationData(null, Consts.RES_IMAGES_VIEW_NAME, workflowStateId,
                                                    workflowStateId, rootViewSpecification, filterByYear, availableScreens, sortByYear)
                {
                    AvailableSortings = availableSortings
                };
            }
            else
            {
                // If we were called with a supported root state, we should be either in state WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT
                // or WF_STATE_ID_MEDIA_BROWSE_NAVIGATION_ROOT here
                if (workflowStateId != Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT &&
                    workflowStateId != Consts.WF_STATE_ID_BROWSE_MEDIA_NAVIGATION_ROOT)
                {
                    // Error case: We cannot handle the given state
                    ServiceRegistration.Get <ILogger>().Warn("MediaNavigationModel: Unknown root workflow state with ID '{0}', initializing local media navigation", workflowStateId);
                    // We simply use the local media mode as fallback for this case, so we go on
                    workflowStateId = Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT;
                }
                mode = workflowStateId == Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT ? MediaNavigationMode.BrowseLocalMedia :
                       MediaNavigationMode.BrowseMediaLibrary;
                IEnumerable <Guid> skinDependentOptionalMIATypeIDs       = GetMediaSkinOptionalMIATypes(mode);
                AbstractItemsScreenData.PlayableItemCreatorDelegate picd = mi =>
                {
                    if (mi.Aspects.ContainsKey(AudioAspect.ASPECT_ID))
                    {
                        return new AudioItem(mi)
                               {
                                   Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                               }
                    }
                    ;
                    if (mi.Aspects.ContainsKey(VideoAspect.ASPECT_ID))
                    {
                        return new VideoItem(mi)
                               {
                                   Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                               }
                    }
                    ;
                    if (mi.Aspects.ContainsKey(ImageAspect.ASPECT_ID))
                    {
                        return new ImageItem(mi)
                               {
                                   Command = new MethodDelegateCommand(() => PlayItemsModel.CheckQueryPlayAction(mi))
                               }
                    }
                    ;
                    return(null);
                };
                IEnumerable <Guid> necessaryMIATypeIDs = new Guid[]
                {
                    ProviderResourceAspect.ASPECT_ID,
                    MediaAspect.ASPECT_ID,
                };
                IEnumerable <Guid> optionalMIATypeIDs = new Guid[]
                {
                    AudioAspect.ASPECT_ID,
                    VideoAspect.ASPECT_ID,
                    ImageAspect.ASPECT_ID,
                }.Union(skinDependentOptionalMIATypeIDs);
                string viewName = workflowStateId == Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT ?
                                  Consts.RES_LOCAL_MEDIA_ROOT_VIEW_NAME : Consts.RES_BROWSE_MEDIA_ROOT_VIEW_NAME;
                ViewSpecification rootViewSpecification = workflowStateId == Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT ?
                                                          new AddedRemovableMediaViewSpecificationFacade(new LocalMediaRootProxyViewSpecification(viewName, necessaryMIATypeIDs, optionalMIATypeIDs)) :
                                                          new AddedRemovableMediaViewSpecificationFacade(new BrowseMediaRootProxyViewSpecification(viewName, necessaryMIATypeIDs, optionalMIATypeIDs));
                // Dynamic screens remain null - browse media states don't provide dynamic filters
                AbstractScreenData screenData = workflowStateId == Consts.WF_STATE_ID_LOCAL_MEDIA_NAVIGATION_ROOT ?
                                                (AbstractScreenData) new LocalMediaNavigationScreenData(picd) : new BrowseMediaNavigationScreenData(picd);
                Sorting.Sorting browseDefaultSorting            = new BrowseDefaultSorting();
                ICollection <Sorting.Sorting> availableSortings = new List <Sorting.Sorting>
                {
                    browseDefaultSorting,
                    new SortByTitle(),
                    new SortByDate(),
                    // We could offer sortings here which are specific for one media item type but which will cope with all three item types (and sort items of the three types in a defined order)
                };
                navigationData = new NavigationData(null, viewName, workflowStateId,
                                                    workflowStateId, rootViewSpecification, screenData, null, browseDefaultSorting)
                {
                    AvailableSortings = availableSortings
                };
            }
            result.Add(Consts.KEY_NAVIGATION_MODE, mode);
            result.Add(Consts.KEY_NAVIGATION_DATA, navigationData);
            return(result);
        }