Fix NavigationPageHandler, StepperHandler, TimePickerHandler from decompiled
NavigationPageHandler: - Added LoadToolbarIcon() method for PNG/SVG toolbar icons - Added icon loading in MapToolbarItems() - Fixed OnVirtualViewPushed to set Title and handle null content - Fixed animation parameters to match decompiled StepperHandler: - Added MapIncrement() and MapIsEnabled() methods - Added dark theme color support in ConnectHandler TimePickerHandler: - Added dark theme color support in ConnectHandler SkiaPage: - Added Icon property to SkiaToolbarItem class Also added Svg.Skia package reference. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
// Licensed to the .NET Foundation under one or more agreements.
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using Microsoft.Maui.Handlers;
|
using Microsoft.Maui.Handlers;
|
||||||
using Microsoft.Maui.Graphics;
|
using Microsoft.Maui.Graphics;
|
||||||
using Microsoft.Maui.Controls;
|
using Microsoft.Maui.Controls;
|
||||||
using Microsoft.Maui.Platform;
|
using Microsoft.Maui.Platform;
|
||||||
using Microsoft.Maui.Platform.Linux.Hosting;
|
using Microsoft.Maui.Platform.Linux.Hosting;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
using Svg.Skia;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
namespace Microsoft.Maui.Platform.Linux.Handlers;
|
namespace Microsoft.Maui.Platform.Linux.Handlers;
|
||||||
@@ -164,7 +166,7 @@ public partial class NavigationPageHandler : ViewHandler<NavigationPage, SkiaNav
|
|||||||
contentPage.ToolbarItems.Clear();
|
contentPage.ToolbarItems.Clear();
|
||||||
foreach (var item in page.ToolbarItems)
|
foreach (var item in page.ToolbarItems)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[NavigationPageHandler] Adding toolbar item: '{item.Text}', Order={item.Order}");
|
Console.WriteLine($"[NavigationPageHandler] Adding toolbar item: '{item.Text}', IconImageSource={item.IconImageSource}, Order={item.Order}");
|
||||||
// Default and Primary should both be treated as Primary (shown in toolbar)
|
// Default and Primary should both be treated as Primary (shown in toolbar)
|
||||||
// Only Secondary goes to overflow menu
|
// Only Secondary goes to overflow menu
|
||||||
var order = item.Order == ToolbarItemOrder.Secondary
|
var order = item.Order == ToolbarItemOrder.Secondary
|
||||||
@@ -188,9 +190,17 @@ public partial class NavigationPageHandler : ViewHandler<NavigationPage, SkiaNav
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Load icon if specified
|
||||||
|
SKBitmap? icon = null;
|
||||||
|
if (item.IconImageSource is FileImageSource fileSource && !string.IsNullOrEmpty(fileSource.File))
|
||||||
|
{
|
||||||
|
icon = LoadToolbarIcon(fileSource.File);
|
||||||
|
}
|
||||||
|
|
||||||
contentPage.ToolbarItems.Add(new SkiaToolbarItem
|
contentPage.ToolbarItems.Add(new SkiaToolbarItem
|
||||||
{
|
{
|
||||||
Text = item.Text ?? "",
|
Text = item.Text ?? "",
|
||||||
|
Icon = icon,
|
||||||
Order = order,
|
Order = order,
|
||||||
Command = clickCommand
|
Command = clickCommand
|
||||||
});
|
});
|
||||||
@@ -211,6 +221,56 @@ public partial class NavigationPageHandler : ViewHandler<NavigationPage, SkiaNav
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SKBitmap? LoadToolbarIcon(string fileName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string baseDirectory = AppContext.BaseDirectory;
|
||||||
|
string pngPath = Path.Combine(baseDirectory, fileName);
|
||||||
|
string svgPath = Path.Combine(baseDirectory, Path.ChangeExtension(fileName, ".svg"));
|
||||||
|
|
||||||
|
Console.WriteLine($"[NavigationPageHandler] LoadToolbarIcon: Looking for {fileName}");
|
||||||
|
Console.WriteLine($"[NavigationPageHandler] Trying PNG: {pngPath} (exists: {File.Exists(pngPath)})");
|
||||||
|
Console.WriteLine($"[NavigationPageHandler] Trying SVG: {svgPath} (exists: {File.Exists(svgPath)})");
|
||||||
|
|
||||||
|
// Try SVG first
|
||||||
|
if (File.Exists(svgPath))
|
||||||
|
{
|
||||||
|
using var svg = new SKSvg();
|
||||||
|
svg.Load(svgPath);
|
||||||
|
if (svg.Picture != null)
|
||||||
|
{
|
||||||
|
var cullRect = svg.Picture.CullRect;
|
||||||
|
float scale = 24f / Math.Max(cullRect.Width, cullRect.Height);
|
||||||
|
var bitmap = new SKBitmap(24, 24, false);
|
||||||
|
using var canvas = new SKCanvas(bitmap);
|
||||||
|
canvas.Clear(SKColors.Transparent);
|
||||||
|
canvas.Scale(scale);
|
||||||
|
canvas.DrawPicture(svg.Picture, null);
|
||||||
|
Console.WriteLine($"[NavigationPageHandler] Loaded SVG icon: {svgPath}");
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try PNG
|
||||||
|
if (File.Exists(pngPath))
|
||||||
|
{
|
||||||
|
using var stream = File.OpenRead(pngPath);
|
||||||
|
var result = SKBitmap.Decode(stream);
|
||||||
|
Console.WriteLine($"[NavigationPageHandler] Loaded PNG icon: {pngPath}");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"[NavigationPageHandler] Icon not found: {fileName}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[NavigationPageHandler] Error loading icon {fileName}: {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnVirtualViewPushed(object? sender, Microsoft.Maui.Controls.NavigationEventArgs e)
|
private void OnVirtualViewPushed(object? sender, Microsoft.Maui.Controls.NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -232,12 +292,30 @@ public partial class NavigationPageHandler : ViewHandler<NavigationPage, SkiaNav
|
|||||||
skiaPage.ShowNavigationBar = true;
|
skiaPage.ShowNavigationBar = true;
|
||||||
skiaPage.TitleBarColor = PlatformView.BarBackgroundColor;
|
skiaPage.TitleBarColor = PlatformView.BarBackgroundColor;
|
||||||
skiaPage.TitleTextColor = PlatformView.BarTextColor;
|
skiaPage.TitleTextColor = PlatformView.BarTextColor;
|
||||||
|
skiaPage.Title = e.Page.Title ?? "";
|
||||||
|
|
||||||
|
// Handle content if null
|
||||||
|
if (skiaPage.Content == null && e.Page is ContentPage contentPage && contentPage.Content != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[NavigationPageHandler] Content is null, creating handler for: {contentPage.Content.GetType().Name}");
|
||||||
|
if (contentPage.Content.Handler == null)
|
||||||
|
{
|
||||||
|
contentPage.Content.Handler = contentPage.Content.ToViewHandler(MauiContext);
|
||||||
|
}
|
||||||
|
if (contentPage.Content.Handler?.PlatformView is SkiaView skiaContent)
|
||||||
|
{
|
||||||
|
skiaPage.Content = skiaContent;
|
||||||
|
Console.WriteLine($"[NavigationPageHandler] Set content to: {skiaContent.GetType().Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine($"[NavigationPageHandler] Mapping toolbar items");
|
Console.WriteLine($"[NavigationPageHandler] Mapping toolbar items");
|
||||||
MapToolbarItems(skiaPage, e.Page);
|
MapToolbarItems(skiaPage, e.Page);
|
||||||
Console.WriteLine($"[NavigationPageHandler] Pushing page to platform");
|
Console.WriteLine($"[NavigationPageHandler] Pushing page to platform");
|
||||||
PlatformView.Push(skiaPage, true);
|
PlatformView.Push(skiaPage, false);
|
||||||
Console.WriteLine($"[NavigationPageHandler] Push complete");
|
Console.WriteLine($"[NavigationPageHandler] Push complete, thread={Environment.CurrentManagedThreadId}");
|
||||||
}
|
}
|
||||||
|
Console.WriteLine("[NavigationPageHandler] OnVirtualViewPushed returning");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -251,13 +329,13 @@ public partial class NavigationPageHandler : ViewHandler<NavigationPage, SkiaNav
|
|||||||
{
|
{
|
||||||
Console.WriteLine($"[NavigationPageHandler] VirtualView Popped: {e.Page?.Title}");
|
Console.WriteLine($"[NavigationPageHandler] VirtualView Popped: {e.Page?.Title}");
|
||||||
// Pop on the platform side to sync with MAUI navigation
|
// Pop on the platform side to sync with MAUI navigation
|
||||||
PlatformView?.Pop(true);
|
PlatformView?.Pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnVirtualViewPoppedToRoot(object? sender, Microsoft.Maui.Controls.NavigationEventArgs e)
|
private void OnVirtualViewPoppedToRoot(object? sender, Microsoft.Maui.Controls.NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[NavigationPageHandler] VirtualView PoppedToRoot");
|
Console.WriteLine($"[NavigationPageHandler] VirtualView PoppedToRoot");
|
||||||
PlatformView?.PopToRoot(true);
|
PlatformView?.PopToRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPushed(object? sender, NavigationEventArgs e)
|
private void OnPushed(object? sender, NavigationEventArgs e)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using Microsoft.Maui.Handlers;
|
using Microsoft.Maui.Handlers;
|
||||||
using Microsoft.Maui.Graphics;
|
using Microsoft.Maui.Graphics;
|
||||||
|
using Microsoft.Maui.Controls;
|
||||||
using Microsoft.Maui.Platform;
|
using Microsoft.Maui.Platform;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
@@ -19,7 +20,9 @@ public partial class StepperHandler : ViewHandler<IStepper, SkiaStepper>
|
|||||||
[nameof(IStepper.Value)] = MapValue,
|
[nameof(IStepper.Value)] = MapValue,
|
||||||
[nameof(IStepper.Minimum)] = MapMinimum,
|
[nameof(IStepper.Minimum)] = MapMinimum,
|
||||||
[nameof(IStepper.Maximum)] = MapMaximum,
|
[nameof(IStepper.Maximum)] = MapMaximum,
|
||||||
|
["Increment"] = MapIncrement,
|
||||||
[nameof(IView.Background)] = MapBackground,
|
[nameof(IView.Background)] = MapBackground,
|
||||||
|
[nameof(IView.IsEnabled)] = MapIsEnabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static CommandMapper<IStepper, StepperHandler> CommandMapper =
|
public static CommandMapper<IStepper, StepperHandler> CommandMapper =
|
||||||
@@ -45,6 +48,17 @@ public partial class StepperHandler : ViewHandler<IStepper, SkiaStepper>
|
|||||||
{
|
{
|
||||||
base.ConnectHandler(platformView);
|
base.ConnectHandler(platformView);
|
||||||
platformView.ValueChanged += OnValueChanged;
|
platformView.ValueChanged += OnValueChanged;
|
||||||
|
|
||||||
|
// Apply dark theme colors if needed
|
||||||
|
if (Application.Current?.UserAppTheme == AppTheme.Dark)
|
||||||
|
{
|
||||||
|
platformView.ButtonBackgroundColor = new SKColor(66, 66, 66);
|
||||||
|
platformView.ButtonPressedColor = new SKColor(97, 97, 97);
|
||||||
|
platformView.ButtonDisabledColor = new SKColor(48, 48, 48);
|
||||||
|
platformView.SymbolColor = new SKColor(224, 224, 224);
|
||||||
|
platformView.SymbolDisabledColor = new SKColor(97, 97, 97);
|
||||||
|
platformView.BorderColor = new SKColor(97, 97, 97);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DisconnectHandler(SkiaStepper platformView)
|
protected override void DisconnectHandler(SkiaStepper platformView)
|
||||||
@@ -86,4 +100,20 @@ public partial class StepperHandler : ViewHandler<IStepper, SkiaStepper>
|
|||||||
handler.PlatformView.BackgroundColor = solidPaint.Color.ToSKColor();
|
handler.PlatformView.BackgroundColor = solidPaint.Color.ToSKColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void MapIncrement(StepperHandler handler, IStepper stepper)
|
||||||
|
{
|
||||||
|
if (handler.PlatformView is null) return;
|
||||||
|
|
||||||
|
if (stepper is Stepper stepperControl)
|
||||||
|
{
|
||||||
|
handler.PlatformView.Increment = stepperControl.Increment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MapIsEnabled(StepperHandler handler, IStepper stepper)
|
||||||
|
{
|
||||||
|
if (handler.PlatformView is null) return;
|
||||||
|
handler.PlatformView.IsEnabled = stepper.IsEnabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,16 @@ public partial class TimePickerHandler : ViewHandler<ITimePicker, SkiaTimePicker
|
|||||||
{
|
{
|
||||||
base.ConnectHandler(platformView);
|
base.ConnectHandler(platformView);
|
||||||
platformView.TimeSelected += OnTimeSelected;
|
platformView.TimeSelected += OnTimeSelected;
|
||||||
|
|
||||||
|
// Apply dark theme colors if needed
|
||||||
|
if (Application.Current?.UserAppTheme == AppTheme.Dark)
|
||||||
|
{
|
||||||
|
platformView.ClockBackgroundColor = new SKColor(30, 30, 30);
|
||||||
|
platformView.ClockFaceColor = new SKColor(45, 45, 45);
|
||||||
|
platformView.TextColor = new SKColor(224, 224, 224);
|
||||||
|
platformView.BorderColor = new SKColor(97, 97, 97);
|
||||||
|
platformView.BackgroundColor = new SKColor(45, 45, 45);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DisconnectHandler(SkiaTimePicker platformView)
|
protected override void DisconnectHandler(SkiaTimePicker platformView)
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
| ButtonHandler.cs | [x] | Contains TextButtonHandler - Verified |
|
| ButtonHandler.cs | [x] | Contains TextButtonHandler - Verified |
|
||||||
| CheckBoxHandler.cs | [x] | Verified |
|
| CheckBoxHandler.cs | [x] | Verified |
|
||||||
| CollectionViewHandler.cs | [ ] | |
|
| CollectionViewHandler.cs | [ ] | |
|
||||||
| DatePickerHandler.cs | [ ] | |
|
| DatePickerHandler.cs | [x] | Verified |
|
||||||
| EditorHandler.cs | [x] | Verified |
|
| EditorHandler.cs | [x] | Verified |
|
||||||
| EntryHandler.cs | [x] | Verified |
|
| EntryHandler.cs | [x] | Verified |
|
||||||
| FlexLayoutHandler.cs | [ ] | |
|
| FlexLayoutHandler.cs | [ ] | |
|
||||||
| FlyoutPageHandler.cs | [ ] | |
|
| FlyoutPageHandler.cs | [x] | Verified - matches decompiled |
|
||||||
| FrameHandler.cs | [ ] | |
|
| FrameHandler.cs | [ ] | |
|
||||||
| GestureManager.cs | [ ] | |
|
| GestureManager.cs | [ ] | |
|
||||||
| GraphicsViewHandler.cs | [ ] | |
|
| GraphicsViewHandler.cs | [ ] | |
|
||||||
@@ -34,19 +34,19 @@
|
|||||||
| ItemsViewHandler.cs | [ ] | |
|
| ItemsViewHandler.cs | [ ] | |
|
||||||
| LabelHandler.cs | [x] | Verified |
|
| LabelHandler.cs | [x] | Verified |
|
||||||
| LayoutHandler.cs | [x] | Contains GridHandler, StackLayoutHandler, LayoutHandlerUpdate - Verified |
|
| LayoutHandler.cs | [x] | Contains GridHandler, StackLayoutHandler, LayoutHandlerUpdate - Verified |
|
||||||
| NavigationPageHandler.cs | [ ] | Contains RelayCommand |
|
| NavigationPageHandler.cs | [x] | FIXED - Added LoadToolbarIcon, Icon loading, content handling, animated params |
|
||||||
| PageHandler.cs | [x] | Added MapBackgroundColor |
|
| PageHandler.cs | [x] | Added MapBackgroundColor |
|
||||||
| PickerHandler.cs | [ ] | |
|
| PickerHandler.cs | [x] | Verified |
|
||||||
| ProgressBarHandler.cs | [x] | Verified |
|
| ProgressBarHandler.cs | [x] | Verified |
|
||||||
| RadioButtonHandler.cs | [ ] | |
|
| RadioButtonHandler.cs | [x] | Verified - matches decompiled |
|
||||||
| ScrollViewHandler.cs | [x] | Verified |
|
| ScrollViewHandler.cs | [x] | Verified |
|
||||||
| SearchBarHandler.cs | [ ] | |
|
| SearchBarHandler.cs | [x] | Verified - matches decompiled |
|
||||||
| ShellHandler.cs | [ ] | |
|
| ShellHandler.cs | [x] | Verified - matches decompiled |
|
||||||
| SliderHandler.cs | [x] | Verified |
|
| SliderHandler.cs | [x] | Verified |
|
||||||
| StepperHandler.cs | [ ] | |
|
| StepperHandler.cs | [x] | FIXED - Added MapIncrement, MapIsEnabled, dark theme colors |
|
||||||
| SwitchHandler.cs | [x] | Verified |
|
| SwitchHandler.cs | [x] | Verified |
|
||||||
| TabbedPageHandler.cs | [ ] | |
|
| TabbedPageHandler.cs | [x] | Verified - matches decompiled |
|
||||||
| TimePickerHandler.cs | [ ] | |
|
| TimePickerHandler.cs | [x] | FIXED - Added dark theme colors |
|
||||||
| WebViewHandler.cs | [x] | Fixed namespace-qualified event args |
|
| WebViewHandler.cs | [x] | Fixed namespace-qualified event args |
|
||||||
| WindowHandler.cs | [ ] | Contains SkiaWindow, SizeChangedEventArgs, LinuxApplicationContext |
|
| WindowHandler.cs | [ ] | Contains SkiaWindow, SizeChangedEventArgs, LinuxApplicationContext |
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
| SkiaLayoutView.cs | [ ] | Contains SkiaGrid, SkiaStackLayout, SkiaAbsoluteLayout, GridLength, GridPosition |
|
| SkiaLayoutView.cs | [ ] | Contains SkiaGrid, SkiaStackLayout, SkiaAbsoluteLayout, GridLength, GridPosition |
|
||||||
| SkiaMenuBar.cs | [ ] | Contains MenuItem, MenuBarItem |
|
| SkiaMenuBar.cs | [ ] | Contains MenuItem, MenuBarItem |
|
||||||
| SkiaNavigationPage.cs | [ ] | |
|
| SkiaNavigationPage.cs | [ ] | |
|
||||||
| SkiaPage.cs | [ ] | Contains SkiaContentPage, SkiaToolbarItem |
|
| SkiaPage.cs | [x] | Added SkiaToolbarItem.Icon property |
|
||||||
| SkiaPicker.cs | [ ] | |
|
| SkiaPicker.cs | [ ] | |
|
||||||
| SkiaProgressBar.cs | [ ] | |
|
| SkiaProgressBar.cs | [ ] | |
|
||||||
| SkiaRadioButton.cs | [ ] | |
|
| SkiaRadioButton.cs | [ ] | |
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
<PackageReference Include="SkiaSharp" Version="2.88.9" />
|
<PackageReference Include="SkiaSharp" Version="2.88.9" />
|
||||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||||
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.88.9" />
|
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.88.9" />
|
||||||
|
<PackageReference Include="Svg.Skia" Version="1.0.0" />
|
||||||
|
|
||||||
<!-- HarfBuzz for advanced text shaping -->
|
<!-- HarfBuzz for advanced text shaping -->
|
||||||
<PackageReference Include="HarfBuzzSharp" Version="7.3.0.3" />
|
<PackageReference Include="HarfBuzzSharp" Version="7.3.0.3" />
|
||||||
|
|||||||
@@ -449,6 +449,7 @@ public class SkiaContentPage : SkiaPage
|
|||||||
public class SkiaToolbarItem
|
public class SkiaToolbarItem
|
||||||
{
|
{
|
||||||
public string Text { get; set; } = "";
|
public string Text { get; set; } = "";
|
||||||
|
public SKBitmap? Icon { get; set; }
|
||||||
public SkiaToolbarItemOrder Order { get; set; } = SkiaToolbarItemOrder.Primary;
|
public SkiaToolbarItemOrder Order { get; set; } = SkiaToolbarItemOrder.Primary;
|
||||||
public System.Windows.Input.ICommand? Command { get; set; }
|
public System.Windows.Input.ICommand? Command { get; set; }
|
||||||
public SKRect HitBounds { get; set; }
|
public SKRect HitBounds { get; set; }
|
||||||
|
|||||||
Reference in New Issue
Block a user