public void AddMatch(string shellSegment, string userSegment, object node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } switch (node) { case ShellUriHandler.GlobalRouteItem globalRoute: if (globalRoute.IsFinished) { _globalRouteMatches.Add(globalRoute.SourceRoute); } break; case Shell shell: Shell = shell; break; case ShellItem item: Item = item; break; case ShellSection section: Section = section; if (Item == null) { Item = Section.Parent as ShellItem; _fullSegments.Add(Item.Route); } break; case ShellContent content: Content = content; if (Section == null) { Section = Content.Parent as ShellSection; _fullSegments.Add(Section.Route); } if (Item == null) { Item = Section.Parent as ShellItem; _fullSegments.Insert(0, Item.Route); } break; } // if shellSegment == userSegment it means the implicit route is part of the request if (!Routing.IsImplicit(shellSegment) || shellSegment == userSegment) { _matchedSegments.Add(shellSegment); } _fullSegments.Add(shellSegment); }
public Uri GetUri() { List<string> paths = new List<string>(); paths.Add(Shell.RouteHost); paths.Add(Shell.Route); if (Item != null && !Routing.IsImplicit(Item)) paths.Add(Item.Route); if (Section != null && !Routing.IsImplicit(Section)) paths.Add(Section.Route); if (Content != null && !Routing.IsImplicit(Content)) paths.Add(Content.Route); string uri = String.Join(_pathSeparator, paths); return new Uri($"{Shell.RouteScheme}://{uri}"); }
internal static List <string> CollapsePath( string[] myRoute, IEnumerable <string> currentRouteStack, bool removeUserDefinedRoute) { var localRouteStack = currentRouteStack.ToList(); for (var i = localRouteStack.Count - 1; i >= 0; i--) { var route = localRouteStack[i]; if (Routing.IsImplicit(route) || (Routing.IsDefault(route) && removeUserDefinedRoute)) { localRouteStack.RemoveAt(i); } } var paths = myRoute.ToList(); // collapse similar leaves int walkBackCurrentStackIndex = -1; if (paths.Count > 0) { walkBackCurrentStackIndex = localRouteStack.IndexOf(paths[0]); } while (paths.Count > 1 && walkBackCurrentStackIndex >= 0) { if (localRouteStack.Count <= walkBackCurrentStackIndex) { break; } if (paths[0] == localRouteStack[walkBackCurrentStackIndex]) { paths.RemoveAt(0); } else { break; } walkBackCurrentStackIndex++; } return(paths); }
public override void Add(ShellItem item) { /* * This is purely for the case where a user is only specifying Tabs at the highest level * <shell> * <tab></tab> * <tab></tab> * </shell> * */ if (Routing.IsImplicit(item) && item is TabBar ) { int i = Count - 1; if (i >= 0 && this[i] is TabBar && Routing.IsImplicit(this[i])) { (this[i] as ShellItem).Items.Add(item.Items[0]); return; } } Inner.Add(item); }
static void SearchPath( object node, RouteRequestBuilder currentMatchedPath, string[] segments, List <RouteRequestBuilder> possibleRoutePaths, int depthToStart, int myDepth = -1, NodeLocation currentLocation = null, bool ignoreGlobalRoutes = true) { if (node is GlobalRouteItem && ignoreGlobalRoutes) { return; } ++myDepth; currentLocation = currentLocation ?? new NodeLocation(); currentLocation.SetNode(node); IEnumerable items = null; if (depthToStart > myDepth) { items = GetItems(node); if (items == null) { return; } foreach (var nextNode in items) { SearchPath(nextNode, null, segments, possibleRoutePaths, depthToStart, myDepth, currentLocation, ignoreGlobalRoutes); } return; } string shellSegment = GetRoute(node); string userSegment = null; if (currentMatchedPath == null) { userSegment = segments[0]; } else { userSegment = currentMatchedPath.NextSegment; } if (userSegment == null) { return; } RouteRequestBuilder builder = null; if (shellSegment == userSegment || Routing.IsImplicit(shellSegment)) { if (currentMatchedPath == null) { builder = new RouteRequestBuilder(shellSegment, userSegment, node, segments); } else { builder = new RouteRequestBuilder(currentMatchedPath); builder.AddMatch(shellSegment, userSegment, node); } if (!Routing.IsImplicit(shellSegment) || shellSegment == userSegment) { possibleRoutePaths.Add(builder); } } items = GetItems(node); if (items == null) { return; } foreach (var nextNode in items) { SearchPath(nextNode, builder, segments, possibleRoutePaths, depthToStart, myDepth, currentLocation, ignoreGlobalRoutes); } }
public static void ApplyQueryAttributes(Element element, IDictionary <string, string> query, bool isLastItem, bool isPopping) { string prefix = ""; if (!isLastItem) { var route = Routing.GetRoute(element); if (string.IsNullOrEmpty(route) || Routing.IsImplicit(route)) { return; } prefix = route + "."; } //if the lastItem is implicitly wrapped, get the actual ShellContent if (isLastItem) { if (element is IShellItemController shellitem && shellitem.GetItems().FirstOrDefault() is ShellSection section) { element = section; } if (element is IShellSectionController shellsection && shellsection.GetItems().FirstOrDefault() is ShellContent content) { element = content; } if (element is ShellContent shellcontent && shellcontent.Content is Element e) { element = e; } } if (!(element is BaseShellItem baseShellItem)) { baseShellItem = element?.Parent as BaseShellItem; } //filter the query to only apply the keys with matching prefix var filteredQuery = new Dictionary <string, string>(query.Count); foreach (var q in query) { if (!q.Key.StartsWith(prefix, StringComparison.Ordinal)) { continue; } var key = q.Key.Substring(prefix.Length); if (key.Contains(".")) { continue; } filteredQuery.Add(key, q.Value); } if (baseShellItem is ShellContent) { baseShellItem.ApplyQueryAttributes(MergeData(element, filteredQuery, isPopping)); } else if (isLastItem) { element.SetValue(ShellContent.QueryAttributesProperty, MergeData(element, query, isPopping)); } IDictionary <string, string> MergeData(Element shellElement, IDictionary <string, string> data, bool isPopping) { if (!isPopping) { return(data); } var returnValue = new Dictionary <string, string>(data); var existing = (IDictionary <string, string>)shellElement.GetValue(ShellContent.QueryAttributesProperty); if (existing == null) { return(data); } foreach (var datum in existing) { if (!returnValue.ContainsKey(datum.Key)) { returnValue[datum.Key] = datum.Value; } } return(returnValue); } }
public static ShellNavigationState GetNavigationState(ShellItem shellItem, ShellSection shellSection, ShellContent shellContent, IReadOnlyList <Page> sectionStack, IReadOnlyList <Page> modalStack) { List <string> routeStack = new List <string>(); bool stackAtRoot = sectionStack == null || sectionStack.Count <= 1; bool hasUserDefinedRoute = (Routing.IsUserDefined(shellItem)) || (Routing.IsUserDefined(shellSection)) || (Routing.IsUserDefined(shellContent)); if (shellItem != null) { var shellItemRoute = shellItem.Route; routeStack.Add(shellItemRoute); if (shellSection != null) { var shellSectionRoute = shellSection.Route; routeStack.Add(shellSectionRoute); if (shellContent != null) { var shellContentRoute = shellContent.Route; routeStack.Add(shellContentRoute); } if (!stackAtRoot) { for (int i = 1; i < sectionStack.Count; i++) { var page = sectionStack[i]; routeStack.AddRange(CollapsePath(Routing.GetRoute(page), routeStack, hasUserDefinedRoute)); } } if (modalStack != null && modalStack.Count > 0) { for (int i = 0; i < modalStack.Count; i++) { var topPage = modalStack[i]; routeStack.AddRange(CollapsePath(Routing.GetRoute(topPage), routeStack, hasUserDefinedRoute)); for (int j = 1; j < topPage.Navigation.NavigationStack.Count; j++) { routeStack.AddRange(CollapsePath(Routing.GetRoute(topPage.Navigation.NavigationStack[j]), routeStack, hasUserDefinedRoute)); } } } } } if (routeStack.Count > 0) { routeStack.Insert(0, "/"); } return(new ShellNavigationState(String.Join("/", routeStack), true)); List <string> CollapsePath( string myRoute, IEnumerable <string> currentRouteStack, bool userDefinedRoute) { var localRouteStack = currentRouteStack.ToList(); for (var i = localRouteStack.Count - 1; i >= 0; i--) { var route = localRouteStack[i]; if (Routing.IsImplicit(route) || (Routing.IsDefault(route) && userDefinedRoute)) { localRouteStack.RemoveAt(i); } } var paths = myRoute.Split('/').ToList(); // collapse similar leaves int walkBackCurrentStackIndex = localRouteStack.Count - (paths.Count - 1); while (paths.Count > 1 && walkBackCurrentStackIndex >= 0) { if (paths[0] == localRouteStack[walkBackCurrentStackIndex]) { paths.RemoveAt(0); } else { break; } walkBackCurrentStackIndex++; } return(paths); } }
bool UpdateFlyoutGroupings() { // The idea here is to create grouping such that the Flyout would // render correctly if it renderered each item in the groups in order // but put a line between the groups. This is needed because our grouping can // actually go 3 layers deep. // Ideally this lets us control where lines are drawn in the core code // just by changing how we generate these groupings var result = new List <List <Element> >(); var currentGroup = new List <Element>(); foreach (var shellItem in ShellController.GetItems()) { if (!ShowInFlyoutMenu(shellItem)) { continue; } if (Routing.IsImplicit(shellItem) || shellItem.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems) { if (shellItem.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems) { IncrementGroup(); } foreach (var shellSection in (shellItem as IShellItemController).GetItems()) { if (!ShowInFlyoutMenu(shellSection)) { continue; } var shellContents = ((IShellSectionController)shellSection).GetItems(); if (Routing.IsImplicit(shellSection) || shellSection.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems) { foreach (var shellContent in shellContents) { if (!ShowInFlyoutMenu(shellContent)) { continue; } currentGroup.Add(shellContent); if (shellContent == shellSection.CurrentItem) { AddMenuItems(shellContent.MenuItems); } } if (shellSection.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems) { IncrementGroup(); } } else { if (!(shellSection.Parent is TabBar)) { if (Routing.IsImplicit(shellSection) && shellContents.Count == 1) { if (!ShowInFlyoutMenu(shellContents[0])) { continue; } currentGroup.Add(shellContents[0]); } else { currentGroup.Add(shellSection); } } // If we have only a single child we will also show the items menu items if (shellContents.Count == 1 && shellSection == shellItem.CurrentItem && shellSection.CurrentItem.MenuItems.Count > 0) { AddMenuItems(shellSection.CurrentItem.MenuItems); } } } if (shellItem.FlyoutDisplayOptions == FlyoutDisplayOptions.AsMultipleItems) { IncrementGroup(); } } else { if (!(shellItem is TabBar)) { currentGroup.Add(shellItem); } } } IncrementGroup(); // If the flyout groupings haven't changed just return // the same instance so the caller knows it hasn't changed // at a later point this will all get converted to an observable collection if (_lastGeneratedFlyoutItems?.Count == result.Count) { bool hasChanged = false; for (var i = 0; i < result.Count && !hasChanged; i++) { var topLevelNew = result[i]; var topLevelPrevious = _lastGeneratedFlyoutItems[i]; if (topLevelNew.Count != topLevelPrevious.Count) { hasChanged = true; break; } for (var j = 0; j > topLevelNew.Count; j++) { if (topLevelNew[j] != topLevelPrevious[j]) { hasChanged = true; break; } } } if (!hasChanged) { return(false); } } _lastGeneratedFlyoutItems = result; return(true); bool ShowInFlyoutMenu(BindableObject bo) { if (bo is MenuShellItem msi) { return(Shell.GetFlyoutItemIsVisible(msi.MenuItem)); } return(Shell.GetFlyoutItemIsVisible(bo)); } void AddMenuItems(MenuItemCollection menuItems) { foreach (var item in menuItems) { if (ShowInFlyoutMenu(item)) { currentGroup.Add(item); } } } void IncrementGroup() { if (currentGroup.Count > 0) { result.Add(currentGroup); currentGroup = new List <Element>(); } } }