Skip to content

Commit

Permalink
Merge pull request #5 from RadekVyM/dev
Browse files Browse the repository at this point in the history
SimpleShell 1.1.0
  • Loading branch information
RadekVyM authored Oct 24, 2022
2 parents 6821bff + e318491 commit 469ec61
Show file tree
Hide file tree
Showing 38 changed files with 1,232 additions and 249 deletions.
95 changes: 8 additions & 87 deletions docs/SimpleToolkit.SimpleShell/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ SimpleShell provides you with some bindable properties which simplify the creati
- `CurrentShellContent` - the currently selected `ShellContent`
- `ShellSections` - read-only list of all `ShellSection`s in the shell
- `ShellContents` - read-only list of all `ShellContent`s in the shell
- `RootPageOverlay` - you can use this property to set a view that will be displayed over all root pages (`ShellContent`s). This is well suited for tab bars, floating buttons, or flyouts that should be visible only on a root page

The code behind of the XAML sample above:

Expand Down Expand Up @@ -138,97 +139,17 @@ Output:

## Visual states

`SimpleShell` provides multiple groups of states.
`SimpleShell` provides multiple groups of visual states which help to define the shell appearance based on the current state of navigation. See [documentation](VisualStates.md) for more information.

### `ShellSection` states
## Transitions

States in the `SimpleShellSectionState.[ShellSection route]` format:
`SimpleShell` allows you to define custom transitions between pages during navigation:

```xml
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SimpleShellSectionStates">
<VisualState x:Name="SimpleShellSectionState.HomeTab">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Red"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="SimpleShellSectionState.SettingsTab">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Green"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
```

When a user navigates to a tab with a `HomeTab` route, the view named `tabBar` will have a red background, and when to a tab with a `SettingsTab` route, the view named `tabBar` will have a green background.

### `ShellContent` states

States in the `SimpleShellContentState.[ShellContent route]` format:

```xml
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SimpleShellContentStates">
<VisualState x:Name="SimpleShellContentState.HomePage">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Yellow"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="SimpleShellContentState.SettingsPage">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Blue"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
```

When a user navigates to a `ShellContent` with a `HomePage` route, the view named `tabBar` will have a yellow background, and when to a `ShellContent` with a `SettingsPage` route, the view named `tabBar` will have a blue background.

### Page type states

States in the `SimplePageState.[Page type name]` format:

```xml
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SimplePageStates">
<VisualState x:Name="SimplePageState.HomePage">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Purple"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="SimplePageState.SettingsPage">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Orange"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
```

When a user navigates to a `HomePage` page, the view named `tabBar` will have a purple background, and when to a `SettingsPage` page, the view named `tabBar` will have a orange background.

### Navigation stack states

When a user navigates to a page that is part of the shell hierarchy, `SimpleShell` goes to the `RootPage` state, otherwise `SimpleShell` goes to the `RegisteredPage` state:
<p align="center">
<img width="350" src="../images/windows_transitions.gif">
</p>

```xml
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SimplePageTypeStates">
<VisualState x:Name="SimplePageTypeState.RegisteredPage">
<VisualState.Setters>
<Setter TargetName="backButton" Property="Button.IsVisible" Value="true"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="SimplePageTypeState.RootPage">
<VisualState.Setters>
<Setter TargetName="backButton" Property="Button.IsVisible" Value="false"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
```
See [documentation](Transitions.md) for more information.

## Implementation details

Expand Down
149 changes: 149 additions & 0 deletions docs/SimpleToolkit.SimpleShell/Transitions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# `SimpleShell` page transitions

`SimpleShell` allows you to define custom transitions between pages during navigation.

## `SimpleShellTransition`

Each transition is represented by a `SimpleShellTransition` object which contains these read-only properties settable via its constructors:

- `Callback` - method that is called when progress of the transition changes. Progress of the transition is passed to the method through a parameter of type `SimpleShellTransitionArgs`
- `Starting` - method that is called when the transition starts
- `Finished` - method that is called when the transition finishes
- `Duration` - method returning duration of the transition
- `DestinationPageInFront` - method returning whether the destination page should be displayed in front of the origin page when navigating from one page to another

Each of these methods takes a object `SimpleShellTransitionArgs` as a parameter. Usefull information about currently running transition can be obtained from this object:

- `OriginPage` of type `VisualElement` - page from which the navigation is initiated
- `DestinationPage` of type `VisualElement` - destination page of the navigation
- `Progress` - progress of the transition. Number from 0 to 1
- `TransitionType` - type of the transition that is represented by `SimpleShellTransitionType` enumeration:
- `Switching` - new root page (`ShellContent`) is being set
- `Pushing` - new page is being pushed to the navigation stack
- `Popping` - existing page is being popped from the navigation stack

## Setting a transition

`SimpleShellTransition` can be set to any page via `SimpleShell.Transition` attached property. If you set a transition on your `SimpleShell` object, that transition will be used as the default transition for all pages.

When navigating from one page to another, **transition of the destination page is played**.

> Every `ShellContent` needs to be placed inside a `Tab` element to play the transition while navigating between two root pages.
### Extension methods

Setting transition can be simplified using several extension methods. These are headers of the methods:

```csharp
public static void SetTransition(
this Page page,
SimpleShellTransition transition)

public static void SetTransition(
this Page page,
Action<SimpleShellTransitionArgs> callback,
uint duration = 250,
Action<SimpleShellTransitionArgs> starting = null,
Action<SimpleShellTransitionArgs> finished = null,
bool destinationPageInFrontOnSwitching = true,
bool destinationPageInFrontOnPushing = true,
bool destinationPageInFrontOnPopping = true)

public static void SetTransition(
this Page page,
Action<SimpleShellTransitionArgs> callback,
Func<SimpleShellTransitionArgs, uint> duration = null,
Action<SimpleShellTransitionArgs> starting = null,
Action<SimpleShellTransitionArgs> finished = null,
Func<SimpleShellTransitionArgs, bool> destinationPageInFront = null)

public static void SetTransition(
this Page page,
Action<SimpleShellTransitionArgs> switchingCallback = null,
Action<SimpleShellTransitionArgs> pushingCallback = null,
Action<SimpleShellTransitionArgs> poppingCallback = null,
Func<SimpleShellTransitionArgs, uint> duration = null,
Action<SimpleShellTransitionArgs> starting = null,
Action<SimpleShellTransitionArgs> finished = null,
Func<SimpleShellTransitionArgs, bool> destinationPageInFront = null)
```

## Example

The default transition can be set, for example, in the constructor of your `AppShell`:

```csharp
public AppShell()
{
InitializeComponent();

Routing.RegisterRoute(nameof(ImagePage), typeof(ImagePage));

this.SetTransition(
callback: args =>
{
switch (args.TransitionType)
{
case SimpleShellTransitionType.Switching:
args.OriginPage.Opacity = 1 - args.Progress;
args.DestinationPage.Opacity = args.Progress;
break;
case SimpleShellTransitionType.Pushing:
args.DestinationPage.TranslationX = (1 - args.Progress) * args.DestinationPage.Width;
break;
case SimpleShellTransitionType.Popping:
args.OriginPage.TranslationX = args.Progress * args.OriginPage.Width;
break;
}
},
finished: args =>
{
args.OriginPage.Opacity = 1;
args.OriginPage.TranslationX = 1;
args.DestinationPage.Opacity = 1;
args.DestinationPage.TranslationX = 1;
},
destinationPageInFront: args => args.TransitionType switch {
SimpleShellTransitionType.Popping => false,
_ => true
},
duration: args => args.TransitionType switch {
SimpleShellTransitionType.Switching => 500,
_ => 350
});
}
```

Output:

<p align="center">
<img width="350" src="../images/windows_transitions.gif">
</p>

Transitions can be set on each page individually. Default transition will be overridden if it is already set:

```csharp
public ImagePage()
{
InitializeComponent();

this.SetTransition(
callback: args =>
{
args.OriginPage.TranslationY = args.Progress * (-args.OriginPage.Height);
args.DestinationPage.TranslationY = (1 - args.Progress) * (args.DestinationPage.Height);
},
500,
finished: args =>
{
args.OriginPage.TranslationY = 0;
args.DestinationPage.TranslationY = 0;
});
}
```

Output:

<p align="center">
<img width="350" src="../images/windows_transitions_2.gif">
</p>
93 changes: 93 additions & 0 deletions docs/SimpleToolkit.SimpleShell/VisualStates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
## Visual states

`SimpleShell` provides multiple groups of states.

### `ShellSection` states

States in the `SimpleShellSectionState.[ShellSection route]` format:

```xml
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SimpleShellSectionStates">
<VisualState x:Name="SimpleShellSectionState.HomeTab">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Red"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="SimpleShellSectionState.SettingsTab">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Green"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
```

When a user navigates to a tab with a `HomeTab` route, the view named `tabBar` will have a red background, and when to a tab with a `SettingsTab` route, the view named `tabBar` will have a green background.

### `ShellContent` states

States in the `SimpleShellContentState.[ShellContent route]` format:

```xml
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SimpleShellContentStates">
<VisualState x:Name="SimpleShellContentState.HomePage">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Yellow"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="SimpleShellContentState.SettingsPage">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Blue"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
```

When a user navigates to a `ShellContent` with a `HomePage` route, the view named `tabBar` will have a yellow background, and when to a `ShellContent` with a `SettingsPage` route, the view named `tabBar` will have a blue background.

### Page type states

States in the `SimplePageState.[Page type name]` format:

```xml
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SimplePageStates">
<VisualState x:Name="SimplePageState.HomePage">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Purple"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="SimplePageState.SettingsPage">
<VisualState.Setters>
<Setter TargetName="tabBar" Property="View.Background" Value="Orange"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
```

When a user navigates to a `HomePage` page, the view named `tabBar` will have a purple background, and when to a `SettingsPage` page, the view named `tabBar` will have a orange background.

### Navigation stack states

When a user navigates to a page that is part of the shell hierarchy, `SimpleShell` goes to the `RootPage` state, otherwise `SimpleShell` goes to the `RegisteredPage` state:

```xml
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SimplePageTypeStates">
<VisualState x:Name="SimplePageTypeState.RegisteredPage">
<VisualState.Setters>
<Setter TargetName="backButton" Property="Button.IsVisible" Value="true"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="SimplePageTypeState.RootPage">
<VisualState.Setters>
<Setter TargetName="backButton" Property="Button.IsVisible" Value="false"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
```
Binary file added docs/images/windows_transitions.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/windows_transitions_2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static partial class WindowExtensions
/// <returns>The builder.</returns>
public static MauiAppBuilder DisplayContentBehindBars(this MauiAppBuilder builder)
{
// TODO: See https://github.com/dotnet/maui/pull/10273
return builder;
}
}
Expand Down
15 changes: 11 additions & 4 deletions src/SimpleToolkit.Playground/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
namespace SimpleToolkit.SimpleShell.Playground
{
internal enum AppShellType
{
Normal, Sample, Playground
}

public partial class App : Application
{
public App()
{
InitializeComponent();

if (MauiProgram.UseSimpleShell)
MainPage = new SimpleAppShell();
else
MainPage = new NormalAppShell();
MainPage = MauiProgram.UsedAppShell switch
{
AppShellType.Normal => new NormalAppShell(),
AppShellType.Sample => new SampleAppShell(),
_ => new SimpleAppShell()
};
}
}
}
Loading

0 comments on commit 469ec61

Please sign in to comment.