Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi Window Support #2811

Merged
merged 34 commits into from
Nov 2, 2021
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5ea64ef
Initial pass at multiwindow on Catalyst
Redth Oct 1, 2021
7f99a32
Pass some blank bundle state for now
Redth Oct 1, 2021
1490d61
Tweak dictionary lookups to avoid runtime ex
Redth Oct 1, 2021
2d2abfa
Add a button to test new window for now
Redth Oct 1, 2021
cc39dc3
Add state from scene connection options user activities
Redth Oct 1, 2021
ee61cf9
Windows
mattleibow Oct 1, 2021
b0f29a9
Make a new Viewmodel instead of reusing
Redth Oct 1, 2021
28253be
Merge branch 'dev-multi-window' of https://github.com/dotnet/maui int…
Redth Oct 1, 2021
accea16
Use the better app instance api
Redth Oct 2, 2021
3b6b0e5
Merge remote-tracking branch 'origin/main' into dev-multi-window
mattleibow Oct 6, 2021
d7dde0a
- push the correct page that's wrapping mainpage
PureWeen Oct 12, 2021
11c0676
- custom navigation page
PureWeen Oct 12, 2021
675c33e
Merge remote-tracking branch 'origin/main' into dev-multi-window
mattleibow Oct 16, 2021
1a157bb
enable experimental builds
mattleibow Oct 16, 2021
bae88bc
Merge remote-tracking branch 'origin/main' into dev-multi-window
mattleibow Oct 16, 2021
ac6f9b4
update things
mattleibow Oct 16, 2021
e83933b
Move things to the handler (windows ed)
mattleibow Oct 16, 2021
37c09c1
Android and Windows are mostly done
mattleibow Oct 17, 2021
de52009
More improvements and consistency
mattleibow Oct 17, 2021
2509f09
Don't reopen windows that have no saved data
mattleibow Oct 17, 2021
feaec30
Fix the build, i think
mattleibow Oct 17, 2021
b88933e
revrt ths
mattleibow Oct 17, 2021
a51f8fb
Merge remote-tracking branch 'origin/main' into dev-multi-window
mattleibow Oct 20, 2021
ca49d84
Merge remote-tracking branch 'origin/main' into dev-multi-window
mattleibow Oct 20, 2021
02aac67
Merge branch 'release/6.0.1xx-preview10' into dev-multi-window
mattleibow Oct 26, 2021
84e8263
Merge branch 'main' into dev-multi-window
Redth Nov 1, 2021
bb3d301
update version
mattleibow Nov 1, 2021
8f56899
Update the test stubs
mattleibow Nov 1, 2021
5bd507d
and that
mattleibow Nov 1, 2021
f085976
Launch side-by-side
mattleibow Nov 1, 2021
dbfd740
guard
mattleibow Nov 1, 2021
97e5d31
Merge remote-tracking branch 'origin/main' into dev-multi-window
mattleibow Nov 2, 2021
fa20cc1
Make this nullable
mattleibow Nov 2, 2021
a4f0012
Merge remote-tracking branch 'origin/main' into dev-multi-window
mattleibow Nov 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,26 @@
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>__MAUI_DEFAULT_SCENE_CONFIGURATION__</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>NSUserActivityTypes</key>
<array>
<string>com.microsoft.maui.sample</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Foundation;
using UIKit;
using Microsoft.Maui;

namespace Maui.Controls.Sample
{
[Register("SceneDelegate")]
public class SceneDelegate : MauiUISceneDelegate
{


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,26 @@
<string>Assets.xcassets/appicon.appiconset</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Access to your location is required for cool things to happen!</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>__MAUI_DEFAULT_SCENE_CONFIGURATION__</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>NSUserActivityTypes</key>
<array>
<string>com.microsoft.maui.sample.default</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -1,59 +1,13 @@
using Foundation;
using UIKit;
using Microsoft.Maui;

namespace Maui.Controls.Sample
{
[Register("SceneDelegate")]
public class SceneDelegate : UIResponder, IUIWindowSceneDelegate
public class SceneDelegate : MauiUISceneDelegate
{

[Export("window")]
public UIWindow Window { get; set; }

[Export("scene:willConnectToSession:options:")]
public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see UIApplicationDelegate `GetConfiguration` instead).
}

[Export("sceneDidDisconnect:")]
public void DidDisconnect(UIScene scene)
{
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see UIApplicationDelegate `DidDiscardSceneSessions` instead).
}

[Export("sceneDidBecomeActive:")]
public void DidBecomeActive(UIScene scene)
{
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}

[Export("sceneWillResignActive:")]
public void WillResignActive(UIScene scene)
{
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}

[Export("sceneWillEnterForeground:")]
public void WillEnterForeground(UIScene scene)
{
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}

[Export("sceneDidEnterBackground:")]
public void DidEnterBackground(UIScene scene)
{
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}

}
}
11 changes: 6 additions & 5 deletions src/Controls/samples/Controls.Sample/Pages/MainPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,19 @@
Source="header_background"/>
<Grid
RowSpacing="0"
Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
Grid.Row="0"
RowDefinitions="Auto,*,Auto">
<Label
Text=".NET MAUI"
Style="{StaticResource TitleStyle}"/>
<Label
Grid.Row="1"
Text="An open-source framework for building iOS, Android, macOS and Windows apps"
Style="{StaticResource SubTitleStyle}"/>
<Button
Grid.Row="2"
Text="One more window"
Clicked="ShowNewWindow" />
</Grid>
<!-- SECTIONS -->
<Grid
Expand Down
14 changes: 14 additions & 0 deletions src/Controls/samples/Controls.Sample/Pages/MainPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
using System;
using Maui.Controls.Sample.ViewModels;
using Microsoft.Maui.Controls;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Maui.Controls.Sample.Pages
{
public partial class MainPage
{
IServiceProvider _services;
MainViewModel _viewModel;

public MainPage(IServiceProvider services, MainViewModel viewModel)
{
InitializeComponent();

BindingContext = viewModel;

_services = services;
_viewModel = viewModel;
}

void ShowNewWindow(object sender, EventArgs e)
{
var mvm = _services.GetService<MainViewModel>();
Application.Current.OpenWindow(new Window(new CustomNavigationPage(_services, mvm)));
}
}
}
14 changes: 14 additions & 0 deletions src/Controls/src/Core/BackgroundingEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace Microsoft.Maui.Controls
{
public class BackgroundingEventArgs : EventArgs
{
public BackgroundingEventArgs(IPersistedState state)
{
State = state;
}

public IPersistedState State { get; set; }
}
}
32 changes: 32 additions & 0 deletions src/Controls/src/Core/HandlerImpl/Application.Impl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ namespace Microsoft.Maui.Controls
{
public partial class Application : IApplication
{
const string MauiWindowIdKey = "__MAUI_WINDOW_ID__";

readonly List<Window> _windows = new();
readonly Dictionary<string, Window> _requestedWindows = new();
ILogger<Application>? _logger;

ILogger<Application>? Logger =>
Expand All @@ -21,6 +24,15 @@ public partial class Application : IApplication
IWindow IApplication.CreateWindow(IActivationState activationState)
{
Window? window = null;

// try get the window that is pending
if (activationState.State?.TryGetValue(MauiWindowIdKey, out var requestedWindowId) ?? false)
{
if (requestedWindowId != null && _requestedWindows.TryGetValue(requestedWindowId, out var w))
window = w;
}

// create a new one if there is no pending windows
if (window == null)
{
window = CreateWindow(activationState);
Expand All @@ -39,6 +51,26 @@ IWindow IApplication.CreateWindow(IActivationState activationState)
return window;
}

void IApplication.OpenWindow(IWindow window)
{
if (window is Window cwindow)
OpenWindow(cwindow);
}

public virtual void OpenWindow(Window window)
{
var id = Guid.NewGuid().ToString();

_requestedWindows[id] = window;

var state = new PersistedState
{
[MauiWindowIdKey] = id
};

Handler?.Invoke(nameof(IApplication.OpenWindow), new OpenWindowRequest(State: state));
}

public void ThemeChanged()
{
Current?.TriggerThemeChanged(new AppThemeChangedEventArgs(Current.RequestedTheme));
Expand Down
8 changes: 8 additions & 0 deletions src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,15 @@ public Window(Page page)
public event EventHandler? Deactivated;
public event EventHandler? Stopped;
public event EventHandler? Destroying;
public event EventHandler<BackgroundingEventArgs>? Backgrounding;

protected virtual void OnCreated() { }
protected virtual void OnResumed() { }
protected virtual void OnActivated() { }
protected virtual void OnDeactivated() { }
protected virtual void OnStopped() { }
protected virtual void OnDestroying() { }
protected virtual void OnBackgrounding(IPersistedState state) { }

protected override void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
Expand Down Expand Up @@ -213,6 +215,12 @@ void IWindow.Resumed()
Application?.SendResume();
}

void IWindow.Backgrounding(IPersistedState state)
{
Backgrounding?.Invoke(this, new BackgroundingEventArgs(state));
OnBackgrounding(state);
}

// Currently this returns MainPage + ModalStack
// Depending on how we want this to show up inside LVT
// we might want to change this to only return the currently visible page
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public IWindow CreateWindow(IActivationState activationState)
throw new System.NotImplementedException();
}

public void OpenWindow(IWindow window)
{
throw new System.NotImplementedException();
}

public void ThemeChanged() { }
}
}
2 changes: 2 additions & 0 deletions src/Core/src/Core/IApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public interface IApplication : IElement
/// <returns>The created window.</returns>
IWindow CreateWindow(IActivationState activationState);

void OpenWindow(IWindow window);

/// <summary>
/// Notify a theme change.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/Core/src/Core/IWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public interface IWindow : ITitledElement

void Destroying();

void Backgrounding(IPersistedState state);

bool BackButtonClicked();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Android.App;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Platform;

namespace Microsoft.Maui.Handlers
{
Expand All @@ -9,5 +10,10 @@ public static void MapTerminate(ApplicationHandler handler, IApplication applica
{
handler.Logger?.LogWarning("Android does not support programmatically terminating the app.");
}

public static void MapOpenWindow(ApplicationHandler handler, IApplication application, object? args)
{
handler.NativeView?.RequestNewWindow(application, args as OpenWindowRequest);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public partial class ApplicationHandler : ElementHandler<IApplication, object>
protected override object CreateNativeElement() => throw new NotImplementedException();

public static void MapTerminate(ApplicationHandler handler, IApplication application, object? args) { }
public static void MapOpenWindow(ApplicationHandler handler, IApplication application, object? args) { }
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Microsoft.Maui.Platform;

namespace Microsoft.Maui.Handlers
{
public partial class ApplicationHandler : ElementHandler<IApplication, UI.Xaml.Application>
Expand All @@ -6,5 +8,10 @@ public static void MapTerminate(ApplicationHandler handler, IApplication applica
{
handler.NativeView.Exit();
}

public static void MapOpenWindow(ApplicationHandler handler, IApplication application, object? args)
{
handler.NativeView?.CreateNativeWindow(application, args as OpenWindowRequest);
}
}
}
3 changes: 2 additions & 1 deletion src/Core/src/Handlers/Application/ApplicationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public partial class ApplicationHandler

public static CommandMapper<IApplication, ApplicationHandler> CommandMapper = new(ElementCommandMapper)
{
[TerminateCommandKey] = MapTerminate
[TerminateCommandKey] = MapTerminate,
[nameof(IApplication.OpenWindow)] = MapOpenWindow
};

ILogger<ApplicationHandler>? _logger;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
using Foundation;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Platform;
using UIKit;

namespace Microsoft.Maui.Handlers
Expand All @@ -17,6 +17,11 @@ public static void MapTerminate(ApplicationHandler handler, IApplication applica
#endif
}

public static void MapOpenWindow(ApplicationHandler handler, IApplication application, object? args)
{
handler.NativeView?.RequestNewWindow(application, args as OpenWindowRequest);
}

#if __MACCATALYST__
class NSApplication
{
Expand Down
Loading