protected override async Task PrepareAsync() { await base.PrepareAsync().ConfigureAwait(false); AbstractItemsScreenData.PlayableItemCreatorDelegate picd = mi => new GameItem(mi) { Command = new MethodDelegateCommand(() => ServiceRegistration.Get <IGameLauncher>().LaunchGame(mi)) }; _genericPlayableItemCreatorDelegate = picd; _defaultScreen = new GamesShowItemsScreenData(picd); _availableScreens = new List <AbstractScreenData> { _defaultScreen, new GameFilterByPlatformScreenData(), new GameFilterByYearScreenData(), new GameFilterByGenreScreenData(), new GameFilterByDeveloperScreenData() }; _defaultSorting = new SortByTitle(); _availableSortings = new List <Sorting> { _defaultSorting, new SortByYear(), new SortByRatingDesc() }; var optionalMias = new Guid[] { GoodMergeAspect.ASPECT_ID }.Union(MediaNavigationModel.GetMediaSkinOptionalMIATypes(MediaNavigationMode)); _customRootViewSpecification = new MediaLibraryQueryViewSpecification(_viewName, null, _necessaryMias, optionalMias, true); }
public void InitMediaNavigation(out string mediaNavigationMode, out NavigationData navigationData) { IEnumerable <Guid> skinDependentOptionalMIATypeIDs = MediaNavigationModel.GetMediaSkinOptionalMIATypes(MediaNavigationMode); 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, MediaNavigationRootState, MediaNavigationRootState, rootViewSpecification, filterByGenre, availableScreens, sortByTitle) { AvailableSortings = availableSortings }; mediaNavigationMode = MediaNavigationMode; }
protected void InitializeSearch(ViewSpecification baseViewSpecification) { _baseViewSpecification = baseViewSpecification as MediaLibraryQueryViewSpecification; if (_baseViewSpecification == null) { return; } if (_simpleSearchTextProperty == null) { _simpleSearchTextProperty = new WProperty(typeof(string), string.Empty); _simpleSearchTextProperty.Attach(OnSimpleSearchTextChanged); } SimpleSearchText = string.Empty; // Initialize data manually which would have been initialized by AbstractItemsScreenData.UpdateMediaItems else IsItemsValid = true; IsItemsEmpty = false; TooManyItems = false; NumItemsStr = "-"; NumItems = 0; lock (_syncObj) _view = null; _items = new ItemsList(); }
/// <summary> /// Updates the GUI data for a filter values selection screen which reflects the available filter values for /// the current base view specification of our <see cref="AbstractScreenData._navigationData"/>. /// </summary> protected void ReloadFilterValuesList(bool createNewList) { MediaLibraryQueryViewSpecification currentVS = _navigationData.BaseViewSpecification as MediaLibraryQueryViewSpecification; if (currentVS == null) { // Should never happen ServiceRegistration.Get <ILogger>().Error("FilterScreenData: Wrong type of media library view '{0}'", _navigationData.BaseViewSpecification); return; } // Control other threads reentering this method lock (_syncObj) { if (_buildingList) { // Another thread is already building the items list - mark it as dirty and let the other thread // rebuild it. _listDirty = true; return; } // Mark the list as being built _buildingList = true; _listDirty = false; } try { ItemsList items; if (createNewList) { items = new ItemsList(); } else { items = _items; items.Clear(); } try { Display_ListBeingBuilt(); bool grouping = true; ICollection <FilterValue> fv = _clusterFilter == null? _filterCriterion.GroupValues(currentVS.NecessaryMIATypeIds, _clusterFilter, currentVS.Filter) : null; if (fv == null || fv.Count <= Consts.MAX_NUM_ITEMS_VISIBLE) { fv = _filterCriterion.GetAvailableValues(currentVS.NecessaryMIATypeIds, _clusterFilter, currentVS.Filter); grouping = false; } if (fv.Count > Consts.MAX_NUM_ITEMS_VISIBLE) { Display_TooManyItems(fv.Count); } else { lock (_syncObj) if (_listDirty) { goto RebuildView; } int totalNumItems = 0; // Build collection of available (filter/display) screens which will remain in the next view - that is all currently // available screens without the screen which equals this current screen. But we cannot simply remove "this" // from the collection, because "this" could be a derived screen (in case our base screen showed groups). // So we need an equality criterion when the screen to be removed is equal to this screen in terms of its // filter criterion. But with the given data, we actually cannot derive that equality. // So we simply use the MenuItemLabel, which should be the same in this and the base screen of the same filter. foreach (FilterValue filterValue in fv) { string filterTitle = filterValue.Title; IFilter selectAttributeFilter = filterValue.SelectAttributeFilter; MediaLibraryQueryViewSpecification subVS = currentVS.CreateSubViewSpecification(filterTitle, filterValue.Filter); T filterValueItem = new T { SimpleTitle = filterTitle, NumItems = filterValue.NumItems, Command = grouping ? new MethodDelegateCommand(() => NavigateToGroup(subVS, selectAttributeFilter)) : new MethodDelegateCommand(() => NavigateToSubView(subVS)) }; items.Add(filterValueItem); if (filterValue.NumItems.HasValue) { totalNumItems += filterValue.NumItems.Value; } } Display_Normal(items.Count, totalNumItems == 0 ? new int?() : totalNumItems); } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("AbstractFiltersScreenData: Error creating filter values list", e); Display_ItemsInvalid(); } RebuildView: if (_listDirty) { lock (_syncObj) _buildingList = false; ReloadFilterValuesList(createNewList); } else { _items = items; _items.FireChange(); } } finally { lock (_syncObj) _buildingList = false; } }
/// <summary> /// Updates the GUI data for a filter values selection screen which reflects the available filter values for /// the current base view specification of our <see cref="AbstractScreenData._navigationData"/>. /// </summary> protected async Task ReloadFilterValuesList(bool createNewList) { MediaLibraryQueryViewSpecification currentVS = _navigationData.BaseViewSpecification as MediaLibraryQueryViewSpecification; if (currentVS == null) { // Should never happen ServiceRegistration.Get <ILogger>().Error("FilterScreenData: Wrong type of media library view '{0}'", _navigationData.BaseViewSpecification); return; } // Control other threads reentering this method lock (_syncObj) { if (_buildingList) { // Another thread is already building the items list - mark it as dirty and let the other thread // rebuild it. _listDirty = true; return; } // Mark the list as being built _buildingList = true; _listDirty = false; } try { ItemsList items; if (createNewList) { items = new ItemsList(); } else { items = _items; items.Clear(); } try { Display_ListBeingBuilt(); IFilter filter = currentVS.FilterTree.BuildFilter(_filterPath); ICollection <Guid> necessaryMIAs = _necessaryFilteredMIATypeIds ?? currentVS.NecessaryMIATypeIds; // If the number of values to create exceeds MAX_NUM_ITEMS_VISIBLE we need to try and group the items. // We request all values first, rather than groups, on the assumption that most of the time the limit // shouldn't be reached given that we are filtering the values. bool grouping = false; ICollection <FilterValue> fv = await _filterCriterion.GetAvailableValuesAsync(necessaryMIAs, _clusterFilter, filter).ConfigureAwait(false); if (fv.Count > Consts.MAX_NUM_ITEMS_VISIBLE && _clusterFilter == null) { ICollection <FilterValue> groupValues = await _filterCriterion.GroupValuesAsync(necessaryMIAs, _clusterFilter, filter).ConfigureAwait(false); if (groupValues != null && groupValues.Count > 0) { fv = groupValues; grouping = true; } } if (fv.Count > Consts.MAX_NUM_ITEMS_VISIBLE) { Display_TooManyItems(fv.Count); } else { bool dirty; lock (_syncObj) dirty = _listDirty; if (dirty) { UpdateOrRebuildView(items, createNewList); return; } _sortable = true; int totalNumItems = 0; List <FilterItem> itemsList = new List <FilterItem>(); // Build collection of available (filter/display) screens which will remain in the next view - that is all currently // available screens without the screen which equals this current screen. But we cannot simply remove "this" // from the collection, because "this" could be a derived screen (in case our base screen showed groups). // So we need an equality criterion when the screen to be removed is equal to this screen in terms of its // filter criterion. But with the given data, we actually cannot derive that equality. // So we simply use the MenuItemLabel, which should be the same in this and the base screen of the same filter. foreach (FilterValue f in fv) { //Used for enclosure FilterValue filterValue = f; _sortable &= filterValue.Item != null; string filterTitle = filterValue.Title; IFilter selectAttributeFilter = filterValue.SelectAttributeFilter; MediaLibraryQueryViewSpecification subVS = currentVS.CreateSubViewSpecification(filterTitle, FilterTreePath.Combine(_filterPath, filterValue.RelativeFilterPath), filterValue.Filter, filterValue.LinkedId); T filterValueItem = new T { // Support non-playable MediaItems (i.e. Series, Seasons) MediaItem = filterValue.Item, SimpleTitle = filterTitle, NumItems = filterValue.NumItems, Id = filterValue.Id, Command = new MethodDelegateCommand(() => { if (grouping) { NavigateToGroup(subVS, selectAttributeFilter); } else { NavigateToSubView(subVS); } }), View = subVS.BuildView() }; itemsList.Add(filterValueItem); if (filterValue.NumItems.HasValue) { totalNumItems += filterValue.NumItems.Value; } } if (_sortable) { Sorting.Sorting sorting = CurrentSorting; if (sorting != null) { itemsList.Sort((i1, i2) => sorting.Compare(i1.MediaItem, i2.MediaItem)); } } // Derived classes can implement special initial selection handling here, // e.g. the first unwatched episode could be selected from a list of episodes SetSelectedItem(itemsList); CollectionUtils.AddAll(items, itemsList); Display_Normal(items.Count, totalNumItems == 0 ? new int?() : totalNumItems); } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("AbstractFiltersScreenData: Error creating filter values list", e); Display_ItemsInvalid(); } UpdateOrRebuildView(items, createNewList); } finally { lock (_syncObj) _buildingList = false; } }
/// <summary> /// Updates the GUI data for a filter values selection screen which reflects the available filter values for /// the current base view specification of our <see cref="AbstractScreenData._navigationData"/>. /// </summary> protected void ReloadFilterValuesList(bool createNewList) { MediaLibraryQueryViewSpecification currentVS = _navigationData.BaseViewSpecification as MediaLibraryQueryViewSpecification; if (currentVS == null) { // Should never happen ServiceRegistration.Get <ILogger>().Error("FilterScreenData: Wrong type of media library view '{0}'", _navigationData.BaseViewSpecification); return; } // Control other threads reentering this method lock (_syncObj) { if (_buildingList) { // Another thread is already building the items list - mark it as dirty and let the other thread // rebuild it. _listDirty = true; return; } // Mark the list as being built _buildingList = true; _listDirty = false; } try { ItemsList items; if (createNewList) { items = new ItemsList(); } else { items = _items; items.Clear(); } try { Display_ListBeingBuilt(); bool grouping = true; //If currentVS is the base view it's possible that it has a filter that is incompatible with _filterCriterion. //This is the case if a plugin has added a base filter to exclude certain items, e.g. TV excludes recordings //and the new filter filters by a different media type, e.g. series'. Ignore the base filter in this case. IFilter currentFilter = (_navigationData.Parent != null && CanFilter(_navigationData.Parent.CurrentScreenData)) || currentVS.CanCombineFilters(_filteredMias) ? currentVS.Filter : null; ICollection <FilterValue> fv = _clusterFilter == null? _filterCriterion.GroupValues(currentVS.NecessaryMIATypeIds, _clusterFilter, currentFilter) : null; if (fv == null || fv.Count <= Consts.MAX_NUM_ITEMS_VISIBLE) { fv = _filterCriterion.GetAvailableValues(currentVS.NecessaryMIATypeIds, _clusterFilter, currentFilter); grouping = false; } if (fv.Count > Consts.MAX_NUM_ITEMS_VISIBLE) { Display_TooManyItems(fv.Count); } else { bool dirty; lock (_syncObj) dirty = _listDirty; if (dirty) { UpdateOrRebuildView(items, createNewList); return; } _sortable = true; int totalNumItems = 0; List <FilterItem> itemsList = new List <FilterItem>(); // Build collection of available (filter/display) screens which will remain in the next view - that is all currently // available screens without the screen which equals this current screen. But we cannot simply remove "this" // from the collection, because "this" could be a derived screen (in case our base screen showed groups). // So we need an equality criterion when the screen to be removed is equal to this screen in terms of its // filter criterion. But with the given data, we actually cannot derive that equality. // So we simply use the MenuItemLabel, which should be the same in this and the base screen of the same filter. foreach (FilterValue filterValue in fv) { _sortable &= filterValue.Item != null; string filterTitle = filterValue.Title; IFilter selectAttributeFilter = filterValue.SelectAttributeFilter; MediaLibraryQueryViewSpecification subVS = currentVS.CreateSubViewSpecification(filterTitle, filterValue.Filter, _filteredMias); T filterValueItem = new T { // Support non-playable MediaItems (i.e. Series, Seasons) MediaItem = filterValue.Item, SimpleTitle = filterTitle, NumItems = filterValue.NumItems, Id = filterValue.Id, Command = grouping ? new MethodDelegateCommand(() => NavigateToGroup(subVS, selectAttributeFilter)) : new MethodDelegateCommand(() => NavigateToSubView(subVS)) }; itemsList.Add(filterValueItem); if (filterValue.NumItems.HasValue) { totalNumItems += filterValue.NumItems.Value; } } if (_sortable) { Sorting.Sorting sorting = CurrentSorting; if (sorting != null) { itemsList.Sort((i1, i2) => sorting.Compare(i1.MediaItem, i2.MediaItem)); } } CollectionUtils.AddAll(items, itemsList); Display_Normal(items.Count, totalNumItems == 0 ? new int?() : totalNumItems); } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("AbstractFiltersScreenData: Error creating filter values list", e); Display_ItemsInvalid(); } UpdateOrRebuildView(items, createNewList); } finally { lock (_syncObj) _buildingList = false; } }
/// <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); }