Skip to content

Commit 5acd61d

Browse files
authored
Merge pull request #46 from roubachof/handlers
Handlers
2 parents 58eaafb + 18a1284 commit 5acd61d

File tree

329 files changed

+7048
-22285
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

329 files changed

+7048
-22285
lines changed

BUILD.md

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
# WARP.md
2+
3+
This file provides guidance to WARP (warp.dev) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
Sharpnado.Shadows is a .NET MAUI library (version 2.0+) that adds customizable shadows to any view across Android, iOS, Windows, and MacCatalyst platforms. The library enables multiple shadows per view with configurable properties (Color, Opacity, BlurRadius, Offset, CornerRadius) and supports Neumorphism design patterns.
8+
9+
**Version 2.0.0** is a complete rewrite for .NET 9 MAUI with modern handler architecture. Legacy Xamarin.Forms support (v1.x) has been moved to a separate branch.
10+
11+
## Repository Structure
12+
13+
```
14+
Sharpnado.Shadows/
15+
├── Maui.Shadows/ # .NET 9 MAUI library (main project)
16+
│ ├── Shade.cs # Core shadow configuration (BindableObject)
17+
│ ├── Shadows.cs # Main ContentView with weak events
18+
│ ├── *Extension.cs # XAML markup extensions
19+
│ ├── MauiAppBuilderExtensions.cs # MAUI initialization (UseSharpnadoShadows)
20+
│ ├── InternalLogger.cs # Logging infrastructure
21+
│ ├── Maui.Shadows.csproj # Multi-targeted .NET 9 project
22+
│ └── Platforms/ # Platform-specific implementations
23+
│ ├── Android/ # Android handlers and controllers
24+
│ │ ├── ShadowsHandler.cs # MAUI ViewHandler
25+
│ │ ├── AndroidShadowsController.cs # Shadow lifecycle management
26+
│ │ ├── BitmapCache.cs # Global bitmap caching
27+
│ │ ├── GpuBlurHelper.cs # GPU-based blur (RenderScript/RenderEffect)
28+
│ │ └── StackBlurHelper.cs # CPU-based StackBlur fallback
29+
│ ├── iOS/ # iOS/MacCatalyst handlers
30+
│ │ ├── ShadowsHandler.cs # MAUI ViewHandler with UIView
31+
│ │ └── iOSShadowsController.cs # CALayer-based shadows
32+
│ └── Windows/ # Windows handlers
33+
│ ├── ShadowsHandler.cs # MAUI ViewHandler with Grid
34+
│ └── WindowsShadowsController.cs # WinUI 3 Composition API
35+
├── MauiSample/ # .NET MAUI sample application
36+
│ └── ShadowsSample.Maui/ # Sample app demonstrating library features
37+
├── Docs/ # Documentation assets (images, diagrams)
38+
└── README.md # Main documentation
39+
```
40+
41+
## Build Commands
42+
43+
### Building the MAUI library (.NET 9)
44+
45+
```bash
46+
# From repository root
47+
cd Maui.Shadows
48+
49+
# Build all target frameworks
50+
dotnet build
51+
52+
# Build for specific platform
53+
dotnet build -f net9.0-android
54+
dotnet build -f net9.0-ios
55+
dotnet build -f net9.0-maccatalyst
56+
dotnet build -f net9.0-windows10.0.19041.0
57+
58+
# Build in Release mode
59+
dotnet build -c Release
60+
61+
# Clean build
62+
dotnet clean && dotnet build
63+
```
64+
65+
### Building the sample application
66+
67+
```bash
68+
# From repository root
69+
cd MauiSample/ShadowsSample.Maui
70+
71+
# Build for all platforms
72+
dotnet build
73+
74+
# Run on specific platform
75+
dotnet build -t:Run -f net9.0-android
76+
dotnet build -t:Run -f net9.0-ios
77+
```
78+
79+
### Creating NuGet package
80+
81+
```bash
82+
# From Maui.Shadows directory
83+
dotnet pack -c Release
84+
85+
# Package will be created in bin/Release/
86+
# Sharpnado.Maui.Shadows.2.0.0.nupkg
87+
```
88+
89+
### Running tests (if available)
90+
91+
```bash
92+
# From repository root
93+
dotnet test
94+
```
95+
96+
## Architecture
97+
98+
### Core Concepts
99+
100+
**Shadows Component**: A .NET MAUI `ContentView` that wraps any view and applies one or more shadow layers (called "Shades").
101+
102+
**Shade**: Represents an individual shadow with five main properties:
103+
- `Point Offset`: Shadow offset from the source (X, Y)
104+
- `Color Color`: Shadow color (MAUI Color)
105+
- `double Opacity`: Shadow opacity (0.0 to 1.0)
106+
- `double BlurRadius`: Blur amount in pixels
107+
- `float CornerRadius`: Corner radius matching (set on Shadows, not individual Shade)
108+
109+
**BlurType** (Android only): Choose rendering algorithm:
110+
- `Gpu` (default): Hardware-accelerated blur using RenderScript/RenderEffect
111+
- `StackBlur`: CPU-based StackBlur algorithm
112+
113+
### Platform-Specific Implementations (.NET MAUI Handlers)
114+
115+
Each platform uses modern MAUI handlers with optimized rendering:
116+
117+
**Android** (`Maui.Shadows/Platforms/Android/`):
118+
- **Handler**: `ShadowsHandler` (ViewHandler<Shadows, FrameLayout>)
119+
- **Controller**: `AndroidShadowsController` manages shadow lifecycle
120+
- **Blur Rendering**:
121+
- `GpuBlurHelper`: RenderScript (API < 31) or RenderEffect (API 31+)
122+
- `StackBlurHelper`: CPU fallback for compatibility
123+
- **Caching**: `BitmapCache` singleton with hash-based bitmap reuse
124+
- **Memory Management**: WeakEvents, proper disposal, cached bitmaps
125+
- **Key Classes**: `ShadowsHandler`, `AndroidShadowsController`, `BitmapCache`, `GpuBlurHelper`, `StackBlurHelper`
126+
127+
**iOS/MacCatalyst** (`Maui.Shadows/Platforms/iOS/`):
128+
- **Handler**: `ShadowsHandler` (ViewHandler<Shadows, UIView>)
129+
- **Controller**: `iOSShadowsController` manages CALayer sublayers
130+
- **Rendering**: Native `CALayer` with shadowColor, shadowOpacity, shadowRadius, shadowOffset
131+
- **Hardware Acceleration**: Full Core Animation GPU acceleration
132+
- **Memory**: UIView container with proper event unsubscription
133+
- **Key Classes**: `ShadowsHandler`, `iOSShadowsController`, `ShadeExtensions`
134+
135+
**Windows** (`Maui.Shadows/Platforms/Windows/`):
136+
- **Handler**: `ShadowsHandler` (ViewHandler<Shadows, Grid>)
137+
- **Controller**: `WindowsShadowsController` manages SpriteVisual shadows
138+
- **Rendering**: WinUI 3 Composition API with DropShadow
139+
- **Structure**: Grid container with Canvas for shadows + content view
140+
- **Hardware Acceleration**: GPU-accelerated via Windows Composition
141+
- **Fixed**: Memory leak (SizeChanged event) from original UWP renderer
142+
- **Key Classes**: `ShadowsHandler`, `WindowsShadowsController`
143+
144+
### Core Library Structure
145+
146+
The .NET 9 MAUI library (`Maui.Shadows/`) contains:
147+
148+
**Core Components**:
149+
- **Shadows.cs**: Main `ContentView` with weak event pattern for memory safety
150+
- **Shade.cs**: `BindableObject` with properties for shadow configuration
151+
- **MauiAppBuilderExtensions.cs**: Modern MAUI initialization with `UseSharpnadoShadows()`
152+
- **InternalLogger.cs**: Logging infrastructure with Action-based delegates
153+
154+
**XAML Markup Extensions** (all implement `IMarkupExtension`):
155+
- **ImmutableShadesExtension**: Creates `ReadOnlyCollection<Shade>` for static resources
156+
- **ShadeStackExtension**: Creates `ObservableCollection<Shade>` for dynamic changes
157+
- **SingleShadeExtension**: Convenience for single shadow (returns `ReadOnlyCollection<Shade>`)
158+
- **NeumorphismShadesExtension**: Pre-configured two-shadow neumorphism effect
159+
160+
**Platform Handlers** (see Platform-Specific Implementations section above)
161+
162+
### Key Design Patterns
163+
164+
**Shade Collections**:
165+
- `ReadOnlyCollection<Shade>`: Immutable, shades are cloned to prevent leaks. **Use for static ResourceDictionary definitions.**
166+
- `ObservableCollection<Shade>`: For dynamic addition/removal of shades during view lifetime
167+
- `IEnumerable<Shade>`: For modifying shade properties during view lifetime
168+
169+
**Important**: Non-ReadOnly shades MUST be declared as transient instances, never as static resources.
170+
171+
**Weak Events**: The library uses `ThomasLevesque.WeakEvent` pattern to prevent memory leaks:
172+
- `WeakCollectionChanged`: For shade collection changes
173+
- `WeakPropertyChanged`: For individual shade property changes
174+
- Prevents handlers from keeping views alive after disposal
175+
176+
**MAUI Handler Pattern**: Each platform implements a `ViewHandler<Shadows, TNative>` that:
177+
1. **CreatePlatformView()**: Creates native container (FrameLayout/UIView/Grid)
178+
2. **ConnectHandler()**: Sets up shadow controller, subscribes to events
179+
3. **DisconnectHandler()**: Unsubscribes events, disposes controller, cleans up resources
180+
4. **PropertyMapper**: Maps `CornerRadius` and `Shades` property changes
181+
5. **Controller**: Separate class manages shadow lifecycle (create, update, destroy)
182+
183+
**Memory Management**:
184+
- All handlers properly unsubscribe from events in `DisconnectHandler()`
185+
- Controllers dispose native resources (bitmaps, layers, visuals)
186+
- Android: Global bitmap cache with weak references
187+
- iOS: CALayer sublayers removed from superlayer
188+
- Windows: SpriteVisual and DropShadow properly disposed
189+
190+
## Initialization Requirements (.NET MAUI)
191+
192+
In `MauiProgram.cs`:
193+
194+
```csharp
195+
using Sharpnado.Shades;
196+
197+
public static class MauiProgram
198+
{
199+
public static MauiApp CreateMauiApp()
200+
{
201+
var builder = MauiApp.CreateBuilder();
202+
builder
203+
.UseMauiApp<App>()
204+
.ConfigureFonts(fonts =>
205+
{
206+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
207+
})
208+
.UseSharpnadoShadows(loggerEnable: false); // Add this line
209+
210+
return builder.Build();
211+
}
212+
}
213+
```
214+
215+
**That's it!** No platform-specific initialization required. Handlers are automatically registered via `MauiAppBuilderExtensions.UseSharpnadoShadows()`.
216+
217+
**Logging**: Set `loggerEnable: true` to enable internal logging for debugging.
218+
219+
## Performance Considerations
220+
221+
### Android
222+
- **BlurType="Gpu"** (default): Best performance with hardware acceleration
223+
- API < 31: Uses RenderScript (deprecated but functional)
224+
- API 31+: Uses RenderEffect (modern API)
225+
- **BlurType="StackBlur"**: CPU fallback, use if GPU has issues on specific devices
226+
- **Bitmap Caching**: Shadows are cached globally by hash (color, size, blur)
227+
- **Avoid Animating**: Don't animate BlurRadius, Color, or Opacity (creates new bitmaps)
228+
- **View Animations OK**: Rotation, scale, translation don't recreate bitmaps
229+
- **Size Animations**: Temporarily set `Shades` to empty collection, animate, then restore
230+
231+
### iOS/MacCatalyst
232+
- **CALayer Hardware Acceleration**: All shadow rendering is GPU-accelerated
233+
- **Animate Freely**: All properties (color, blur, opacity, offset) can be animated efficiently
234+
- **No Bitmap Overhead**: Native CALayer shadows don't use bitmaps
235+
236+
### Windows
237+
- **Composition API**: Hardware-accelerated via WinUI 3 Composition
238+
- **SpriteVisual**: Lightweight drop shadows with GPU rendering
239+
- **Animate Freely**: All properties can be animated efficiently
240+
241+
### General
242+
- **Weak Events**: Prevent memory leaks, no performance overhead
243+
- **Shade Collections**: Use `ReadOnlyCollection<Shade>` in ResourceDictionary for best performance
244+
- **Multiple Shadows**: Each shade adds rendering cost, but caching mitigates on Android
245+
246+
## Dependencies
247+
248+
- **Microsoft.Maui.Controls** (9.0.110): .NET MAUI framework
249+
- **ThomasLevesque.WeakEvent** (4.1.0): Weak event pattern implementation for memory leak prevention
250+
251+
## Code Style
252+
253+
- **Language Version**: `latest` (C# 12 features enabled)
254+
- **Nullable Reference Types**: Enabled throughout project
255+
- **ImplicitUsings**: Enabled for common namespaces
256+
- **Target Framework**: .NET 9 with multi-targeting
257+
- **Coding Patterns**: Modern C# (pattern matching, target-typed new, null-coalescing)
258+
- **Async/Await**: Used where appropriate (not in this project)
259+
- **Disposal**: Proper `IDisposable` implementation in all controllers
260+
261+
## Namespace Convention
262+
263+
**Assembly Name**: `Sharpnado.Maui.Shadows`
264+
**Root Namespace**: `Sharpnado.Shades`
265+
**XAML Namespace**: `xmlns:sh="clr-namespace:Sharpnado.Shades;assembly=Sharpnado.Maui.Shadows"`
266+
267+
This is intentional - "Shades" is the conceptual name (a shadow is made of multiple shades), while "Shadows" is the product name.
268+
269+
## Version History
270+
271+
### Version 2.0.0 (Current - .NET MAUI)
272+
- Complete rewrite for .NET 9 MAUI
273+
- Modern ViewHandler architecture for all platforms
274+
- Android: New `BlurType` property (Gpu/StackBlur)
275+
- Fixed memory leaks (Windows SizeChanged event, proper event unsubscription)
276+
- Enhanced null safety with nullable reference types
277+
- Improved logging and debugging
278+
- **Breaking Changes**: See README.md for migration guide
279+
280+
### Version 1.x (Legacy - Xamarin.Forms)
281+
- Original Xamarin.Forms implementation
282+
- Supported: Android, iOS, UWP, Tizen
283+
- Deprecated: No longer maintained
284+
- Code moved to separate branch
285+
286+
## NuGet Package
287+
288+
- **Package ID**: `Sharpnado.Maui.Shadows`
289+
- **Version**: 2.0.0
290+
- **License**: MIT
291+
- **Target Frameworks**: net9.0, net9.0-android, net9.0-ios, net9.0-maccatalyst, net9.0-windows10.0.19041.0
292+
- **Minimum OS Versions**:
293+
- Android: API 21 (Android 5.0)
294+
- iOS: 12.2
295+
- MacCatalyst: 15.0
296+
- Windows: 10.0.17763.0

0 commit comments

Comments
 (0)