diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..b775de0 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,18 @@ +{ + "permissions": { + "allow": [ + "Bash(dotnet build:*)", + "Bash(dotnet test:*)", + "Bash(dotnet clean:*)", + "Bash(Remove-Item -Recurse -Force CodeSoupCafe.Mauiobj,CodeSoupCafe.Mauibin -ErrorAction SilentlyContinue)", + "Bash(Remove-Item -Recurse -Force obj,bin -ErrorAction SilentlyContinue)", + "Bash(dir:*)", + "Bash(dotnet pack:*)", + "Bash(dotnet restore:*)", + "Bash(dotnet sln:*)", + "Bash(findstr:*)", + "Bash(Get-ChildItem -Recurse -Filter \"*carousel*\")", + "Bash(Select-Object FullName)" + ] + } +} diff --git a/.github/workflows/dotnet-desktop.yml b/.github/workflows/dotnet-desktop.yml index fac0a1a..166f7ed 100644 --- a/.github/workflows/dotnet-desktop.yml +++ b/.github/workflows/dotnet-desktop.yml @@ -15,21 +15,32 @@ jobs: runs-on: windows-latest # Or macos-latest for iOS/Mac Catalyst builds steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Setup .NET SDK - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '10.0.x' + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "10.0.x" - - name: Install MAUI Workloads - run: dotnet workload install maui + - name: Install MAUI Workloads + run: dotnet workload install maui - - name: Restore NuGet packages - run: dotnet restore LunaDraw.csproj + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json', '**/*.csproj') }} + restore-keys: | + ${{ runner.os }}-nuget- - - name: Build MAUI App (Windows) - run: dotnet build LunaDraw.csproj -c Release -f net10.0-windows10.0.19041.0 + # - name: Remove Local Source for CI + # run: dotnet nuget remove source LocalNuGetPackages --configfile nuget.config - - name: Run Unit Tests - run: dotnet test tests/LunaDraw.Tests/LunaDraw.Tests.csproj + - name: Restore NuGet packages + run: dotnet restore LunaDraw.csproj --configfile nuget.config + + - name: Build MAUI App (Windows) + run: dotnet build LunaDraw.csproj -c Release -f net10.0-windows10.0.19041.0 + + - name: Run Unit Tests + run: dotnet test tests/LunaDraw.Tests/LunaDraw.Tests.csproj diff --git a/App.xaml b/App.xaml index fc81ac9..9e45f6d 100644 --- a/App.xaml +++ b/App.xaml @@ -12,6 +12,9 @@ + + + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..39231a1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,233 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +LunaDraw is a child-centric drawing application (ages 3-8) built with .NET MAUI targeting Windows, Android, iOS, and MacCatalyst. The app features 24+ magical brush effects, shape tools, stamps, undo/redo, layer management, and "Movie Mode" time-lapse replay. + +**Important Context:** + +- The codebase is heavily AI-generated ("vibe-coded") and can be fragile in places +- Some canvas functionality was migrated from a working app in `\Legacy\SurfaceBurnCalc` +- The app is in active development with missing features tracked in `Documentation/MissingFeatures.md` + +## Build & Development Commands + +### Building + +```bash +# Build the project (Windows target) +dotnet build LunaDraw.csproj -f net10.0-windows10.0.19041.0 + +# Build for specific platform +dotnet build LunaDraw.csproj -f net10.0-android36.0 +dotnet build LunaDraw.csproj -f net10.0-ios26.0 +dotnet build LunaDraw.csproj -f net10.0-maccatalyst26.0 +``` + +### Testing + +```bash +# Run all tests +dotnet test tests/LunaDraw.Tests/LunaDraw.Tests.csproj + +# Run specific test +dotnet test tests/LunaDraw.Tests/LunaDraw.Tests.csproj --filter "FullyQualifiedName~TestMethodName" +``` + +### Running + +- Use Visual Studio 2022 or VS Code with C# Dev Kit and .NET MAUI extensions +- Select target framework (e.g., `net10.0-windows10.0.19041.0`) +- Build and Run through IDE + +## Architecture + +### Core Technologies + +- **.NET MAUI** - Cross-platform UI framework +- **SkiaSharp** - All vector graphics and rendering (primary graphics engine) +- **ReactiveUI** - MVVM framework and state management using observables +- **CommunityToolkit.Maui** - Extended MAUI controls and utilities + +### Architectural Patterns + +#### MVVM with ReactiveUI + +- ViewModels inherit from `ReactiveObject` for property change notifications +- Use `this.RaiseAndSetIfChanged(ref field, value)` for reactive properties +- Leverage reactive subscriptions for messaging and state changes + +#### Messaging & Communication + +- **MessageBus** (ReactiveUI's `IMessageBus`): Use sparingly for loosely-coupled broadcast messages between disconnected components +- **Reactive Observables**: Preferred approach for component communication where possible +- **Command/Event Pattern**: Fallback when reactive approaches don't fit +- MessageBus is instance-based (injected via DI), NOT static for testability + +#### Dependency Injection + +Services registered in `MauiProgram.cs`: + +- **Core State**: `IMessageBus`, `NavigationModel`, `SelectionObserver`, `ILayerFacade` +- **Logic Services**: `ICanvasInputHandler`, `ClipboardMemento`, `IBitmapCache`, `IPreferencesFacade`, `IDrawingStorageMomento` +- **ViewModels**: Singleton or Transient as appropriate +- **Pages**: Typically Transient + +### Key Architectural Components + +#### Drawing Model + +- **IDrawableElement**: Base interface for all drawable objects (paths, shapes, stamps, images) + + - Supports selection, transforms, visibility, layering (ZIndex), opacity, fill/stroke + - Each element has `Bounds`, `TransformMatrix`, and methods: `Draw()`, `HitTest()`, `Clone()`, `Translate()`, `Transform()` + - Concrete implementations: `DrawablePath`, `DrawableEllipse`, `DrawableRectangle`, `DrawableLine`, `DrawableImage`, `DrawableStamps`, `DrawableGroup` + +- **Layer**: Container for drawable elements with ReactiveUI observable collections + + - Uses **QuadTree spatial indexing** (`QuadTreeMemento`) for efficient spatial queries and rendering + - No bitmap tiling - renders directly from vector elements + - Auto-assigns ZIndex to new elements to maintain draw order + - Supports masking modes, visibility, locking + +- **ILayerFacade**: Abstraction for layer management operations + - Manages `ObservableCollection` and current layer state + - Integrates with `HistoryMemento` for undo/redo + - Methods: `AddLayer()`, `RemoveLayer()`, `MoveLayer()`, `MoveElementsToLayer()`, `SaveState()` + +#### Tool System + +- **IDrawingTool**: Interface for all drawing/editing tools +- Tool implementations: `FreehandTool`, `EraserTool`, `EraserBrushTool`, `FillTool`, `SelectTool`, `LineTool`, `RectangleTool`, `EllipseTool`, `ShapeTool` +- Tools receive `ToolContext` with canvas state, navigation, layers, and brush settings +- Input handling delegated to `CanvasInputHandler` which dispatches to active tool + +#### View & Viewport Management + +- **NavigationModel**: Manages pan/zoom transformations via `ViewMatrix` (SKMatrix) +- **CanvasInputHandler**: Central touch/mouse input processor + - Handles multi-touch gestures (pan, zoom, rotate) on canvas and selection + - Delegates single-touch drawing to active tool + - Right-click switches to Select tool + - Applies smoothing to gestures for fluid interaction +- **MainPage**: Primary page hosting `SKCanvasView` for rendering + - Subscribes to `CanvasInvalidateMessage` to trigger redraws + - Manages context menus and flyout panels (brushes, shapes, settings) + +#### State Management & History + +- **HistoryMemento**: Undo/redo stack for layer states +- **ClipboardMemento**: Copy/paste buffer for drawable elements +- **DrawingStorageMomento**: Serialization/deserialization of drawings to file +- **QuadTreeMemento**: Generic spatial partitioning for efficient hit-testing and culling + +## Code Quality & Testing Standards + +### Testing with xUnit, Moq + +- **Test Format**: Arrange-Act-Assert (AAA) + - If no `// Arrange` needed, start with `// Act` +- **Naming**: `Should_When_Returns` format + - Example: `Should_Set_Sliding_Issued_At_Time_When_Valid_Credentials_Expired_Or_Invalid_Returns_Logout` +- **Test Instances**: Use class name for instance, NOT 'sut' or arbitrary names + - Mocks: `mockClassName` (e.g., `mockLayerFacade`) +- **Assertions**: One assertion per line +- **Test Types**: Prefer `[Theory]`, `[InlineData]`, `[MemberData]` over multiple `[Fact]` methods. Include negative test cases + +### Bug Fixing Workflow + +1. **Write test first** to validate the bug exists +2. Implement the fix +3. Run test to confirm bug elimination + +### Code Style Rules (from .clinerules) + +- **NO underscores** in names +- **NO regions** +- **NO abbreviations** in variable names or otherwise (use full descriptive names) +- **NO legacy or duplicate code** - refactor to clean state, remove obsolete code +- **Static extensions**: Use ONLY for reusable logic (see `Logic/Extensions/`) + +### SOLID & Design Principles + +Ensure adherence to: + +- Single Responsibility Principle (SRP) +- Open/Closed Principle (OCP) +- Liskov Substitution Principle (LSP) +- Interface Segregation Principle (ISP) +- Dependency Inversion Principle (DIP) +- DRY (Don't Repeat Yourself) +- Low Coupling / High Cohesion +- Separation of Concerns & Modularity + +## Project Structure + +``` +LunaDraw/ +├── Components/ # Reusable UI components and controls +│ ├── Carousel/ # Gallery carousel implementation +│ ├── *FlyoutPanel.xaml # Brush, shape, settings panels +│ └── *.cs # Custom controls (BrushPreview, ShapePreview, etc.) +├── Converters/ # XAML value converters +├── Documentation/ # Architecture, features, missing features +├── Logic/ # Core business logic (non-UI) +│ ├── Constants/ # App-wide constants +│ ├── Extensions/ # Static extension methods (SkiaSharp, Preferences) +│ ├── Handlers/ # Input handling (CanvasInputHandler) +│ ├── Messages/ # MessageBus message types +│ ├── Models/ # Domain models (IDrawableElement, Layer, ToolContext, etc.) +│ ├── Tools/ # IDrawingTool implementations +│ ├── Utils/ # Utilities (LayerFacade, Mementos, BitmapCache, etc.) +│ └── ViewModels/ # ReactiveUI ViewModels +├── Pages/ # MAUI pages (MainPage) +├── Platforms/ # Platform-specific code +├── Resources/ # Images, fonts, splash, raw assets +├── tests/ # Unit tests +│ └── LunaDraw.Tests/ +└── MauiProgram.cs # DI registration and app configuration +``` + +## Important Technical Notes + +### SkiaSharp Rendering + +- All graphics rendered via SkiaSharp (`SKCanvas`, `SKPaint`, `SKPath`) +- `MainPage.OnCanvasViewPaintSurface`: Main rendering loop + - Applies `NavigationModel.ViewMatrix` for pan/zoom + - Iterates layers, uses QuadTree to cull off-screen elements + - Elements sorted by ZIndex before drawing + +### Brush Effects + +- 24+ brush effects with custom shaders and blending modes +- Examples: Glow/Neon (additive blending, bloom), Star Sparkles, Rainbow, Fireworks, Crayon, Spray, Ribbon +- Brush settings stored in `ToolbarViewModel` and passed via `ToolContext` + +### Movie Mode (Time-Lapse) + +- Records drawing process in background +- Playback animates creation of drawing + +### Child-Friendly UX Requirements + +- Large touch targets (min 2cm x 2cm) +- Multi-sensory feedback (sounds, animations) +- Icon-driven, minimal text +- Visual/audio guidance over explicit instructions + +## Legacy & Migration Notes + +- Canvas functionality migrated from `\Legacy\SurfaceBurnCalc` (previous working app) +- Current branch `reactive-carousel-v2` is refactoring carousel infrastructure from SBC to MAUI +- Code is fragile in places due to AI generation - test thoroughly + +## Additional Resources + +- **README.md**: Project overview, features, screenshots, setup +- **Documentation/ArchitectureDesign.md**: Detailed architecture and design requirements +- **Documentation/Features.md**: Feature specifications +- **Documentation/MissingFeatures.md**: Pending features and known issues +- **.clinerules/**: Coding standards and SPARC methodology guidelines diff --git a/Components/AdvancedSettingsPopup.xaml b/Components/AdvancedSettingsPopup.xaml index 6765595..9dda415 100644 --- a/Components/AdvancedSettingsPopup.xaml +++ b/Components/AdvancedSettingsPopup.xaml @@ -7,7 +7,7 @@ x:Class="LunaDraw.Components.AdvancedSettingsPopup" x:DataType="viewModels:MainViewModel" CanBeDismissedByTappingOutsideOfPopup="True" - BackgroundColor="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray900}}"> + BackgroundColor="{AppThemeBinding Light={StaticResource PopupBackgroundLight}, Dark={StaticResource PopupBackgroundDark}}"> - @@ -20,7 +20,7 @@ HorizontalTextAlignment="Center"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +