Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[WiP] .NET MAUI Shell Improvements #10804

Closed
PureWeen opened this issue May 20, 2020 · 12 comments
Closed

[WiP] .NET MAUI Shell Improvements #10804

PureWeen opened this issue May 20, 2020 · 12 comments

Comments

@PureWeen
Copy link
Contributor

PureWeen commented May 20, 2020

Mission statements

Make it simple and straightforward for new developers to get a complete app experience that is properly structured, uses the right elements, with very little effort and a clear path to being good by default.

Without this, we force our users to learn quite a lot about Forms to properly structure their first application, or rely on generated code like templates, without a chance to upgrade the experience as time goes by,

This is both a batteries included approach, as well as an opinionated approach to make our users succeed by default.

More explicit declaration of different areas of an app

The current Shell model is more Storyboard focused. So the user specifies everything that could make up an app into Shell.

The following Xaml will render a single tabbar without a Flyout Menu

<TabBar = "Login"/>
<FlyoutItem Route="CustomerProfile">
<TabBar Route="AdminProfile" />

Will there be two TabBars? Will there be a FlyoutItem and a TabBar?

The next version of Shell will shift to having a tighter connection between what's in the Shell and what you see

<App StartingRoute="Login">
    <App.Routes>
        <Route = "Login">
            <TabBar Title="Login" />
        </Route> 
        <Route="CustomerProfile">
            <ContentPage />
        </Route>
        <Route="AdminProfile">
            <TabBar FlyoutDisplayOptions="AsMultipleItems" >
             </TabBar>
        </Route>
    </App.Routes>

App with no tabs or flyout

Example

<App>
    <App.Routes>
        <Route = "Foo">
            <ShellContent>
        </Route>
        <Route="Login">
            <MyLoginPage/>
        </Route>
    </App.Routes>
</App>

Enable Deep Tab Nesting Scenarios

Example

<App>
    <App.Routes>
        <Route = "Foo">
            <TabBar Location="Bottom"  IsNavigationRoot="true">
                <TabBar Location="Top" Name="Your Library">
                    <TabBar Location="Top" Name="Music" Route = "Music">
                        <Tab Name="PlayLists" Route="Login">
                        <Tab Name="Artists">
                        <Tab Name="Albums">
                        <NavigationButton Route="Foo">
                    </TabBar>
                    <TabBar Location="Top" Name="Podcasts" Route = "Podcasts">
                        <Tab Name="Episodes">
                        <Tab Name="Downloads">
                        <Tab Name="Shows">
                    </TabBar>
                </TabBar>
                <Tab Name="Home" />
                <Tab Name="Search" />
            </TabBar>
        </Route>
        <Route="Login">
            <MyLoginPage/>
        </Route>
    </App.Routes>

     <FlyoutNavigation  />
</App>

Nested Tabs / Tabs

Nested tabs will all be realized via the TabView control (#10773) and we will also allow users to swap out native implementations with the TabView Control

Deeper Flyout Customization

NavigationItem

public class NavigationItem
{
     public string Route {get; set;}  
     public ICommand Command {get; set;}
     public ShellElement { get;  set;}
     public string Title {get; set;}
     public ImageSource Icon {get; set;}

}

NavigationList

By default the NavigationList will use an ItemSource generated from the currently active App.Route based on the normal Shell Parameters. But users can specify a totally customized list if they would like to.

public class NavigationList
{
     public IList<INavigationItem> NavigationItems {get; set;}
     public DataTemplate ItemTemplate {get;set;}
     public DatatTemplate  ItemTemplateSelector {get;set;}
}
public class FlyoutNavigation  : NavigationList
{
}

Customized Flyout

        <FlyoutNavigation>
            <FlyoutNavigation.ItemSource>
                <NavigationItem Route="Animals">
                    <NavigationItem Route="Monkey" />
                    <NavigationItem Route="Rabbits" />
                </NavigationItem>
                <NavigationItem Route="Music" />
                <NavigationItem Route="Podcasts" />
            </FlyoutNavigation.ItemSource>
        </FlyoutNavigation>

Enable ShellElement navigation scenarios

Currently with shell you can only push ContentPages but the user should be able to push everything and anything.

This will also allow you to better articulate at what level you want a navigation to occur.

Right now whenever you push a ContentPage the NavigationStack is always relative to a bottom tab. Once we enable shell types to be pushable those can push at different levels

  • GotoAsync("ShellContent")
    • This will set the NavigationContainer to the first explicit parent. So if you have top tabs it'll be relative to the top tab.
  • GotoAsync("Tab")
    • This will Push how things are currently pushed. The navigation stack will be relative to the bottom tab
  • GotoAsync("FlyoutItem")
    • This will push an entirely new main layout onto the stack

More Lifecycle hooks and structure to better enable customization and MVVM frameworks

#5166

Ongoing work here

#6764

This will enable people to tap into literally every part of shell. We can even use this to let people more expressively navigate

For example a Path is now defined by the following concrete class

public class PathPart
{
    public string Path { get; }

    // in theory you could store a bindingcontext here for tombstoning        
    public IEnumerable<KeyValuePair<string, object>> Parameters { get; }
    public Element ShellPart { get; }

    // This describes how you will transition to and away from this Path Part
    ITransitionPlan Transition { get; }

    // how am I presented? Modally? as a page?W
    PresentationMode Presentation { get;  }

so we could add an overload for GoToAsync that takes a PathPart which would let people articulate more complex parameters

Considerations

Things Shell does really well that we should maintain

  • Performance
    • Because shell has an opinionated structure it's able to be leaner than non Shell apps
  • A lot of Functional UI generated from very minimal code
  • Simplified Theming
  • Ability to start with a lot of behavior and then customize from there. Start from a full app and then customize vs having to build everything up.
    • BackButtonBehavior
    • Tabs are generated from ShellStructures
  • Simplified Navigation
    • User doesn't have to think about navigation pages
    • Shell has navigating/navigated events that all navigation filters through
      • This allows users to intercept and cancel ALL navigation. Being able to intercept navigation is one of our largest feature requests. With Shell you can cancel hardware/software navigation. Current Forms can't do this. Current Forms has no centralized navigation hooks.
    • Passing data during Navigation
  • Search Handler
    • The search handler isn't fully baked but it follows along with the idea that it's fully configured and functional and then you just add an ItemSource and it has Search Events

Missing features of shell

  • abstract names mixed with concrete names are confusing
    • The shell structure itself is somewhat a barrier of entry.
  • lack of scenario support is frustrating
    • The thing you have to keep in mind with Shell is that it's a projection of UI against a scenario. You describe the scenario of your app and this generates a UI. You then customize that UI.
    • Expanding no this idea here [Spec] Shell Scenarios #8528
  • lack of customization is a problem (how to style tabs, style flyout, tweak animations, RTL)
    • This isn't directly a Shell problem but Shell is supposed to enable these scenarios.
    • Do we still want transitions to be native? or do we want them to be xplat?
  • devs cannot achieve the navigation they require (nested tabs or tabs + flyout etc)
    • Nested tabs. Is the solution here Javier's tabs?
  • devs are frustrated on how to define routes to pages not visible
    • Declare routes inside Xaml some how not that crazy to overcome
@PureWeen PureWeen added t/bug 🐛 s/unverified New report that has yet to be verified labels May 20, 2020
@rmarinho rmarinho added p/Android p/iOS 🍎 t/enhancement ➕ and removed s/unverified New report that has yet to be verified labels May 21, 2020
@pictos
Copy link
Contributor

pictos commented May 21, 2020

@PureWeen I want to add some items, that I think should be good to take care of.

Deeper Flyout Customization

Navigation

  • Would be great if we can handle Navigated and Navigating in an async way. Maybe we can use a Func<Targs, Task> or creating other method to handle that;
  • An in-the-box way to pass complex objects in the navigation, today it's easy to do that with a custom NavigationService implementation, but if we can have this by default it's great also. We can use the same approach as Android (e.g. input.Extras);

Shell.TitleView

  • Some apps require a custom header, with custom size and elements, that way we can improve the Shell.TitleView to delivery. For example, today the Height of the TitleView has a maximum value.

If I think in something else I'll update this comment.

@PureWeen
Copy link
Contributor Author

PureWeen commented May 21, 2020

Deeper Flyout Customization

Hopefully I'll have the work done I've been doing on my streams which will enable all of this!!
Do you have comments on what I've defined here in the spec around it?

Navigation

The hooks that will come about as part of this PR
#5166

Will make all the lifecycle parts async

Maybe we'll add some sort of Async Token to the existing navigating/navigated events?

Shell.TitleView

Yes! Once I get the Flyout more customizable I'll probably switch to getting this implemented
#9107

I think it won't be too hard... 🤞

And then I'd like to extend @jsuarezruiz 's appbar so you can just set it into the titleview and it'll just take over

@davidortinau davidortinau changed the title [WiP] Pre Maui Shell Improvements [WiP] Pre .NET MAUI Shell Improvements May 21, 2020
@pictos
Copy link
Contributor

pictos commented May 23, 2020

Do you have comments on what I've defined here in the spec around it?

I don't think so. It is just that I didn't see an API spec, so I thought that spec doesn't exist at all.

Maybe we'll add some sort of Async Token to the existing navigating/navigated events?

Can you provide an example? I don't know how it looks like

I think it won't be too hard... 🤞

If it's hard we can talk and figure out a way to make it work❣️

Do you have an ETA for the @jsuarezruiz's appbar? And for merge it into Shell?

@timahrentlov
Copy link

timahrentlov commented Jun 3, 2020

What if you don't want any tabs or flyouts and just want to roll with your own mainpage - but still want to be able to use route navigation, parameters, constructor injection, etc?

Is that covered by the envisioned improvements? I can't tell.

@PureWeen
Copy link
Contributor Author

PureWeen commented Jun 4, 2020

@pictos

Can you provide an example? I don't know how it looks like

Not exactly this but something like this
https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.background.backgroundtaskdeferral?view=winrt-19041

Or the arg could just have a property that's by default null but if you want to defer the navigating you can set it to a task. The calling code will then await that task and once it's completed continue

there's a few ways to approach it

Do you have an ETA for the @jsuarezruiz's appbar? And for merge it into Shell?

Soonish :-) @jsuarezruiz is a bit busy this week working on drawing/brushes/triage but we'll hopefully have some working versions of these things everyone can play with.

What if you don't want any tabs or flyouts and just want to roll with your own mainpage - but still want to be able to use route navigation, parameters, constructor injection, etc?

Is that covered by the envisioned improvements? I can't tell.

@timahrentlov

I added a basic sample

<App>
    <App.Routes>
        <Route = "Foo">
            <ShellContent>
        </Route>
        <Route="Login">
            <MyLoginPage/>
        </Route>
    </App.Routes>
</App>

So for that you would just not define any tabs or flyouts

@timahrentlov
Copy link

@PureWeen Thanks!

@PureWeen PureWeen changed the title [WiP] Pre .NET MAUI Shell Improvements [WiP] .NET MAUI Shell Improvements Jul 17, 2020
@Jakar510
Copy link

Jakar510 commented Aug 2, 2020

+1

@samhouts samhouts added this to the 5.0.0 milestone Aug 13, 2020
@jbe2277
Copy link

jbe2277 commented Aug 31, 2020

@jsuarezruiz
Copy link
Contributor

@PureWeen Should/can we move this to .NET MAUI?

@nogginbox
Copy link

Does this ticket include looking at adding DI support to shell. I'm getting quite frustrated at the lack of guidance on how to do DI with shell and I'm not sure it is possible.

@pictos
Copy link
Contributor

pictos commented Nov 24, 2021

@nogginbox yes, you can follow the progress on this PR

@jfversluis
Copy link
Member

I think a lot of this has already moved to the .NET MAUI repo. In any case, this won't make it's way into Xamarin.Forms anymore. I will see to it that we reevaluate all the things in here for .NET MAUI, but closing this here for now :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants