Showing preview only (1,549K chars total). Download the full file or copy to clipboard to get everything.
Repository: jonathanpeppers/spice
Branch: main
Commit: b05aeaa7fadd
Files: 358
Total size: 1.4 MB
Directory structure:
gitextract_5fqaxoqu/
├── .config/
│ └── dotnet-tools.json
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── copilot-setup-steps.yml
│ └── spice.yml
├── .gitignore
├── .vscode/
│ └── settings.json
├── Directory.Build.props
├── Directory.Build.targets
├── LICENSE
├── NuGet.config
├── README.md
├── docs/
│ ├── DATA-BINDING-SPEC.md
│ ├── MAUI-CONTROLS-COMPARISON.md
│ ├── NAVIGATION-SPEC.md
│ ├── THEME-SPEC.md
│ ├── VIEW-LIFECYCLE-SPEC.md
│ └── spice.pptx
├── global.json
├── samples/
│ ├── HeadToHeadMaui/
│ │ ├── App.xaml
│ │ ├── App.xaml.cs
│ │ ├── AppShell.xaml
│ │ ├── AppShell.xaml.cs
│ │ ├── HeadToHeadMaui.csproj
│ │ ├── HeadToHeadMaui.sln
│ │ ├── MainPage.xaml
│ │ ├── MainPage.xaml.cs
│ │ ├── MauiProgram.cs
│ │ ├── Platforms/
│ │ │ ├── Android/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── MainActivity.cs
│ │ │ │ ├── MainApplication.cs
│ │ │ │ └── Resources/
│ │ │ │ └── values/
│ │ │ │ └── colors.xml
│ │ │ ├── MacCatalyst/
│ │ │ │ ├── AppDelegate.cs
│ │ │ │ ├── Info.plist
│ │ │ │ └── Program.cs
│ │ │ ├── Tizen/
│ │ │ │ ├── Main.cs
│ │ │ │ └── tizen-manifest.xml
│ │ │ ├── Windows/
│ │ │ │ ├── App.xaml
│ │ │ │ ├── App.xaml.cs
│ │ │ │ ├── Package.appxmanifest
│ │ │ │ └── app.manifest
│ │ │ └── iOS/
│ │ │ ├── AppDelegate.cs
│ │ │ ├── Info.plist
│ │ │ └── Program.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ └── Resources/
│ │ ├── Raw/
│ │ │ └── AboutAssets.txt
│ │ └── Styles/
│ │ ├── Colors.xaml
│ │ └── Styles.xaml
│ ├── HeadToHeadSpice/
│ │ ├── App.cs
│ │ ├── GlobalUsings.cs
│ │ ├── HeadToHeadSpice.csproj
│ │ └── Platforms/
│ │ ├── Android/
│ │ │ ├── AndroidManifest.xml
│ │ │ └── MainActivity.cs
│ │ └── iOS/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Program.cs
│ ├── README.md
│ ├── Spice.BlazorSample/
│ │ ├── App.cs
│ │ ├── GlobalUsings.cs
│ │ ├── Main.razor
│ │ ├── Pages/
│ │ │ └── Index.razor
│ │ ├── Platforms/
│ │ │ ├── Android/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── MainActivity.cs
│ │ │ └── iOS/
│ │ │ ├── AppDelegate.cs
│ │ │ ├── Info.plist
│ │ │ └── Program.cs
│ │ ├── Shared/
│ │ │ ├── MainLayout.razor
│ │ │ ├── MainLayout.razor.css
│ │ │ ├── NavMenu.razor
│ │ │ └── NavMenu.razor.css
│ │ ├── Spice.BlazorSample.csproj
│ │ ├── _Imports.razor
│ │ └── wwwroot/
│ │ ├── css/
│ │ │ ├── app.css
│ │ │ └── open-iconic/
│ │ │ ├── FONT-LICENSE
│ │ │ ├── ICON-LICENSE
│ │ │ ├── README.md
│ │ │ └── font/
│ │ │ └── fonts/
│ │ │ └── open-iconic.otf
│ │ └── index.html
│ ├── Spice.Scenarios/
│ │ ├── App.cs
│ │ ├── GlobalUsings.cs
│ │ ├── Platforms/
│ │ │ ├── Android/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── MainActivity.cs
│ │ │ └── iOS/
│ │ │ ├── AppDelegate.cs
│ │ │ ├── Info.plist
│ │ │ └── Program.cs
│ │ ├── Scenarios/
│ │ │ ├── ActivityIndicatorScenario.cs
│ │ │ ├── BorderScenario.cs
│ │ │ ├── BoxViewScenario.cs
│ │ │ ├── CheckBoxScenario.cs
│ │ │ ├── CollectionViewScenario.cs
│ │ │ ├── ContentViewScenario.cs
│ │ │ ├── DatePickerScenario.cs
│ │ │ ├── EditorScenario.cs
│ │ │ ├── EntryScenario.cs
│ │ │ ├── GhostButtonScenario.cs
│ │ │ ├── HelloWorldScenario.cs
│ │ │ ├── ImageButtonScenario.cs
│ │ │ ├── MarginScenario.cs
│ │ │ ├── PickerScenario.cs
│ │ │ ├── ProgressBarScenario.cs
│ │ │ ├── RadioButtonScenario.cs
│ │ │ ├── RefreshViewScenario.cs
│ │ │ ├── ScrollViewScenario.cs
│ │ │ ├── SearchBarScenario.cs
│ │ │ ├── SliderScenario.cs
│ │ │ ├── SwipeViewScenario.cs
│ │ │ ├── SwitchScenario.cs
│ │ │ ├── ThemeScenario.cs
│ │ │ ├── TimePickerScenario.cs
│ │ │ └── WebViewScenario.cs
│ │ └── Spice.Scenarios.csproj
│ └── samples.slnx
├── sizes/
│ ├── com.companyname.Hello-Signed.apkdesc
│ ├── com.companyname.HelloBlazor-Signed.apkdesc
│ └── startup.md
├── spice.slnx
├── src/
│ ├── ProfiledAot/
│ │ ├── Directory.Build.props
│ │ ├── Directory.Build.targets
│ │ ├── README.md
│ │ ├── build.proj
│ │ └── shared/
│ │ └── nuget.config
│ ├── Spice/
│ │ ├── Blazor/
│ │ │ ├── BlazorWebView.cs
│ │ │ ├── SpiceDispatcher.cs
│ │ │ ├── SpiceServiceProvider.cs
│ │ │ └── UriExtensions.cs
│ │ ├── Core/
│ │ │ ├── ActivityIndicator.cs
│ │ │ ├── Application.cs
│ │ │ ├── BindingExtensions.cs
│ │ │ ├── Border.cs
│ │ │ ├── BoxView.cs
│ │ │ ├── Button.cs
│ │ │ ├── CheckBox.cs
│ │ │ ├── CollectionView.cs
│ │ │ ├── ColumnDefinition.cs
│ │ │ ├── ContentView.cs
│ │ │ ├── DatePicker.cs
│ │ │ ├── Editor.cs
│ │ │ ├── Entry.cs
│ │ │ ├── Grid.cs
│ │ │ ├── GridLength.cs
│ │ │ ├── GridUnitType.cs
│ │ │ ├── Image.cs
│ │ │ ├── ImageButton.cs
│ │ │ ├── Label.cs
│ │ │ ├── LayoutAlignment.cs
│ │ │ ├── LayoutExpandFlag.cs
│ │ │ ├── LayoutOptions.cs
│ │ │ ├── NavigationView.cs
│ │ │ ├── Orientation.cs
│ │ │ ├── Picker.cs
│ │ │ ├── PlatformAppearance.cs
│ │ │ ├── ProgressBar.cs
│ │ │ ├── RadioButton.cs
│ │ │ ├── RefreshView.cs
│ │ │ ├── RootComponent.cs
│ │ │ ├── RowDefinition.cs
│ │ │ ├── ScrollView.cs
│ │ │ ├── SearchBar.cs
│ │ │ ├── SelectionMode.cs
│ │ │ ├── Slider.cs
│ │ │ ├── StackLayout.cs
│ │ │ ├── SwipeBehaviorOnInvoked.cs
│ │ │ ├── SwipeDirection.cs
│ │ │ ├── SwipeItem.cs
│ │ │ ├── SwipeItems.cs
│ │ │ ├── SwipeMode.cs
│ │ │ ├── SwipeView.cs
│ │ │ ├── Switch.cs
│ │ │ ├── TabView.cs
│ │ │ ├── Theme.cs
│ │ │ ├── Thickness.cs
│ │ │ ├── TimePicker.cs
│ │ │ ├── TwoWayBindingExtensions.cs
│ │ │ ├── View.cs
│ │ │ └── WebView.cs
│ │ ├── GlobalUsings.cs
│ │ ├── MSBuild/
│ │ │ ├── Spice.Blazor.targets
│ │ │ ├── Spice.props
│ │ │ ├── Spice.targets
│ │ │ ├── spice-blazor.aotprofile
│ │ │ ├── spice-blazor.aotprofile.txt
│ │ │ ├── spice.aotprofile
│ │ │ └── spice.aotprofile.txt
│ │ ├── Platforms/
│ │ │ ├── Android/
│ │ │ │ ├── ActivityIndicator.cs
│ │ │ │ ├── Application.cs
│ │ │ │ ├── Blazor/
│ │ │ │ │ ├── AndroidAssetFileProvider.cs
│ │ │ │ │ ├── AndroidWebViewManager.cs
│ │ │ │ │ ├── BlazorWebView.cs
│ │ │ │ │ ├── SpiceBlazorWebViewClient.cs
│ │ │ │ │ └── SpiceDispatcher.cs
│ │ │ │ ├── Border.cs
│ │ │ │ ├── BoxView.cs
│ │ │ │ ├── Button.cs
│ │ │ │ ├── CheckBox.cs
│ │ │ │ ├── CollectionView.cs
│ │ │ │ ├── ContentView.cs
│ │ │ │ ├── DatePicker.cs
│ │ │ │ ├── Editor.cs
│ │ │ │ ├── Entry.cs
│ │ │ │ ├── Grid.cs
│ │ │ │ ├── Image.cs
│ │ │ │ ├── ImageButton.cs
│ │ │ │ ├── Interop.java
│ │ │ │ ├── Label.cs
│ │ │ │ ├── NavigationView.cs
│ │ │ │ ├── Picker.cs
│ │ │ │ ├── Platform.cs
│ │ │ │ ├── PlatformAppearance.cs
│ │ │ │ ├── PlatformExtensions.cs
│ │ │ │ ├── ProgressBar.cs
│ │ │ │ ├── RadioButton.cs
│ │ │ │ ├── RefreshView.cs
│ │ │ │ ├── ScrollView.cs
│ │ │ │ ├── SearchBar.cs
│ │ │ │ ├── Slider.cs
│ │ │ │ ├── SpiceActivity.cs
│ │ │ │ ├── StackLayout.cs
│ │ │ │ ├── SwipeView.cs
│ │ │ │ ├── Switch.cs
│ │ │ │ ├── TabView.cs
│ │ │ │ ├── TimePicker.cs
│ │ │ │ ├── Transforms.xml
│ │ │ │ ├── View.cs
│ │ │ │ └── WebView.cs
│ │ │ └── iOS/
│ │ │ ├── ActivityIndicator.cs
│ │ │ ├── Application.cs
│ │ │ ├── Blazor/
│ │ │ │ ├── BlazorWebView.cs
│ │ │ │ ├── SpiceDispatcher.cs
│ │ │ │ ├── iOSFileProvider.cs
│ │ │ │ └── iOSWebViewManager.cs
│ │ │ ├── Border.cs
│ │ │ ├── BoxView.cs
│ │ │ ├── Button.cs
│ │ │ ├── CheckBox.cs
│ │ │ ├── CollectionView.cs
│ │ │ ├── ConstraintHelper.cs
│ │ │ ├── ContentView.cs
│ │ │ ├── DatePicker.cs
│ │ │ ├── Editor.cs
│ │ │ ├── Entry.cs
│ │ │ ├── Grid.cs
│ │ │ ├── Image.cs
│ │ │ ├── ImageButton.cs
│ │ │ ├── Label.cs
│ │ │ ├── NavigationView.cs
│ │ │ ├── Picker.cs
│ │ │ ├── Platform.cs
│ │ │ ├── PlatformAppearance.cs
│ │ │ ├── PlatformExtensions.cs
│ │ │ ├── ProgressBar.cs
│ │ │ ├── RadioButton.cs
│ │ │ ├── RefreshView.cs
│ │ │ ├── ScrollView.cs
│ │ │ ├── SearchBar.cs
│ │ │ ├── Slider.cs
│ │ │ ├── SpiceAppDelegate.cs
│ │ │ ├── SpiceViewController.cs
│ │ │ ├── StackLayout.cs
│ │ │ ├── SwipeView.cs
│ │ │ ├── Switch.cs
│ │ │ ├── TabView.cs
│ │ │ ├── TimePicker.cs
│ │ │ ├── View.cs
│ │ │ └── WebView.cs
│ │ ├── README.md
│ │ └── Spice.csproj
│ └── Spice.Templates/
│ ├── Spice.Templates.csproj
│ └── templates/
│ ├── spice/
│ │ ├── .template.config/
│ │ │ └── template.json
│ │ ├── App.cs
│ │ ├── GlobalUsings.cs
│ │ ├── Hello.csproj
│ │ └── Platforms/
│ │ ├── Android/
│ │ │ ├── AndroidManifest.xml
│ │ │ └── MainActivity.cs
│ │ └── iOS/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Program.cs
│ └── spice-blazor/
│ ├── .template.config/
│ │ └── template.json
│ ├── App.cs
│ ├── GlobalUsings.cs
│ ├── HelloBlazor.csproj
│ ├── Main.razor
│ ├── Pages/
│ │ └── Index.razor
│ ├── Platforms/
│ │ ├── Android/
│ │ │ ├── AndroidManifest.xml
│ │ │ └── MainActivity.cs
│ │ └── iOS/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Program.cs
│ ├── Shared/
│ │ ├── MainLayout.razor
│ │ ├── MainLayout.razor.css
│ │ ├── NavMenu.razor
│ │ └── NavMenu.razor.css
│ ├── _Imports.razor
│ └── wwwroot/
│ ├── css/
│ │ ├── app.css
│ │ └── open-iconic/
│ │ ├── FONT-LICENSE
│ │ ├── ICON-LICENSE
│ │ ├── README.md
│ │ └── font/
│ │ └── fonts/
│ │ └── open-iconic.otf
│ └── index.html
└── tests/
└── Spice.Tests/
├── ActivityIndicatorTests.cs
├── ApplicationTests.cs
├── AutomationIdTests.cs
├── BindingExtensionsTests.cs
├── BorderTests.cs
├── BoxViewTests.cs
├── ButtonTests.cs
├── CheckBoxTests.cs
├── CollectionViewTests.cs
├── ContentViewTests.cs
├── DatePickerTests.cs
├── EditorTests.cs
├── EntryTests.cs
├── GridLengthTests.cs
├── GridTests.cs
├── ImageButtonTests.cs
├── ImageTests.cs
├── LabelTests.cs
├── LayoutOptionsTests.cs
├── MarginTests.cs
├── ModalPresentationTests.cs
├── NavigationViewTests.cs
├── PickerTests.cs
├── Platforms/
│ ├── Android/
│ │ ├── AndroidManifest.xml
│ │ ├── MainActivity.cs
│ │ ├── TestDevice.cs
│ │ ├── TestEntryPoint.cs
│ │ └── TestInstrumentation.cs
│ └── iOS/
│ ├── AppDelegate.cs
│ ├── Info.plist
│ ├── Program.cs
│ ├── TestDevice.cs
│ └── TestEntryPoint.cs
├── ProgressBarTests.cs
├── PropertyChangedTests.cs
├── RadioButtonTests.cs
├── RefreshViewTests.cs
├── ScrollViewTests.cs
├── SearchBarTests.cs
├── SliderTests.cs
├── Spice.Tests.csproj
├── StackLayoutTests.cs
├── SwipeItemsTests.cs
├── SwipeViewTests.cs
├── SwitchTests.cs
├── TabViewTests.cs
├── TestViewModel.cs
├── ThemeTests.cs
├── ThicknessTests.cs
├── TimePickerTests.cs
├── TwoWayBindingExtensionsTests.cs
├── Usings.cs
├── ViewLifecycleTests.cs
├── ViewOpacityTests.cs
├── ViewSizeTests.cs
├── ViewTests.cs
├── ViewVisibilityTests.cs
└── WebViewTests.cs
================================================
FILE CONTENTS
================================================
================================================
FILE: .config/dotnet-tools.json
================================================
{
"version": 1,
"isRoot": true,
"tools": {
"androidsdk.tool": {
"version": "0.25.0",
"commands": [
"android"
],
"rollForward": true
},
"microsoft.dotnet.xharness.cli": {
"version": "11.0.0-prerelease.26114.1",
"commands": [
"xharness"
],
"rollForward": true
}
}
}
================================================
FILE: .editorconfig
================================================
root = true
# All files
[*]
indent_style = tab
# Xml files
[*.xml]
indent_style = space
indent_size = 2
# C# files
[*.cs]
#### Core EditorConfig Options ####
# Indentation and spacing
indent_size = 4
tab_width = 4
# New line preferences
end_of_line = crlf
insert_final_newline = false
#### .NET Coding Conventions ####
[*.{cs,vb}]
# Organize usings
dotnet_separate_import_directive_groups = true
dotnet_sort_system_directives_first = true
file_header_template = unset
# this. and Me. preferences
dotnet_style_qualification_for_event = false:silent
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_property = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
# Expression-level preferences
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_object_initializer = true:suggestion
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_style_prefer_auto_properties = true:suggestion
dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
dotnet_style_prefer_conditional_expression_over_return = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
# Parameter preferences
dotnet_code_quality_unused_parameters = all:suggestion
# Suppression preferences
dotnet_remove_unnecessary_suppression_exclusions = none
#### C# Coding Conventions ####
[*.cs]
# var preferences
csharp_style_var_elsewhere = false:silent
csharp_style_var_for_built_in_types = false:silent
csharp_style_var_when_type_is_apparent = false:silent
# Expression-bodied members
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_lambdas = true:suggestion
csharp_style_expression_bodied_local_functions = false:silent
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_prefer_not_pattern = true:suggestion
csharp_style_prefer_pattern_matching = true:silent
csharp_style_prefer_switch_expression = true:suggestion
# Null-checking preferences
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_prefer_static_local_function = true:warning
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
# Code-block preferences
csharp_prefer_braces = true:silent
csharp_prefer_simple_using_statement = true:suggestion
# Expression-level preferences
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_range_operator = true:suggestion
csharp_style_throw_expression = true:suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
# 'using' directive preferences
csharp_using_directive_placement = outside_namespace:silent
#### C# Formatting Rules ####
# New line preferences
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_open_brace = all
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_labels = one_less_than_current
csharp_indent_switch_labels = true
# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# Wrapping preferences
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
#### Naming styles ####
[*.{cs,vb}]
# Naming rules
dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces
dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion
dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces
dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase
dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion
dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters
dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase
dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods
dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties
dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.events_should_be_pascalcase.symbols = events
dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion
dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables
dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase
dotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion
dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants
dotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase
dotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion
dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters
dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase
dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields
dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion
dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields
dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase
dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion
dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields
dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase
dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields
dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields
dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields
dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields
dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums
dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions
dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase
dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase
# Symbol specifications
dotnet_naming_symbols.interfaces.applicable_kinds = interface
dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interfaces.required_modifiers =
dotnet_naming_symbols.enums.applicable_kinds = enum
dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.enums.required_modifiers =
dotnet_naming_symbols.events.applicable_kinds = event
dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.events.required_modifiers =
dotnet_naming_symbols.methods.applicable_kinds = method
dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.methods.required_modifiers =
dotnet_naming_symbols.properties.applicable_kinds = property
dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.properties.required_modifiers =
dotnet_naming_symbols.public_fields.applicable_kinds = field
dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal
dotnet_naming_symbols.public_fields.required_modifiers =
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
dotnet_naming_symbols.private_fields.required_modifiers =
dotnet_naming_symbols.private_static_fields.applicable_kinds = field
dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
dotnet_naming_symbols.private_static_fields.required_modifiers = static
dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum
dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types_and_namespaces.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
dotnet_naming_symbols.type_parameters.applicable_kinds = namespace
dotnet_naming_symbols.type_parameters.applicable_accessibilities = *
dotnet_naming_symbols.type_parameters.required_modifiers =
dotnet_naming_symbols.private_constant_fields.applicable_kinds = field
dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
dotnet_naming_symbols.private_constant_fields.required_modifiers = const
dotnet_naming_symbols.local_variables.applicable_kinds = local
dotnet_naming_symbols.local_variables.applicable_accessibilities = local
dotnet_naming_symbols.local_variables.required_modifiers =
dotnet_naming_symbols.local_constants.applicable_kinds = local
dotnet_naming_symbols.local_constants.applicable_accessibilities = local
dotnet_naming_symbols.local_constants.required_modifiers = const
dotnet_naming_symbols.parameters.applicable_kinds = parameter
dotnet_naming_symbols.parameters.applicable_accessibilities = *
dotnet_naming_symbols.parameters.required_modifiers =
dotnet_naming_symbols.public_constant_fields.applicable_kinds = field
dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal
dotnet_naming_symbols.public_constant_fields.required_modifiers = const
dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal
dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static
dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static
dotnet_naming_symbols.local_functions.applicable_kinds = local_function
dotnet_naming_symbols.local_functions.applicable_accessibilities = *
dotnet_naming_symbols.local_functions.required_modifiers =
# Naming styles
dotnet_naming_style.pascalcase.required_prefix =
dotnet_naming_style.pascalcase.required_suffix =
dotnet_naming_style.pascalcase.word_separator =
dotnet_naming_style.pascalcase.capitalization = pascal_case
dotnet_naming_style.ipascalcase.required_prefix = I
dotnet_naming_style.ipascalcase.required_suffix =
dotnet_naming_style.ipascalcase.word_separator =
dotnet_naming_style.ipascalcase.capitalization = pascal_case
dotnet_naming_style.tpascalcase.required_prefix = T
dotnet_naming_style.tpascalcase.required_suffix =
dotnet_naming_style.tpascalcase.word_separator =
dotnet_naming_style.tpascalcase.capitalization = pascal_case
dotnet_naming_style._camelcase.required_prefix = _
dotnet_naming_style._camelcase.required_suffix =
dotnet_naming_style._camelcase.word_separator =
dotnet_naming_style._camelcase.capitalization = camel_case
dotnet_naming_style.camelcase.required_prefix =
dotnet_naming_style.camelcase.required_suffix =
dotnet_naming_style.camelcase.word_separator =
dotnet_naming_style.camelcase.capitalization = camel_case
dotnet_naming_style.s_camelcase.required_prefix = s_
dotnet_naming_style.s_camelcase.required_suffix =
dotnet_naming_style.s_camelcase.word_separator =
dotnet_naming_style.s_camelcase.capitalization = camel_case
# CommunityToolkit.Mvvm
dotnet_analyzer_diagnostic.category-CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator.severity = none
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
================================================
FILE: .github/copilot-instructions.md
================================================
# Spice 🌶 — Copilot Instructions
Minimal cross-platform mobile UI framework for .NET (iOS + Android). **No** `Microsoft.Maui.Controls`, XAML, DI, MVVM, data-binding, or `System.Reflection`. Views are POCOs mapping to native controls. Uses only `Microsoft.Maui.Graphics` (`Color`) and MAUI's SingleProject + Resizetizer.
## Partial Class Pattern (Core Architecture)
Each view = 3 files: `Core/{Type}.cs` (cross-platform, `[ObservableProperty]`), `Platforms/iOS/{Type}.cs` (UIKit), `Platforms/Android/{Type}.cs` (Android widgets). Platform partials implement `partial void On{Prop}Changed`. Platform files excluded from other TFMs via `Spice.targets`. Follow `Image`/`Label` as templates for new controls.
## Conventions
- **Namespace**: `Spice` only — no sub-namespaces
- **Properties**: `[ObservableProperty]` on `_camelCase` fields → generates `PascalCase` + `On{Prop}Changed`
- **Implicit operators**: `public static implicit operator NativeType(SpiceType)` in platform partials
- **Lazy views**: `Lazy<T> _nativeView` with factory function
- **XML docs**: Required on all public API; include platform mappings (e.g. `Android.Widget.TextView / UIKit.UILabel`)
- **GlobalUsings**: `CommunityToolkit.Mvvm.ComponentModel` + `Color = Microsoft.Maui.Graphics.Color`
- **`VANILLA` define**: Active on `net10.0` only; prefer partials over `#if`
- **Blazor**: `Blazor/` folders at library+platform levels; `BlazorWebView` extends `WebView`
- **iOS memory**: NSObject subclasses must not hold strong references to other NSObjects (causes cycles the garbage collector cannot break). Use `WeakReference<T>` for any NSObject-typed field/property in an NSObject subclass. Enforced by [`MemoryAnalyzers`](https://github.com/jonathanpeppers/memory-analyzers) (MEM0001–MEM0003).
## Layout
```
src/Spice/Core/ cross-platform views
src/Spice/Platforms/ iOS + Android partials, entry points
src/Spice/Blazor/ cross-platform Blazor; platform Blazor in Platforms/*/Blazor/
src/Spice/MSBuild/ Spice.props (capabilities), Spice.targets (inlined SingleProject)
samples/ Spice.Scenarios, Spice.BlazorSample, HeadToHead*
tests/Spice.Tests/ xUnit on net10.0 — views tested as POCOs, no device needed
sizes/ .apkdesc baselines for CI apkdiff (10% APK / 15% content thresholds)
src/Spice.Templates/ dotnet new spice / spice-blazor
```
## Build & Test
```sh
dotnet build # all TFMs (needs maui-android + maui-ios workloads)
dotnet build -f net10.0-android -t:Run # run Android
dotnet build -f net10.0-ios -t:Run # run iOS
dotnet test tests/Spice.Tests/Spice.Tests.csproj # unit tests (net10.0, no device)
```
## Entry Points
- **iOS**: Scene-based. `SpiceAppDelegate<TApp>` + `SpiceSceneDelegate<TApp>`. Consumers: `class AppDelegate : SpiceAppDelegate<App> { }`. Requires `UIApplicationSceneManifest` in Info.plist. Window via `Platform.Window`.
- **Android**: `SpiceActivity : AppCompatActivity`. Sets `Platform.Context`. Consumers call `SetContentView(new App())`.
## MSBuild
`Spice.targets` inlines MAUI's SingleProject logic (platform folder filtering, IDE capabilities) because Spice doesn't reference MAUI Controls. Do not add a `Microsoft.Maui.Controls` dependency.
## CI
`macos-latest`: build → apkdiff size check → test → pack. Update baselines: `apkdiff -s --save-description-2=sizes/{name}.apkdesc`.
================================================
FILE: .github/dependabot.yml
================================================
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "nuget"
directory: "/" # Location of package manifests
schedule:
interval: "daily"
================================================
FILE: .github/workflows/copilot-setup-steps.yml
================================================
name: "Copilot Setup Steps"
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
permissions:
contents: read
env:
WORKLOAD_VERSION: 10.0.103
steps:
- name: checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: install .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: install workloads
run: dotnet workload install maui-android --version $WORKLOAD_VERSION
================================================
FILE: .github/workflows/spice.yml
================================================
name: build
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: macos-latest
env:
WORKLOAD_VERSION: 10.0.103
ValidateXcodeVersion: false
APK_PERCENTAGE_REGRESSION: 10
CONTENT_PERCENTAGE_REGRESSION: 15
steps:
- name: checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: select Xcode version
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: install .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.slnx', '**/Directory.Build.props', '**/Directory.Build.targets') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: install workloads
run: dotnet workload install maui-android maui-ios --version $WORKLOAD_VERSION
- name: restore all projects
run: |
dotnet restore spice.slnx
dotnet restore samples/samples.slnx
- name: build main solution (Release)
run: dotnet build spice.slnx -c Release --no-restore -bl:bin/build-main.binlog -maxcpucount
- name: build samples (Debug, faster)
run: dotnet build samples/samples.slnx -c Debug --no-restore -bl:bin/build-samples.binlog -maxcpucount
- name: tests
run: dotnet test tests/Spice.Tests/Spice.Tests.csproj -f net10.0 -c Release --no-build
- name: pack
run: dotnet pack spice.slnx -c Release --no-build -bl:bin/pack.binlog
- name: build templates
run: |
dotnet new install src/Spice.Templates
mkdir -p bin/templates && cd bin/templates
dotnet new spice -n Hello
dotnet new spice-blazor -n HelloBlazor
TARGETS='<Project><PropertyGroup><RestorePackagesPath>$(MSBuildThisFileDirectory)packages</RestorePackagesPath><RestoreAdditionalProjectSources>$(MSBuildThisFileDirectory)../../../bin/Release/</RestoreAdditionalProjectSources><RestoreNoCache>true</RestoreNoCache></PropertyGroup></Project>'
echo $TARGETS > Hello/Directory.Build.targets
echo $TARGETS > HelloBlazor/Directory.Build.targets
echo '<Project />' > Directory.Build.props
echo '<Project />' > Directory.Build.targets
dotnet build Hello/Hello.csproj -f net10.0-android -c Release -r android-arm64
dotnet build HelloBlazor/HelloBlazor.csproj -f net10.0-android -c Release -r android-arm64
- name: run apkdiff
run: |
dotnet tool install --global apkdiff
apkdiff -s --save-description-2=bin/com.companyname.Hello-Signed.apkdesc --descrease-is-regression --test-apk-percentage-regression=$APK_PERCENTAGE_REGRESSION --test-content-percentage-regression=$CONTENT_PERCENTAGE_REGRESSION sizes/com.companyname.Hello-Signed.apkdesc bin/templates/Hello/bin/Release/net10.0-android/android-arm64/com.companyname.Hello-Signed.apk
apkdiff -s --save-description-2=bin/com.companyname.HelloBlazor-Signed.apkdesc --descrease-is-regression --test-apk-percentage-regression=$APK_PERCENTAGE_REGRESSION --test-content-percentage-regression=$CONTENT_PERCENTAGE_REGRESSION sizes/com.companyname.HelloBlazor-Signed.apkdesc bin/templates/HelloBlazor/bin/Release/net10.0-android/android-arm64/com.companyname.HelloBlazor-Signed.apk
- name: artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: nupkgs
path: bin
device-tests-android:
runs-on: ubuntu-latest
env:
WORKLOAD_VERSION: 10.0.103
steps:
- name: checkout
uses: actions/checkout@v4
- name: enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: install .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.slnx', '**/Directory.Build.props', '**/Directory.Build.targets') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: install workloads
run: dotnet workload install maui-android --version $WORKLOAD_VERSION
- name: restore .NET tools
run: dotnet tool restore
- name: restore test app
run: dotnet msbuild tests/Spice.Tests/Spice.Tests.csproj -t:Restore -p:TargetFramework=net10.0-android -p:RuntimeIdentifier=android-x64
- name: build test app
run: dotnet build tests/Spice.Tests/Spice.Tests.csproj -f net10.0-android -c Release -r android-x64 --no-restore -bl:bin/build-device-tests-android.binlog
- name: run Android device tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 34
target: google_apis
arch: x86_64
script: dotnet xharness android test --app="tests/Spice.Tests/bin/Release/net10.0-android/android-x64/com.jonathanpeppers.spice.tests-Signed.apk" --package-name="com.jonathanpeppers.spice.tests" --instrumentation="com.jonathanpeppers.spice.tests.TestInstrumentation" --output-directory=bin/device-test-results/android --timeout=00:10:00
- name: publish test results
if: always()
uses: actions/upload-artifact@v4
with:
name: device-test-results-android
path: bin/device-test-results/android
device-tests-ios:
runs-on: macos-latest
env:
WORKLOAD_VERSION: 10.0.103
ValidateXcodeVersion: false
steps:
- name: checkout
uses: actions/checkout@v4
- name: select Xcode version
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: install .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.slnx', '**/Directory.Build.props', '**/Directory.Build.targets') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: install workloads
run: dotnet workload install maui-ios --version $WORKLOAD_VERSION
- name: restore .NET tools
run: dotnet tool restore
- name: restore test app
run: dotnet msbuild tests/Spice.Tests/Spice.Tests.csproj -t:Restore -p:TargetFramework=net10.0-ios -p:RuntimeIdentifier=iossimulator-arm64
- name: build test app
run: dotnet build tests/Spice.Tests/Spice.Tests.csproj -f net10.0-ios -c Release -r iossimulator-arm64 --no-restore -bl:bin/build-device-tests-ios.binlog
- name: run iOS device tests
run: >
dotnet xharness apple test
--app="tests/Spice.Tests/bin/Release/net10.0-ios/iossimulator-arm64/Spice.Tests.app"
--output-directory=bin/device-test-results/ios
--target=ios-simulator-64
--timeout=00:15:00
--launch-timeout=00:10:00
--communication-channel=Network
- name: collect simulator logs
if: always()
run: |
# Grab the most recent simulator device log
UDID=$(xcrun simctl list devices booted -j | python3 -c "import sys,json; devs=[d for r in json.load(sys.stdin)['devices'].values() for d in r if d['state']=='Booted']; print(devs[0]['udid'] if devs else '')" 2>/dev/null || true)
if [ -n "$UDID" ]; then
LOG_DIR="$HOME/Library/Logs/DiagnosticReports"
mkdir -p bin/device-test-results/ios
cp "$LOG_DIR"/*.ips bin/device-test-results/ios/ 2>/dev/null || true
# Also grab the system log from the simulator
xcrun simctl spawn "$UDID" log show --last 5m --predicate 'process == "Spice.Tests"' > bin/device-test-results/ios/simulator-system.log 2>&1 || true
fi
- name: publish test results
if: always()
uses: actions/upload-artifact@v4
with:
name: device-test-results-ios
path: bin/device-test-results/ios
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
# macOS
.DS_Store
.idea/
================================================
FILE: .vscode/settings.json
================================================
{
"dotnet.defaultSolution": "spice.sln"
}
================================================
FILE: Directory.Build.props
================================================
<Project>
<PropertyGroup>
<!-- Projects have to opt in -->
<IsPackable>false</IsPackable>
<Version>0.2.0</Version>
<PackageVersion>$(Version)-beta.1</PackageVersion>
<Authors>Jonathan Peppers</Authors>
<PackageProjectUrl>https://github.com/jonathanpeppers/spice</PackageProjectUrl>
<PackageTags>.NET C# MAUI Mobile Android iOS</PackageTags>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>icon.png</PackageIcon>
<PackageOutputPath>$(MSBuildThisFileDirectory)bin/$(Configuration)/</PackageOutputPath>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<!-- Show all trimmer warnings/errors in this repo, not just one per assembly -->
<TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>
</Project>
================================================
FILE: Directory.Build.targets
================================================
<Project>
<PropertyGroup>
<!-- Weird fix for VS Mac -->
<CreatePackage Condition=" '$(TargetFramework)' == 'net10.0-ios' ">false</CreatePackage>
</PropertyGroup>
<ItemGroup>
<PackageReference Update="Microsoft.Maui.Resizetizer" Version="10.0.40" />
</ItemGroup>
</Project>
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 Jonathan Peppers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: NuGet.config
================================================
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
</packageSources>
</configuration>
================================================
FILE: README.md
================================================
# Spice 🌶, a spicy cross-platform UI framework!
A prototype (and design) of API minimalism for mobile.
If you like this idea, star for approval! Read on for details!

## Getting Started
Simply install the template:
```sh
dotnet new install Spice.Templates
```
Create either a plain Spice project, or a hybrid "Spice+Blazor" project:
```sh
dotnet new spice
# Or if you want hybrid/web support
dotnet new spice-blazor
```
Or use the project template in Visual Studio:

Build it as you would for other .NET MAUI projects:
```sh
dotnet build
# To run on Android
dotnet build -f net10.0-android -t:Run
# To run on iOS
dotnet build -f net10.0-ios -t:Run
```
Of course, you can also just open the project in Visual Studio and hit F5.
## Startup Time & App Size
In comparison to a `dotnet new maui` project, I created a Spice
project with the same layouts and optimized settings for both project
types. (`AndroidLinkMode=r8`, etc.)
App size of a single-architecture `.apk`, built for `android-arm64`:

The average startup time of 10 runs on a Pixel 5:

This gives you an idea of how much "stuff" is in .NET MAUI.
In some respects the above comparison isn't completely fair, as Spice
🌶 has very few features. However, Spice 🌶 is [fully
trimmable][trimming], and so a `Release` build of an app without
`Spice.Button` will have the code for `Spice.Button` trimmed away. It
will be quite difficult for .NET MAUI to become [fully
trimmable][trimming] -- due to the nature of XAML, data-binding, and
other System.Reflection usage in the framework.
[trimming]: https://learn.microsoft.com/dotnet/core/deploying/trimming/prepare-libraries-for-trimming
## Background & Motivation
In reviewing, many of the *cool* UI frameworks for mobile:
* [Flutter](https://flutter.dev)
* [SwiftUI](https://developer.apple.com/xcode/swiftui/)
* [Jetpack Compose](https://developer.android.com/jetpack/compose)
* [Fabulous](https://fabulous.dev/)
* [Comet](https://github.com/dotnet/Comet)
* An, of course, [.NET MAUI](https://dotnet.microsoft.com/apps/maui)!
Looking at what apps look like today -- it seems like bunch of
rigamarole to me. Can we build mobile applications *without* design
patterns?
The idea is we could build apps in a simple way, in a similar vein as
[minimal APIs in ASP.NET Core][minimal-apis] but for mobile & maybe
one day desktop:
```csharp
public class App : Application
{
public App()
{
int count = 0;
var label = new Label
{
Text = "Hello, Spice 🌶",
};
var button = new Button
{
Text = "Click Me",
Clicked = _ => label.Text = $"Times: {++count}"
};
Main = new StackLayout { label, button };
}
}
```
These "view" types are mostly just [POCOs][poco].
Thus you can easily write unit tests in a vanilla `net10.0` Xunit
project, such as:
```csharp
[Fact]
public void Application()
{
var app = new App();
var label = (Label)app.Main.Children[0];
var button = (Button)app.Main.Children[1];
button.Clicked(button);
Assert.Equal("Times: 1", label.Text);
button.Clicked(button);
Assert.Equal("Times: 2", label.Text);
}
```
The above views in a `net10.0` project are not real UI, while
`net10.0-android` and `net10.0-ios` projects get the full
implementations that actually *do* something on screen.
So for example, adding `App` to the screen on Android:
```csharp
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(new App());
}
```
And on iOS:
```csharp
var vc = new UIViewController();
vc.View.AddSubview(new App());
Window.RootViewController = vc;
```
`App` is a native view on both platforms. You just add it to an the
screen as you would any other control or view. This can be mix &
matched with regular iOS & Android UI because Spice 🌶 views are just
native views.
[poco]: https://en.wikipedia.org/wiki/Plain_old_CLR_object
[minimal-apis]: https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis
## *NEW* Blazor Support
Currently, Blazor/Hybrid apps are strongly tied to .NET MAUI. The
implementation is basically working with the plumbing of the native
"web view" on each platform. So we could have implemented
`BlazorWebView` to be used in "plain" `dotnet new android` or
`dotnet new ios` apps. For now, I've migrated some of the source code
from `BlazorWebView` from .NET MAUI to Spice 🌶, making it available
as a new control:
```csharp
public class App : Application
{
public App()
{
Main = new BlazorWebView
{
HostPage = "wwwroot/index.html",
RootComponents =
{
new RootComponent { Selector = "#app", ComponentType = typeof(Main) }
},
};
}
}
```
From here, you can write `Index.razor` as the Blazor you know and love:
```razor
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
```
To arrive at Blazor web content inside iOS/Android apps:

This setup might be particularly useful if you want web content to
take full control of the screen with minimal native controls. No need
for the app size / startup overhead of .NET MAUI if you don't actually
have native content?
## Scope
* No XAML. No DI. No MVVM. No MVC. No data-binding. No System.Reflection.
* *Do we need these things?*
* Target iOS & Android only to start.
* Implement only the simplest controls.
* The native platforms do their own layout.
* Document how to author custom controls.
* Leverage C# Hot Reload for fast development.
* Measure startup time & app size.
* Profit?
Benefits of this approach are full support for [trimming][trimming]
and eventually [NativeAOT][nativeaot] if it comes to mobile one day. 😉
[nativeaot]: https://learn.microsoft.com/dotnet/core/deploying/native-aot/
## Thoughts on .NET MAUI
.NET MAUI is great. XAML is great. Think of this idea as a "mini"
MAUI.
Spice 🌶 will even leverage various parts of .NET MAUI:
* The iOS and Android workloads for .NET.
* The .NET MAUI "Single Project" system.
* The .NET MAUI "Asset" system, aka Resizetizer.
* Microsoft.Maui.Graphics for primitives like `Color`.
And, of course, you should be able to use Microsoft.Maui.Essentials by
opting in with `UseMauiEssentials=true`.
It is an achievement in itself that I was able to invent my own UI
framework and pick and choose the pieces of .NET MAUI that made sense
for my framework.
## Implemented Controls
* `View`: maps to `Android.Views.View` and `UIKit.View`.
* `Label`: maps to `Android.Widget.TextView` and `UIKit.UILabel`
* `Button`: maps to `Android.Widget.Button` and `UIKit.UIButton`
* `StackLayout`: maps to `Android.Widget.LinearLayout` and `UIKit.UIStackView`
* `Image`: maps to `Android.Widget.ImageView` and `UIKit.UIImageView`
* `Entry`: maps to `Android.Widget.EditText` and `UIKit.UITextField`
* `WebView`: maps to `Android.Webkit.WebView` and `WebKit.WKWebView`
* `BlazorWebView` extends `WebView` adding support for Blazor. Use the
`spice-blazor` template to get started.
## Custom Controls
Let's review an implementation for `Image`.
First, you can write the cross-platform part for a vanilla `net10.0`
class library:
```csharp
public partial class Image : View
{
[ObservableProperty]
string _source = "";
}
```
`[ObservableProperty]` comes from the [MVVM Community
Toolkit][observable] -- I made use of it for simplicity. It will
automatically generate various `partial` methods,
`INotifyPropertyChanged`, and a `public` property named `Source`.
We can implement the control on Android, such as:
```csharp
public partial class Image
{
public static implicit operator ImageView(Image image) => image.NativeView;
public Image() : base(c => new ImageView(c)) { }
public new ImageView NativeView => (ImageView)_nativeView.Value;
partial void OnSourceChanged(string value)
{
// NOTE: the real implementation is in Java for performance reasons
var image = NativeView;
var context = image.Context;
int id = context!.Resources!.GetIdentifier(value, "drawable", context.PackageName);
if (id != 0)
{
image.SetImageResource(id);
}
}
}
```
This code takes the name of an image, and looks up a drawable with the
same name. This also leverages the .NET MAUI asset system, so a
`spice.svg` can simply be loaded via `new Image { Source = "spice" }`.
Lastly, the iOS implementation:
```csharp
public partial class Image
{
public static implicit operator UIImageView(Image image) => image.NativeView;
public Image() : base(_ => new UIImageView { AutoresizingMask = UIViewAutoresizing.None }) { }
public new UIImageView NativeView => (UIImageView)_nativeView.Value;
partial void OnSourceChanged(string value) => NativeView.Image = UIImage.FromFile($"{value}.png");
}
```
This implementation is a bit simpler, all we have to do is call
`UIImage.FromFile()` and make sure to append a `.png` file extension
that the MAUI asset system generates.
Now, let's say you don't want to create a control from scratch.
Imagine a "ghost button":
```csharp
class GhostButton : Button
{
public GhostButton() => NativeView.Alpha = 0.5f;
}
```
In this case, the `NativeView` property returns the underlying
`Android.Widget.Button` or `UIKit.Button` that both conveniently have
an `Alpha` property that ranges from 0.0f to 1.0f. The same code
works on both platforms!
Imagine the APIs were different, you could instead do:
```csharp
class GhostButton : Button
{
public GhostButton
{
#if ANDROID
NativeView.SomeAndroidAPI(0.5f);
#elif IOS
NativeView.SomeiOSAPI(0.5f);
#endif
}
}
```
Accessing the native views don't require any weird design patterns.
Just `#if` as you please.
[observable]: https://learn.microsoft.com/dotnet/communitytoolkit/mvvm/generators/observableproperty
## Hot Reload
C# Hot Reload (in Visual Studio) works fine, as it does for vanilla .NET
iOS/Android apps:

Note that this only works for `Button.Clicked` because the method is
invoked when you click. If the method that was changed was already
run, *something* has to force it to run again.
[`MetadataUpdateHandler`][muh] is the solution to this problem, giving
frameworks a way to "reload themselves" for Hot Reload.
Unfortunately, [`MetadataUpdateHandler`][muh] does not currently work
for non-MAUI apps in Visual Studio 2022 17.5:
```csharp
[assembly: System.Reflection.Metadata.MetadataUpdateHandler(typeof(HotReload))]
static class HotReload
{
static void UpdateApplication(Type[]? updatedTypes)
{
if (updatedTypes == null)
return;
foreach (var type in updatedTypes)
{
// Do something with the type
Console.WriteLine("UpdateApplication: " + type);
}
}
}
```
The above code works fine in a `dotnet new maui` app, but not a
`dotnet new spice` or `dotnet new android` application.
And so we can't add proper functionality for reloading `ctor`'s of
Spice 🌶 views. The general idea is we could recreate the `App` class and
replace the views on screen. We could also create Android activities
or iOS view controllers if necessary.
Hopefully, we can implement this for a future release of Visual Studio.
[muh]: https://learn.microsoft.com/dotnet/api/system.reflection.metadata.metadataupdatehandlerattribute
================================================
FILE: docs/DATA-BINDING-SPEC.md
================================================
# Data-Binding in Spice 🌶
**Status:** Design Specification
**Created:** February 2026
## Overview
Spice views already extend `ObservableObject` (via CommunityToolkit.Mvvm), so every `View`,
`Label`, `CheckBox`, etc. implements `INotifyPropertyChanged` out of the box. This spec
proposes a small `Bind()` helper that wires `PropertyChanged` subscriptions with less
boilerplate — while staying NativeAOT safe, trimmer safe, and reflection-free.
## What We Have Today
Direct lambda assignments — explicit, transparent, zero magic:
```csharp
public class App : Application
{
public App()
{
int count = 0;
var label = new Label { Text = "Hello, Spice 🌶" };
var button = new Button
{
Clicked = _ => label.Text = $"Times: {++count}"
};
Main = new StackLayout { label, button };
}
}
```
For larger UIs, a ViewModel with manual `PropertyChanged` wiring works but gets verbose:
```csharp
var vm = new TodoViewModel();
var titleLabel = new Label();
var countLabel = new Label();
var checkbox = new CheckBox();
vm.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(TodoViewModel.Title))
titleLabel.Text = vm.Title;
else if (e.PropertyName == nameof(TodoViewModel.Count))
countLabel.Text = $"Count: {vm.Count}";
else if (e.PropertyName == nameof(TodoViewModel.IsCompleted))
checkbox.IsChecked = vm.IsCompleted;
};
// Reverse: view → viewmodel (Action<CheckBox> property, not an event)
checkbox.CheckedChanged = cb => vm.IsCompleted = cb.IsChecked;
Main = new StackLayout { titleLabel, countLabel, checkbox };
```
## Proposed: `Bind()` Helper
### Core API
One method, no expression trees, no reflection:
```csharp
namespace Spice;
public static class BindingExtensions
{
/// <summary>
/// One-way binding: subscribes to source.PropertyChanged and invokes
/// <paramref name="apply"/> whenever the named property changes.
/// Sets the initial value immediately.
/// </summary>
public static IDisposable Bind<TSource, TValue>(
this TSource source,
string propertyName,
Func<TSource, TValue> getter,
Action<TValue> apply)
where TSource : INotifyPropertyChanged
{
// Sync initial value
apply(getter(source));
PropertyChangedEventHandler handler = (_, e) =>
{
if (e.PropertyName == propertyName)
apply(getter(source));
};
source.PropertyChanged += handler;
return new BindingSubscription(source, handler);
}
}
internal sealed class BindingSubscription : IDisposable
{
private readonly INotifyPropertyChanged _source;
private readonly PropertyChangedEventHandler _handler;
private bool _disposed;
public BindingSubscription(INotifyPropertyChanged source, PropertyChangedEventHandler handler)
{
_source = source;
_handler = handler;
}
public void Dispose()
{
if (!_disposed)
{
_source.PropertyChanged -= _handler;
_disposed = true;
}
}
}
```
Usage with `nameof()` keeps everything compile-time safe:
```csharp
vm.Bind(nameof(vm.Title), v => v.Title, text => titleLabel.Text = text);
vm.Bind(nameof(vm.Count), v => v.Count, n => countLabel.Text = $"Count: {n}");
```
### Why Not `Expression<Func<TSource, TValue>>`?
An expression-tree overload like `vm.Bind(x => x.Title, ...)` is ergonomically nicer, but
`Expression.Compile()` internally uses `Reflection.Emit` (or an interpreter on .NET 8+).
For a library that promises NativeAOT safety, introducing expression trees is a real trade-off:
- ✅ Works on .NET 8+ NativeAOT via the built-in interpreter
- ⚠️ Slower than a plain `Func<>` (interpreter overhead + one-time compile cost)
- ⚠️ Adds `System.Linq.Expressions` as a de facto dependency
- ❌ Fails on older NativeAOT runtimes without the interpreter
If the convenience is deemed worth it, an **optional** overload can be added alongside
the `nameof` version — never as the only option:
```csharp
// Optional convenience overload (expression tree)
public static IDisposable Bind<TSource, TValue>(
this TSource source,
Expression<Func<TSource, TValue>> propertySelector,
Action<TValue> apply)
where TSource : INotifyPropertyChanged
{
string name = ((MemberExpression)propertySelector.Body).Member.Name;
var getter = propertySelector.Compile();
return source.Bind(name, getter, apply);
}
```
### Two-Way Binding
Since Spice views **already implement `INotifyPropertyChanged`**, true two-way binding is
straightforward — subscribe in both directions with a guard to prevent infinite loops:
```csharp
public static IDisposable BindTwoWay<TSource, TValue>(
this TSource source,
string sourceProperty,
Func<TSource, TValue> sourceGetter,
Action<TSource, TValue> sourceSetter,
INotifyPropertyChanged target,
string targetProperty,
Func<TValue> targetGetter,
Action<TValue> targetSetter)
where TSource : INotifyPropertyChanged
{
bool updating = false;
targetSetter(sourceGetter(source)); // initial sync
PropertyChangedEventHandler sourceHandler = (_, e) =>
{
if (!updating && e.PropertyName == sourceProperty)
{
updating = true;
targetSetter(sourceGetter(source));
updating = false;
}
};
PropertyChangedEventHandler targetHandler = (_, e) =>
{
if (!updating && e.PropertyName == targetProperty)
{
updating = true;
sourceSetter(source, targetGetter());
updating = false;
}
};
source.PropertyChanged += sourceHandler;
target.PropertyChanged += targetHandler;
return new TwoWayBindingSubscription(source, sourceHandler, target, targetHandler);
}
```
Usage — ViewModel ↔ Entry (both are ObservableObjects):
```csharp
vm.BindTwoWay(
nameof(vm.Username), v => v.Username, (v, val) => v.Username = val,
usernameEntry,
nameof(Entry.Text), () => usernameEntry.Text, val => usernameEntry.Text = val);
```
This is verbose, which is intentional — it makes data flow explicit. For common cases,
convenience overloads or a fluent builder could be added later.
## Usage Examples
### Simple One-Way
```csharp
public class CounterApp : Application
{
public CounterApp()
{
var vm = new CounterViewModel();
var label = new Label();
var button = new Button
{
Text = "Increment",
Clicked = _ => vm.Count++
};
vm.Bind(nameof(vm.Count), v => v.Count, n => label.Text = $"Count: {n}");
Main = new StackLayout { label, button };
}
}
```
### CollectionView with Per-Item Binding
For CollectionView recycling, wrap the template in a custom `IDisposable` View:
```csharp
public class TodoItemView : StackLayout, IDisposable
{
private IDisposable? _titleBinding;
public TodoItemView(TodoItem item)
{
var label = new Label();
var checkbox = new CheckBox();
// One-way: model → view
_titleBinding = item.Bind(nameof(item.Title), t => t.Title,
text => label.Text = text);
item.Bind(nameof(item.IsCompleted), t => t.IsCompleted,
done => checkbox.IsChecked = done);
// Reverse: view → model
checkbox.CheckedChanged = cb => item.IsCompleted = cb.IsChecked;
Children.Add(new StackLayout { label, checkbox });
}
public void Dispose()
{
_titleBinding?.Dispose();
}
}
var collectionView = new CollectionView
{
ItemsSource = vm.Items,
ItemTemplate = item => new TodoItemView((TodoItem)item)
};
```
When the view is recycled, `Dispose()` will be called and subscriptions cleaned up.
See [VIEW-LIFECYCLE-SPEC.md](./VIEW-LIFECYCLE-SPEC.md) for details.
## Memory Management
`Bind()` returns `IDisposable`. In most Spice apps, bindings live as long as the view, so
disposal is unnecessary. For short-lived views bound to long-lived sources, dispose explicitly:
```csharp
var binding = vm.Bind(nameof(vm.Title), v => v.Title, text => label.Text = text);
// ...
binding.Dispose(); // unsubscribes from PropertyChanged
```
Multiple bindings can be grouped with `CompositeDisposable` or a simple list:
```csharp
var bindings = new List<IDisposable>
{
vm.Bind(nameof(vm.Title), v => v.Title, t => label.Text = t),
vm.Bind(nameof(vm.Count), v => v.Count, n => countLabel.Text = $"{n}"),
};
// Dispose all at once
foreach (var b in bindings) b.Dispose();
```
## Alternatives Considered
| Approach | Pros | Cons |
|---|---|---|
| **Manual `PropertyChanged` (status quo)** | Zero abstraction, fully explicit | Verbose, error-prone string matching |
| **`nameof` + `Func<>` (this proposal)** | NativeAOT safe, no new dependencies | Property name repeated in `nameof()` call |
| **`Expression<Func<>>` only** | Ergonomic (`x => x.Title`) | `Expression.Compile()` has NativeAOT caveats |
| **Source generator** | Zero runtime cost, best ergonomics | Significant implementation effort, new tooling |
| **CallerArgumentExpression hack** | No expression trees | Fragile string parsing, breaks with refactoring |
The `nameof` + `Func<>` approach is the right default for Spice: zero new dependencies,
truly NativeAOT safe, and the `nameof()` repetition is a minor cost for full transparency.
## Future Work
1. **View lifecycle** — Add `Detached` event to `View` for CollectionView recycling cleanup
2. **Source generator** — Compile-time codegen to eliminate `nameof()` boilerplate
3. **Value converters** — `Bind(..., converter: boolToColor)` for transformations
## Summary
- Spice views already implement `INotifyPropertyChanged` — leverage it
- `Bind()` is a thin helper over `PropertyChanged`, not a framework
- `nameof()` + `Func<>` = truly NativeAOT safe, no expression trees required
- Two-way binding works because both sides are `ObservableObject`
- Expression-tree overload is opt-in, not the default
================================================
FILE: docs/MAUI-CONTROLS-COMPARISON.md
================================================
# .NET MAUI Controls vs Spice Implementation Status
This document compares the stable/supported controls from .NET MAUI with what is currently implemented in Spice.
## Pages
| MAUI Control | Implemented in Spice | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| ContentPage | ❌ No | ❌ No | Spice uses a different architecture without MAUI Controls |
| FlyoutPage | ❌ No | ❌ No | Spice uses a different architecture without MAUI Controls |
| NavigationPage | ❌ No | ❌ No | Spice uses a different architecture without MAUI Controls |
| TabbedPage | ❌ No | ❌ No | Spice uses a different architecture without MAUI Controls |
## Layouts
| MAUI Control | Implemented in Spice | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| AbsoluteLayout | ❌ No | ❌ No | Rare use case, complex |
| BindableLayout | ❌ No | ❌ No | Binding-focused pattern |
| FlexLayout | ❌ No | 🟡 Maybe | Powerful but complex CSS flexbox |
| Grid | ✅ Yes | ✅ Done | Essential for complex layouts |
| HorizontalStackLayout | ❌ No | ❌ No | StackLayout with Horizontal orientation |
| StackLayout | ✅ Yes | ✅ Done | Fully implemented |
| VerticalStackLayout | ❌ No | ❌ No | StackLayout with Vertical orientation |
## Views
| MAUI Control | Implemented in Spice | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| ActivityIndicator | ✅ Yes | ✅ Done | Loading spinner - very common |
| BlazorWebView | ✅ Yes | ✅ Done | Extends `WebView` in Blazor/ folders |
| Border | ✅ Yes | ✅ Done | Useful for rounded corners/borders |
| BoxView | ✅ Yes | ✅ Done | Colored rectangles - useful for dividers |
| Button | ✅ Yes | ✅ Done | Fully implemented |
| CarouselView | ❌ No | ❌ No | Complex, less common |
| CheckBox | ✅ Yes | ✅ Done | Standard checkbox input |
| CollectionView | ✅ Yes | ✅ Done | Powerful grid/list control |
| ContentView | ✅ Yes | ✅ Done | Custom control composition |
| DatePicker | ✅ Yes | ✅ Done | Date selection - common in forms |
| Editor | ✅ Yes | ✅ Done | Multi-line text input |
| Ellipse | ❌ No | 🟢 Maybe | Shape control - can use Image |
| Entry | ✅ Yes | ✅ Done | Single-line text input |
| Frame | ❌ No | ❌ No | Superseded by Border |
| GraphicsView | ❌ No | ❌ No | Advanced - Microsoft.Maui.Graphics available |
| HybridWebView | ❌ No | ❌ No | Specialized, newer control |
| Image | ✅ Yes | ✅ Done | Fully implemented |
| ImageButton | ✅ Yes | ✅ Done | Common pattern (Image + tap) |
| IndicatorView | ❌ No | ❌ No | Depends on CarouselView |
| Label | ✅ Yes | ✅ Done | Fully implemented |
| Line | ❌ No | ❌ No | Shape control - can use BoxView |
| ListView | ❌ No | 🟡 Yes | Scrollable lists - very common |
| Map | ❌ No | ❌ No | External dependency |
| Path | ❌ No | ❌ No | Complex shapes - can use Image |
| Picker | ✅ Yes | ✅ Done | Dropdown selection - essential |
| Polygon | ❌ No | ❌ No | Shape control - can use Image |
| Polyline | ❌ No | ❌ No | Shape control - can use Image |
| ProgressBar | ✅ Yes | ✅ Done | Progress display - common |
| RadioButton | ✅ Yes | ✅ Done | Single selection from a group; uses cross-platform GroupName (no Android RadioGroup) because iOS lacks a native radio button |
| Rectangle | ❌ No | 🟢 Maybe | Shape control - BoxView covers this |
| RefreshView | ✅ Yes | ✅ Done | Pull-to-refresh wrapper |
| RoundRectangle | ❌ No | ❌ No | Border can handle this |
| ScrollView | ✅ Yes | ✅ Done | Fully implemented |
| SearchBar | ✅ Yes | ✅ Done | Search input with search button |
| Slider | ✅ Yes | ✅ Done | Range selection - common |
| Stepper | ❌ No | ❌ No | Rare, can use buttons + label |
| SwipeView | ✅ Yes | ✅ Done | Swipe actions - nice UX feature |
| Switch | ✅ Yes | ✅ Done | Toggle control - essential |
| TableView | ❌ No | ❌ No | Settings-style list (less common) |
| TimePicker | ✅ Yes | ✅ Done | Time selection - common in forms |
| TitleBar | ❌ No | ❌ No | Desktop-focused |
| TwoPaneView | ❌ No | ❌ No | Foldable-specific |
| WebView | ✅ Yes | ✅ Done | Fully implemented |
## Summary
**Implemented: 26 / 60+ controls**
### Spice Controls (Core)
- ✅ ActivityIndicator
- ✅ Application
- ✅ Border
- ✅ BoxView
- ✅ Button
- ✅ CheckBox
- ✅ CollectionView
- ✅ ContentView
- ✅ DatePicker
- ✅ Editor (multi-line text)
- ✅ Entry (single-line text)
- ✅ Grid
- ✅ Image
- ✅ ImageButton
- ✅ Label
- ✅ Picker
- ✅ ProgressBar
- ✅ RadioButton
- ✅ RefreshView
- ✅ ScrollView
- ✅ SearchBar
- ✅ Slider
- ✅ StackLayout
- ✅ SwipeView
- ✅ Switch (toggle control)
- ✅ TimePicker (time selection)
- ✅ View (base class)
- ✅ WebView
- ✅ BlazorWebView (Blazor-specific)
### Supporting Types
- LayoutAlignment (enums for alignment)
- LayoutOptions (alignment with expansion)
- Orientation (horizontal/vertical)
- RootComponent (Blazor)
- SelectionMode (selection in lists)
- SwipeBehaviorOnInvoked, SwipeDirection, SwipeItem, SwipeItems, SwipeMode (swipe gesture support)
### Key Differences
- **No XAML**: Spice uses POCOs, not XAML markup
- **No Data Binding**: No `System.Reflection` or binding infrastructure
- **No MVVM**: Direct code, no ViewModels required
- **Partial Class Pattern**: Each control has cross-platform Core + iOS + Android partials
- **Minimal Dependencies**: Only uses `Microsoft.Maui.Graphics` (Color) and MAUI's SingleProject
### Platform Mappings
#### iOS (UIKit)
- ActivityIndicator → UIActivityIndicatorView
- Border → UIView (with CALayer border)
- BoxView → UIView
- Button → UIButton
- CheckBox → UIButton (with checkmark styling)
- CollectionView → UICollectionView
- ContentView → UIView
- DatePicker → UIDatePicker
- Editor → UITextView
- Entry → UITextField
- Grid → Custom constraint-based layout
- Image → UIImageView
- ImageButton → UIButton
- Label → UILabel
- Picker → UIPickerView
- ProgressBar → UIProgressView
- RadioButton → UIButton (with circle/circle.fill SF Symbols; cross-platform GroupName for exclusivity)
- RefreshView → UIView with UIRefreshControl
- ScrollView → UIScrollView
- SearchBar → UISearchBar
- Slider → UISlider
- StackLayout → UIStackView
- SwipeView → UIView with gesture recognizers
- Switch → UISwitch
- TimePicker → UIDatePicker (Mode = Time)
- WebView → WKWebView
#### Android (Android Widgets)
- ActivityIndicator → ProgressBar (indeterminate)
- Border → FrameLayout (with GradientDrawable background)
- BoxView → View
- Button → AppCompatButton
- CheckBox → CheckBox
- CollectionView → AndroidX.RecyclerView.Widget.RecyclerView
- ContentView → FrameLayout
- DatePicker → DatePickerDialog
- Editor → EditText (multiline)
- Entry → AppCompatEditText
- Grid → GridLayout
- Image → AppCompatImageView
- ImageButton → ImageButton
- Label → AppCompatTextView
- Picker → Spinner
- ProgressBar → ProgressBar
- RadioButton → Android.Widget.RadioButton (cross-platform GroupName for exclusivity, not RadioGroup)
- RefreshView → AndroidX.SwipeRefreshLayout.Widget.SwipeRefreshLayout
- ScrollView → ScrollView / HorizontalScrollView
- SearchBar → SearchView
- Slider → SeekBar
- StackLayout → LinearLayout
- SwipeView → Custom view with gesture detection
- Switch → SwitchCompat
- TimePicker → TimePickerDialog
- WebView → WebView
---
## MAUI View/VisualElement Properties vs Spice View
This section compares the properties available on MAUI's `View` class (which inherits from `VisualElement`, `NavigableElement`, `Element`, and `BindableObject`) with Spice's `View` base class.
### Layout & Sizing Properties
| MAUI Property | Spice Implementation | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| Width | ✅ Yes | ✅ Done | Read-only - returns actual rendered width |
| Height | ✅ Yes | ✅ Done | Read-only - returns actual rendered height |
| WidthRequest | ✅ Yes | ✅ Done | Desired width - essential for sizing |
| HeightRequest | ✅ Yes | ✅ Done | Desired height - essential for sizing |
| MinimumWidthRequest | ❌ No | 🟡 Maybe | Useful for responsive layouts |
| MinimumHeightRequest | ❌ No | 🟡 Maybe | Useful for responsive layouts |
| MaximumWidthRequest | ❌ No | 🟡 Maybe | Useful for responsive layouts |
| MaximumHeightRequest | ❌ No | 🟡 Maybe | Useful for responsive layouts |
| HorizontalOptions | ✅ Yes | ✅ Done | Spice: `HorizontalOptions` (LayoutOptions) |
| VerticalOptions | ✅ Yes | ✅ Done | Spice: `VerticalOptions` (LayoutOptions) |
| Margin | ✅ Yes | ✅ Done | Outer spacing using Thickness struct |
| Bounds | ❌ No | ❌ No | Read-only - internal layout info |
| Frame | ❌ No | ❌ No | Read-only - screen position |
| DesiredSize | ❌ No | ❌ No | Read-only - layout system internal |
### Alignment Properties
| MAUI Property | Spice Implementation | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| HorizontalOptions (MAUI) | ✅ Yes | ✅ Done | Spice: `HorizontalOptions` (LayoutOptions) |
| VerticalOptions (MAUI) | ✅ Yes | ✅ Done | Spice: `VerticalOptions` (LayoutOptions) |
### Appearance Properties
| MAUI Property | Spice Implementation | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| BackgroundColor | ✅ Yes | ✅ Done | Color type |
| Background | ❌ No | ❌ No | Brush (gradients) - complex |
| Opacity | ✅ Yes | ✅ Done | 0-1 transparency - clamped range |
| IsVisible | ✅ Yes | ✅ Done | Show/hide element - very common |
| Shadow | ❌ No | ❌ No | Platform-inconsistent, use native |
| Clip | ❌ No | ❌ No | Advanced, less common |
### Transform Properties
| MAUI Property | Spice Implementation | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| Rotation | ❌ No | ❌ No | Animation-focused, adds complexity |
| RotationX | ❌ No | ❌ No | 3D transforms - rare use case |
| RotationY | ❌ No | ❌ No | 3D transforms - rare use case |
| Scale | ❌ No | ❌ No | Animation-focused |
| ScaleX | ❌ No | ❌ No | Animation-focused |
| ScaleY | ❌ No | ❌ No | Animation-focused |
| TranslationX | ❌ No | ❌ No | Animation-focused |
| TranslationY | ❌ No | ❌ No | Animation-focused |
| AnchorX | ❌ No | ❌ No | Transform origin - depends on transforms |
| AnchorY | ❌ No | ❌ No | Transform origin - depends on transforms |
### Interaction Properties
| MAUI Property | Spice Implementation | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| IsEnabled | ✅ Yes | ✅ Done | Enable/disable interaction - essential for forms |
| InputTransparent | ❌ No | 🟡 Maybe | Pass-through touch events - useful |
| IsFocused | ❌ No | ❌ No | Read-only focus state - advanced |
| GestureRecognizers | ❌ No | ❌ No | Add tap handlers directly to controls |
### Hierarchy & Navigation
| MAUI Property | Spice Implementation | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| Children (collection) | ✅ Yes | ✅ Done | `ObservableCollection<View>` |
| Parent | ❌ No | 🟡 Maybe | Parent element - useful for traversal |
| Navigation | ❌ No | ❌ No | MAUI page-based navigation |
| Id | ❌ No | ❌ No | Unique identifier - less useful |
### Styling & Resources
| MAUI Property | Spice Implementation | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| Style | ❌ No | ❌ No | XAML-focused pattern |
| StyleClass | ❌ No | ❌ No | CSS-like classes - binding-focused |
| Class | ❌ No | ❌ No | Style classes - binding-focused |
| ClassId | ❌ No | ❌ No | Semantic identifier - testing-focused |
| StyleId | ❌ No | ❌ No | User identifier - debugging-focused |
| Resources | ❌ No | ❌ No | XAML resource dictionary |
| Behaviors | ❌ No | ❌ No | XAML behavior system |
| Triggers | ❌ No | ❌ No | XAML property triggers |
| Effects | ❌ No | ❌ No | Platform effects - advanced |
### Data Binding & Context
| MAUI Property | Spice Implementation | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| BindingContext | ❌ No | ❌ No | Data binding context (not Spice's philosophy) |
### Platform & Accessibility
| MAUI Property | Spice Implementation | Should Implement? | Notes |
|--------------|---------------------|-------------------|-------|
| AutomationId | ✅ Yes | ✅ Done | UI testing identifier - useful for QA |
| Handler | ❌ No | ❌ No | Platform handler - internal |
| FlowDirection | ❌ No | 🟢 Maybe | RTL support - i18n feature |
| IsLoaded | ❌ No | ❌ No | Loaded state - internal lifecycle |
| Dispatcher | ❌ No | ❌ No | UI thread dispatcher - internal |
### Spice-Specific Properties
| Spice Property | MAUI Equivalent | Notes |
|---------------|-----------------|-------|
| Children | Yes (in Container types) | `ObservableCollection<View>`, supports collection initializers |
| HorizontalOptions | HorizontalOptions | Uses `LayoutOptions` with alignment and expansion flags |
| VerticalOptions | VerticalOptions | Uses `LayoutOptions` with alignment and expansion flags |
| BackgroundColor | BackgroundColor | Uses `Microsoft.Maui.Graphics.Color` |
| IsVisible | IsVisible | Show/hide element |
| IsEnabled | IsEnabled | Enable/disable interaction |
| Opacity | Opacity | 0-1 transparency, clamped range |
| AutomationId | AutomationId | UI testing identifier |
| Margin | Margin | Outer spacing using Thickness struct |
| WidthRequest | WidthRequest | Desired width for sizing |
| HeightRequest | HeightRequest | Desired height for sizing |
| Width | Width | Read-only actual width |
| Height | Height | Read-only actual height |
### Summary
**Spice View Properties: 14**
- Children (collection)
- HorizontalOptions (LayoutOptions)
- VerticalOptions (LayoutOptions)
- BackgroundColor
- IsVisible
- IsEnabled
- Opacity
- AutomationId
- Margin
- WidthRequest
- HeightRequest
- Width (read-only)
- Height (read-only)
**MAUI View/VisualElement Properties: 60+**
Spice's `View` class is intentionally minimal, focusing on the essential properties needed for basic layout and appearance. MAUI's extensive property set supports:
- Complex styling and theming (not in Spice)
- Data binding and MVVM (not in Spice)
- Advanced transforms and animations (not in Spice)
- Accessibility and testing infrastructure (not in Spice)
- Resource management and behaviors (not in Spice)
Spice uses `[ObservableProperty]` for property change notifications, generating `On{Prop}Changed` partial methods implemented in platform-specific files, rather than MAUI's `BindableProperty` system.
---
## Recommended Additions for Spice
Based on Spice's minimalist philosophy and common mobile UI needs, here are reasonable additions that would enhance functionality without compromising simplicity:
### 🔥 High Priority - Essential Controls
**Layouts**
- ✅ **Grid** - Essential for complex layouts; maps to UIStackView/LinearLayout with weights or constraint-based layout (IMPLEMENTED)
- ✅ **ScrollView** - Fundamental for scrollable content; maps to UIScrollView/ScrollView (IMPLEMENTED)
**Input Controls**
- ✅ **Switch** - Standard toggle control; maps to UISwitch/SwitchCompat (IMPLEMENTED)
- ✅ **Slider** - Common for settings/media controls; maps to UISlider/SeekBar (IMPLEMENTED)
- ✅ **Picker** - Standard dropdown/selection; maps to UIPickerView/Spinner (IMPLEMENTED)
- ✅ **DatePicker** - Date selection; maps to UIDatePicker/DatePickerDialog (IMPLEMENTED)
- ✅ **TimePicker** - Time selection; maps to UIDatePicker/TimePickerDialog (IMPLEMENTED)
- ✅ **CheckBox** - Boolean selection; maps to UIButton (checkmark)/CheckBox (IMPLEMENTED)
**Display Controls**
- ✅ **ActivityIndicator** - Loading spinner; maps to UIActivityIndicatorView/ProgressBar (indeterminate) (IMPLEMENTED)
- ✅ **ProgressBar** - Progress display; maps to UIProgressView/ProgressBar (determinate) (IMPLEMENTED)
### 🟡 Medium Priority - Very Useful
**Layouts**
- ✅ **ContentView** - Custom control container for composition (IMPLEMENTED)
- ✅ **Border** - Wraps content with border/rounded corners; common UI pattern (IMPLEMENTED)
**Lists**
- ✅ **CollectionView** - Flexible grid/list; maps to UICollectionView/RecyclerView (IMPLEMENTED)
- 🟡 **ListView** - Scrollable list of items; maps to UITableView/RecyclerView (critical for many apps)
**Input**
- ✅ **Editor** - Multi-line text input; maps to UITextView/EditText (multiline) (IMPLEMENTED)
- ✅ **SearchBar** - Search input; maps to UISearchBar/SearchView (IMPLEMENTED)
**Display**
- ✅ **ImageButton** - Tappable image; common pattern (can be done with Image + gesture) (IMPLEMENTED)
### 🟢 Nice to Have - Special Cases
**Advanced Controls**
- ✅ **RefreshView** - Pull-to-refresh wrapper (IMPLEMENTED)
- ✅ **SwipeView** - Swipe actions/context menus (IMPLEMENTED)
- ✅ **RadioButton** - Radio button groups; uses cross-platform GroupName since iOS has no native radio concept
**Shapes** (Lower priority - can use Image or GraphicsView)
- ✅ **BoxView** - Colored rectangle (useful for dividers/spacers) (IMPLEMENTED)
- 🟢 **Rectangle/Ellipse** - Basic shapes
### 📊 View Properties - High Priority
**Layout & Sizing**
- ✅ **WidthRequest/HeightRequest** - Essential for sizing views (IMPLEMENTED)
- ✅ **Margin** - Outer spacing (critical for layouts) (IMPLEMENTED)
- 🟡 **Padding** - Inner spacing (for containers)
**Appearance**
- ✅ **IsVisible** - Show/hide elements (very common) (IMPLEMENTED)
- ✅ **Opacity** - Transparency (common for fade effects) (IMPLEMENTED)
**Interaction**
- ✅ **IsEnabled** - Enable/disable controls (essential for forms) (IMPLEMENTED)
### ❌ Not Recommended
**Probably Skip**
- ❌ **Transforms** (Rotation, Scale, Translation) - Animation-focused, adds complexity
- ❌ **CarouselView** - Complex, less common
- ❌ **IndicatorView** - Depends on CarouselView
- ❌ **TabbedPage/NavigationPage** - Page-level navigation (different architecture)
- ❌ **Map** - External dependency (Microsoft.Maui.Controls.Maps)
- ❌ **GraphicsView** - Advanced graphics (Microsoft.Maui.Graphics already available)
- ❌ **HybridWebView** - Specialized, newer control
- ❌ **TitleBar** - Desktop-focused
- ❌ **TwoPaneView** - Foldable-specific
- ❌ **Shapes** (Path, Polygon, Polyline, Line) - Can use Image or custom drawing
- ❌ **Shadow** - Platform-inconsistent, can use native code
- ❌ **Clip** - Advanced, less common
- ❌ **GestureRecognizers** - Can add tap handlers directly to controls
- ❌ **Behaviors/Triggers/Effects** - XAML/binding-focused patterns
- ❌ **Stepper** - Rare, can use buttons + label
### Implementation Priority
**Phase 1 (Core Controls)** ✅
1. ✅ Grid layout
2. ✅ ScrollView
3. ✅ Switch
4. ✅ ActivityIndicator
5. ✅ ProgressBar
6. ✅ IsVisible property
7. ✅ IsEnabled property
8. ✅ WidthRequest/HeightRequest
9. ✅ Margin
**Phase 2 (Input Controls)** ✅
1. ✅ Picker
2. ✅ Slider
3. ✅ CheckBox
4. ✅ DatePicker
5. ✅ TimePicker
6. ✅ Editor (multiline text)
**Phase 3 (Lists & Advanced)** ✅
1. 🟡 ListView
2. ✅ SearchBar
3. ✅ CollectionView
4. ✅ Border
5. ✅ ContentView
6. ✅ ImageButton
**Phase 4 (Nice-to-Have)** ✅
1. ✅ RefreshView
2. ✅ SwipeView
3. ✅ BoxView
4. ✅ RadioButton
5. ✅ Opacity property
---
*Note: Spice is focused on minimal cross-platform UI with no Microsoft.Maui.Controls dependency. Controls are added based on common mobile scenarios rather than full MAUI parity.*
================================================
FILE: docs/NAVIGATION-SPEC.md
================================================
# Navigation in Spice 🌶
Three new views and two methods on `Application`. That's it.
## Overview
| Type | What it does | iOS | Android |
|------|-------------|-----|---------|
| `NavigationView` | Push/pop stack with nav bar | `UINavigationController` | AndroidX Navigation |
| `TabView` | Bottom tabs | `UITabBarController` | `BottomNavigationView` |
| `Application.PresentAsync()` | Modal overlay | `PresentViewController()` | `DialogFragment` |
> These are **views**, not pages — they compose with existing Spice views like any other layout.
> `Application.Main` swapping still works; these are additive.
## NavigationView
```csharp
public class App : Application
{
public App()
{
Main = new NavigationView<HomeView>();
}
}
public class HomeView : StackLayout
{
public HomeView()
{
Title = "Home";
Add(new Label { Text = "Welcome!" });
Add(new Button
{
Text = "Details",
Clicked = _ => Navigation!.Push<DetailView>()
});
}
}
public class DetailView : StackLayout
{
public DetailView()
{
Title = "Details";
Add(new Label { Text = "Detail content" });
}
// Back button is automatic — no code needed
}
```
### Proposed API
```csharp
// Added to View base class
public partial class View
{
[ObservableProperty] string _title = "";
public NavigationView? Navigation { get; internal set; }
}
public partial class NavigationView : View
{
public NavigationView(View root);
public NavigationView(Func<View> factory); // lazy with args
public void Push(View view);
public void Push(Func<View> factory); // lazy with args
public void Push<T>() where T : View, new(); // lazy parameterless
public void Pop();
public void PopToRoot();
}
// Generic subclass — creates root view lazily
public partial class NavigationView<TRoot> : NavigationView where TRoot : View, new()
{
public NavigationView();
}
```
`Push`/`Pop` are synchronous — matches Spice's `Action<T>` callback pattern. The native platform handles animations.
`Push<T>()` and `Push(() => new T(args))` create the view on demand. Use `Push(view)` when you already have one.
`Title` is added to `View` so any view can set a nav bar title. Ignored when not inside a `NavigationView`.
`Navigation` is set on child views by `NavigationView` when they're pushed, similar to how layouts already manage their `Children`.
## TabView
```csharp
Main = new TabView
{
new Tab<HomeView>("Home", "home.png"),
new Tab<SearchView>("Search", "search.png"),
new Tab<ProfileView>("Profile", "profile.png"),
};
```
Each tab can contain a `NavigationView` for independent push/pop stacks:
```csharp
Main = new TabView
{
new Tab("Home", "home.png", new NavigationView<HomeView>()),
new Tab("Search", "search.png", new NavigationView<SearchView>()),
};
```
### Proposed API
```csharp
public partial class TabView : View
{
public void Add(Tab tab); // collection initializer support
}
public partial class Tab : View
{
[ObservableProperty] string _icon = "";
public Tab(string title, string icon, View content);
public Tab(string title, string icon, Func<View> factory); // lazy with args
}
// Generic subclass — creates content lazily on first tab selection
public partial class Tab<TContent> : Tab where TContent : View, new()
{
public Tab(string title, string icon);
}
```
`Tab` reuses `View.Title` for the tab label and `View.Children` for its content.
## Modal Presentation
```csharp
// Present (from any view)
await PresentAsync<LoginView>();
// Dismiss (from inside the modal)
await DismissAsync();
```
### Proposed API
```csharp
public partial class View
{
public Task PresentAsync(View view);
public Task PresentAsync(Func<View> factory); // lazy with args
public Task PresentAsync<T>() where T : View, new(); // lazy parameterless
public Task DismissAsync();
}
```
Modal methods live on `View` so any view can present/dismiss — no need for a global `Application.Current` singleton.
Modals are async because the caller often needs to know when presentation/dismissal completes (e.g., to read a result). `Push`/`Pop` don't need this — you fire and forget.
## Complete Example
```csharp
public class App : Application
{
public App()
{
Main = new TabView
{
new Tab("Feed", "feed.png", new NavigationView<FeedView>()),
new Tab<ProfileView>("Profile", "profile.png"),
};
}
}
public class FeedView : StackLayout
{
public FeedView()
{
Title = "Feed";
Add(new Button
{
Text = "View Post",
Clicked = _ => Navigation!.Push<PostView>()
});
Add(new Button
{
Text = "New Post",
Clicked = async _ => await PresentAsync<NewPostView>()
});
}
}
public class PostView : StackLayout
{
public PostView()
{
Title = "Post";
Add(new Label { Text = "Post content..." });
Add(new Button
{
Text = "Comments",
Clicked = _ => Navigation!.Push<CommentsView>()
});
}
}
public class NewPostView : StackLayout
{
public NewPostView()
{
Title = "New Post";
Add(new Entry { Placeholder = "What's on your mind?" });
Add(new Button
{
Text = "Post",
Clicked = async _ => await DismissAsync()
});
}
}
```
## Migration
```csharp
// Before — swap the whole view tree
new Button { Clicked = _ => Main = new DetailView() }
// After — push onto the stack, get a nav bar + back button for free
new Button { Clicked = _ => Navigation!.Push<DetailView>() }
```
## Platform Mapping
### iOS
| Spice | iOS |
|-------|-----|
| `NavigationView` | `UINavigationController` |
| `Push()` | `pushViewController(_:animated:)` |
| `Pop()` | `popViewController(animated:)` |
| `PopToRoot()` | `popToRootViewController(animated:)` |
| `TabView` | `UITabBarController` |
| `Tab` | `UITab` / tab bar item |
| `PresentAsync()` | `present(_:animated:completion:)` |
| `DismissAsync()` | `dismiss(animated:completion:)` |
### Android
| Spice | Android |
|-------|---------|
| `NavigationView` | `NavController` + `NavHostFragment` |
| `Push()` | `navigate()` |
| `Pop()` | `navigateUp()` |
| `PopToRoot()` | `popBackStack(startDest)` |
| `TabView` | `BottomNavigationView` |
| `Tab` | Menu item |
| `PresentAsync()` | `DialogFragment.show()` |
| `DismissAsync()` | `DialogFragment.dismiss()` |
## Design Decisions
**Why "views" not "pages"?** Spice doesn't have pages. `NavigationView` and `TabView` are views — they inherit from `View`, use `[ObservableProperty]`, and compose like `StackLayout` or `Grid`.
**Why sync Push/Pop but async modals?** Push/pop match Spice's `Action<T>` event pattern — no `async void` needed in `Clicked` handlers. Modals are async because callers often await the result.
**Why `Title` on View?** It's one `[ObservableProperty]` field. Ignored unless the view is inside a `NavigationView` or `Tab`. Simpler than a separate "page" abstraction.
**What about `Application.Main` swapping?** Still works. Use `NavigationView`/`TabView` when you want native navigation chrome (back button, nav bar, tab bar). Use `Main =` when you don't.
**Why three overload forms?** `Push(view)` for pre-built views. `Push<T>()` for parameterless construction. `Push(() => new DetailView(postId))` for lazy creation with arguments. Same pattern on `Tab`, `NavigationView`, and `PresentAsync`.
================================================
FILE: docs/THEME-SPEC.md
================================================
# Themes in Spice 🌶
**Status:** Implemented
**Created:** February 2026
## Overview
Spice provides a built-in `Theme` class — a plain C# object with well-known color
properties — and a mechanism for views to consume those colors automatically, update
live when the theme changes, and still allow per-view overrides. The entire design is
**NativeAOT safe, trimmer safe, and reflection-free**.
## `Theme` Class
### Core API
A `Theme` is just a POCO that extends `ObservableObject` — same base as every Spice view.
It defines **semantic color slots** that map to view properties:
```csharp
public partial class Theme : ObservableObject
{
/// <summary>Default text color for Label, Button, Entry, SearchBar, etc.</summary>
[ObservableProperty]
Color? _textColor;
/// <summary>Default background color for all views.</summary>
[ObservableProperty]
Color? _backgroundColor;
/// <summary>Accent/tint color for interactive controls (Button background, Switch tint, ActivityIndicator, etc.)</summary>
[ObservableProperty]
Color? _accentColor;
/// <summary>Border/stroke color for Border views.</summary>
[ObservableProperty]
Color? _strokeColor;
/// <summary>Placeholder text color for Editor, SearchBar, etc.</summary>
[ObservableProperty]
Color? _placeholderColor;
}
```
No reflection, no dictionaries, no string lookups. Just typed properties on a typed object.
### Built-In Light and Dark Themes
The built-in themes use float constructors instead of `Colors` static properties to avoid
pulling `Microsoft.Maui.Graphics` references into the AOT-compiled output, keeping APK size
down:
```csharp
public partial class Theme
{
public static Theme Light => new()
{
TextColor = Black, // #000000
BackgroundColor = White, // #FFFFFF
AccentColor = new Color(0f, 0.471f, 0.831f), // #0078D4
StrokeColor = new Color(0.878f, 0.878f, 0.878f), // #E0E0E0
PlaceholderColor = DarkGray, // #A9A9A9
};
public static Theme Dark => new()
{
TextColor = White, // #FFFFFF
BackgroundColor = new Color(0.118f, 0.118f, 0.118f), // #1E1E1E
AccentColor = new Color(0.298f, 0.761f, 1f), // #4CC2FF
StrokeColor = new Color(0.251f, 0.251f, 0.251f), // #404040
PlaceholderColor = LightGray, // #D3D3D3
};
}
```
### Setting the Theme on Application
```csharp
public partial class Application : View
{
/// <summary>
/// The current theme. Setting this applies colors to the entire view tree
/// and subscribes to live updates. Null means no theme — views keep their
/// individually-set colors (backward compatible default).
/// </summary>
[ObservableProperty]
Theme? _theme;
}
```
> **Why nullable?** Theming is opt-in. Existing apps that never set `Theme` continue
> working exactly as before — no colors change, no behavior changes. Apps opt in with
> a single line: `Theme = Theme.Light;`
## How Theming Works
### Step 1: Each View Knows How to Apply a Theme
Every view type overrides a `protected virtual` method that maps theme color slots to its
own properties. This is the **only** connection between themes and views — no reflection,
no attribute scanning, no magic.
The base `View` class applies `BackgroundColor`:
```csharp
// In View (base class)
protected virtual void ApplyTheme(Theme theme)
{
if (CanApplyTheme((int)ThemeProperty.BackgroundColor))
BackgroundColor = theme.BackgroundColor;
}
```
Subclasses override to add their own mappings:
```csharp
// In Label
protected override void ApplyTheme(Theme theme)
{
base.ApplyTheme(theme);
if (CanApplyTheme((int)ThemeProperty.TextColor))
TextColor = theme.TextColor;
}
```
```csharp
// In Button — uses AccentColor for its background
protected override void ApplyTheme(Theme theme)
{
base.ApplyTheme(theme);
if (CanApplyTheme((int)ThemeProperty.TextColor))
TextColor = theme.TextColor;
if (CanApplyTheme((int)ThemeProperty.BackgroundColor))
BackgroundColor = theme.AccentColor;
}
```
```csharp
// In Border
protected override void ApplyTheme(Theme theme)
{
base.ApplyTheme(theme);
if (CanApplyTheme((int)ThemeProperty.Stroke))
Stroke = theme.StrokeColor;
}
```
```csharp
// In Editor — text and placeholder colors
protected override void ApplyTheme(Theme theme)
{
base.ApplyTheme(theme);
if (CanApplyTheme((int)ThemeProperty.TextColor))
TextColor = theme.TextColor;
if (CanApplyTheme((int)ThemeProperty.PlaceholderColor))
PlaceholderColor = theme.PlaceholderColor;
}
```
```csharp
// In ActivityIndicator — accent color
protected override void ApplyTheme(Theme theme)
{
base.ApplyTheme(theme);
if (CanApplyTheme((int)ThemeProperty.Color))
Color = theme.AccentColor;
}
```
#### Complete Theme Mapping Table
| View | Theme Slot → Property |
|---|---|
| **View** (base) | `BackgroundColor` → `BackgroundColor` |
| **Label** | `TextColor` → `TextColor` |
| **Button** | `TextColor` → `TextColor`, `AccentColor` → `BackgroundColor` |
| **Entry** | `TextColor` → `TextColor` |
| **Editor** | `TextColor` → `TextColor`, `PlaceholderColor` → `PlaceholderColor` |
| **SearchBar** | `TextColor` → `TextColor`, `PlaceholderColor` → `PlaceholderColor` |
| **DatePicker** | `TextColor` → `TextColor` |
| **Picker** | `TextColor` → `TextColor` |
| **Border** | `StrokeColor` → `Stroke` |
| **ActivityIndicator** | `AccentColor` → `Color` |
Views that only inherit the base `BackgroundColor` mapping (no override): Image, ImageButton,
Switch, Slider, ProgressBar, WebView, ScrollView, StackLayout, ContentView, Grid, BoxView,
CheckBox, RadioButton, TimePicker.
### Step 2: Tracking "Developer Set" vs "Theme Set"
When a developer explicitly sets a color on a view, that value takes priority over the
theme. This is tracked with a bitmask (`_explicitProps`) and a `ThemeProperty` flags enum:
```csharp
public partial class View
{
/// <summary>
/// Built-in theme property flags. An Int32 supports up to 32 properties.
/// Custom views can define additional flags starting at 1 << 5.
/// </summary>
[Flags]
public enum ThemeProperty
{
None = 0,
BackgroundColor = 1 << 0,
TextColor = 1 << 1,
PlaceholderColor= 1 << 2,
Stroke = 1 << 3,
Color = 1 << 4,
}
bool _isApplyingTheme;
int _explicitProps;
/// <summary>
/// Tracks whether a theme property was explicitly set by the developer.
/// When value is non-null the flag is set; when null it is cleared.
/// </summary>
public void TrackExplicit(int property, object? value)
{
if (!_isApplyingTheme)
{
if (value is not null)
_explicitProps |= property;
else
_explicitProps &= ~property;
}
}
/// <summary>
/// Returns true when the theme property has not been explicitly set.
/// </summary>
public bool CanApplyTheme(int property) => (_explicitProps & property) == 0;
}
```
Each view hooks its `On{Prop}Changing` partial to call `TrackExplicit`:
```csharp
// In View
partial void OnBackgroundColorChanging(Color? value) =>
TrackExplicit((int)ThemeProperty.BackgroundColor, value);
// In Label
partial void OnTextColorChanging(Color? value) =>
TrackExplicit((int)ThemeProperty.TextColor, value);
// In Border
partial void OnStrokeChanging(Color? value) =>
TrackExplicit((int)ThemeProperty.Stroke, value);
```
> **Why a bitmask instead of per-property booleans?** A single `int` tracks up to 32
> properties with no per-field memory overhead. The `ThemeProperty` enum provides
> compile-time safety for the flag values.
To **clear** an explicit override and revert to the theme:
```csharp
label.TextColor = null; // clears the flag, theme value applies on next theme application
```
### Step 3: Walking the View Tree
When `Application.Theme` is set or changed, the entire `Main` view tree is walked via
`ApplyThemeToTree` (an `internal static` method on `View`). Each view is themed through
`ApplyThemeInternal`, which manages the `_isApplyingTheme` flag, stores the applied theme
for dynamic children, and delegates to the virtual `ApplyTheme`:
```csharp
// In View
internal void ApplyThemeInternal(Theme theme)
{
_isApplyingTheme = true;
_appliedTheme = theme;
if (!_themeChildrenSubscribed)
{
_themeChildrenSubscribed = true;
Children.CollectionChanged += OnThemeChildrenChanged;
}
ApplyTheme(theme);
_isApplyingTheme = false;
}
internal static void ApplyThemeToTree(View? view, Theme theme)
{
if (view is null) return;
view.ApplyThemeInternal(theme);
foreach (var child in view.Children)
ApplyThemeToTree(child, theme);
}
```
In `Application`, theme changes subscribe to `PropertyChanged` for live updates. Setting
`Main` after a theme also applies the theme to the new tree. Explicitly setting `Theme`
disables `UseSystemTheme`:
```csharp
// In Application
partial void OnThemeChanging(Theme? value)
{
if (!_isSettingSystemTheme)
UseSystemTheme = false;
}
partial void OnThemeChanged(Theme? oldValue, Theme? newValue)
{
if (oldValue is not null)
oldValue.PropertyChanged -= OnThemePropertyChanged;
if (newValue is not null)
{
newValue.PropertyChanged += OnThemePropertyChanged;
ApplyThemeToTree(Main, newValue);
}
}
partial void OnMainChanged(View? oldValue, View? newValue)
{
if (newValue is not null && Theme is not null)
ApplyThemeToTree(newValue, Theme);
}
void OnThemePropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (Theme is not null)
ApplyThemeToTree(Main, Theme);
}
```
### Step 4: New Views Get the Theme Too
When a view is added to the tree at runtime, it picks up the current theme. Each
view lazily subscribes to its own `Children.CollectionChanged` the first time
`ApplyThemeInternal` is called, and themes any newly added children:
```csharp
// In View — registered lazily inside ApplyThemeInternal
void OnThemeChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems is not null && _appliedTheme is not null)
{
foreach (View child in e.NewItems)
ApplyThemeToTree(child, _appliedTheme);
}
}
```
## Dark Mode / Light Mode
### Simple Toggle
```csharp
public class App : Application
{
public App()
{
Theme = Theme.Light;
var toggle = new Switch
{
Toggled = sw => Theme = sw.IsOn ? Theme.Dark : Theme.Light
};
Main = new StackLayout
{
new Label { Text = "Hello, Spice 🌶" },
new Label { Text = "Dark Mode:" },
toggle,
};
}
}
```
Flipping the `Switch` swaps the entire theme — every view in the tree updates immediately.
### Automatic System Appearance Detection
Spice provides `PlatformAppearance` — a cross-platform static class that exposes the
system's current appearance and a change notification:
```csharp
public static partial class PlatformAppearance
{
/// <summary>
/// Event raised when the system appearance changes.
/// The bool parameter is true when the system switched to dark mode.
/// </summary>
public static event Action<bool>? Changed;
/// <summary>
/// Gets whether the system is in dark mode.
/// </summary>
public static bool IsDarkMode { get; }
}
```
Set `Application.UseSystemTheme = true` and Spice handles the rest:
```csharp
public class App : Application
{
public App()
{
UseSystemTheme = true; // auto-selects Theme.Light or Theme.Dark based on OS
Main = new StackLayout
{
new Label { Text = "Hello, Spice 🌶" },
};
}
}
```
When `UseSystemTheme` is enabled:
- On startup, Spice queries `PlatformAppearance.IsDarkMode` and sets `Theme` accordingly
- It subscribes to `PlatformAppearance.Changed` so that `Theme` is swapped automatically when the OS appearance changes
- Setting `Theme` explicitly disables `UseSystemTheme` (explicit wins)
- When `UseSystemTheme` is disabled, the `Changed` subscription is removed
```csharp
partial void OnUseSystemThemeChanged(bool value)
{
if (value)
{
PlatformAppearance.Changed += OnPlatformAppearanceChanged;
_isSettingSystemTheme = true;
Theme = PlatformAppearance.IsDarkMode ? Theme.Dark : Theme.Light;
_isSettingSystemTheme = false;
}
else
{
PlatformAppearance.Changed -= OnPlatformAppearanceChanged;
}
}
void OnPlatformAppearanceChanged(bool isDarkMode)
{
if (_useSystemTheme)
{
_isSettingSystemTheme = true;
Theme = isDarkMode ? Theme.Dark : Theme.Light;
_isSettingSystemTheme = false;
}
AppearanceChanged?.Invoke(isDarkMode);
}
```
Platform implementations behind `PlatformAppearance.IsDarkMode`:
- **iOS** — reads `UITraitCollection.CurrentTraitCollection.UserInterfaceStyle`; listens for trait changes via `RegisterForTraitChanges` (iOS 17+) or `TraitCollectionDidChange`.
- **Android** — reads `UiMode.NightMask` from `Resources.Configuration`; listens for configuration changes in `SpiceActivity.OnConfigurationChanged`.
For fully custom themes that still track the OS mode, use the `AppearanceChanged` callback:
```csharp
AppearanceChanged = isDark => Theme = isDark ? myDarkTheme : myLightTheme;
```
## Custom Themes
### Extend the Built-In Slots
Developers can create their own themes by simply constructing `Theme` with different colors:
```csharp
var corporate = new Theme
{
TextColor = Color.FromArgb("#333333"),
BackgroundColor = Color.FromArgb("#F5F5F5"),
AccentColor = Color.FromArgb("#FF6600"), // brand orange
StrokeColor = Color.FromArgb("#CCCCCC"),
PlaceholderColor = Color.FromArgb("#999999"),
};
app.Theme = corporate;
```
### Add New Color Slots (Subclass)
For app-specific color slots that built-in views don't know about:
```csharp
public partial class BrandTheme : Theme
{
[ObservableProperty]
Color? _headerColor;
[ObservableProperty]
Color? _cardBackgroundColor;
}
```
Custom views consume these in their own `ApplyTheme`:
```csharp
public partial class HeaderView : Label
{
protected override void ApplyTheme(Theme theme)
{
base.ApplyTheme(theme);
if (theme is BrandTheme brand && brand.HeaderColor is not null)
TextColor = brand.HeaderColor;
}
}
```
## Per-View Overrides
Setting a color explicitly on a view always wins over the theme:
```csharp
app.Theme = Theme.Dark; // TextColor = White
var label = new Label { Text = "Always red", TextColor = Colors.Red };
// TextColor stays Red even though the theme says White
```
To reset a view back to the theme's color:
```csharp
label.TextColor = null; // Reverts to theme's TextColor on next theme application
```
## Design Decisions
### Why Not a Dictionary / Resource System?
Frameworks like WPF and MAUI use dictionaries (`ResourceDictionary`) where theme values are
looked up by string key at runtime. This is flexible but:
| | Dictionary (WPF/MAUI) | Typed Theme (Spice) |
|---|---|---|
| **NativeAOT safe** | ❌ Often uses reflection for type conversion | ✅ Plain properties, zero reflection |
| **Trimmer safe** | ⚠️ String keys can't be statically analyzed | ✅ Direct property access, fully trimmable |
| **Compile-time safety** | ❌ Typo in key = runtime error | ✅ Typo in property name = compile error |
| **Discoverability** | ❌ Keys are strings, need documentation | ✅ IntelliSense shows all available slots |
| **Debuggability** | ❌ Opaque dictionary lookups | ✅ Step through `ApplyTheme` line by line |
A typed `Theme` class trades some flexibility (you can't add arbitrary keys at runtime) for
compile-time safety, IntelliSense, and zero runtime overhead. This matches Spice's philosophy.
### Why Not Expression Trees / Compiled Lambdas?
Expression trees would let us infer property names automatically, but they require
`System.Linq.Expressions` which is not fully NativeAOT safe and increases binary size.
Explicit virtual methods are zero-overhead and always trimmable.
### Why a Bitmask for Override Tracking?
A single `int _explicitProps` field tracks up to 32 themeable properties with zero
per-field memory overhead. The `ThemeProperty` flags enum provides compile-time safety
for the bit positions. Custom views can define additional flags starting at `1 << 5`.
### Why `protected virtual` Instead of `public virtual`?
`ApplyTheme` is a framework implementation detail — developers don't call it directly,
they set `Application.Theme` and the framework handles the rest. Making it `protected`
keeps it out of the public API surface while still allowing external libraries and custom
controls to override it and participate in theming.
### Why Re-Apply the Entire Theme on Single-Property Changes?
When `Theme.TextColor` changes, we re-apply the full theme to the view tree instead of
only updating text colors. This keeps the logic simple — `ApplyTheme` is the single source
of truth for all theme→view mappings. Theme objects are small (a handful of color
properties), and the view tree traversal is fast (layout trees are typically shallow).
## Full Example
```csharp
public class App : Application
{
public App()
{
Theme = Theme.Light;
int count = 0;
var label = new Label { Text = "Hello, Spice 🌶" };
var counter = new Label { Text = "Times: 0" };
var button = new Button
{
Text = "Tap me",
Clicked = _ => counter.Text = $"Times: {++count}",
};
var darkModeSwitch = new Switch
{
Toggled = sw => Theme = sw.IsOn ? Theme.Dark : Theme.Light,
};
var overrideLabel = new Label
{
Text = "I'm always red",
TextColor = Colors.Red, // explicit override — theme won't touch this
};
Main = new StackLayout
{
label,
counter,
button,
new StackLayout
{
Orientation = Orientation.Horizontal,
new Label { Text = "Dark Mode:" },
darkModeSwitch,
},
overrideLabel,
};
}
}
```
Toggle the switch → every view updates to dark colors instantly, except the red label which
keeps its explicit color.
## Summary
- **`Theme`** is a POCO extending `ObservableObject` — just typed color properties, no reflection
- **`Application.Theme`** sets the active theme and walks the view tree
- **Live updates** — change a theme property or swap the entire theme, views update immediately
- **Explicit overrides win** — set `TextColor = Colors.Red` and the theme won't touch it; set to `null` to revert
- **Bitmask tracking** — `ThemeProperty` flags + `_explicitProps` track developer-set vs theme-set properties
- **Dynamic children** — views added to the tree at runtime automatically receive the current theme
- **Dark/Light mode** — `UseSystemTheme = true` auto-detects OS appearance; or swap manually with one assignment
- **Custom themes** — subclass `Theme` or just construct one with your own colors
- **NativeAOT safe** — zero reflection, fully trimmable, compile-time type safety
================================================
FILE: docs/VIEW-LIFECYCLE-SPEC.md
================================================
# View Lifecycle & Cleanup in Spice 🌶
**Status:** Design Specification
**Created:** February 2026
## Overview
Spice Views are created lazily and kept alive by their parent hierarchy. To support proper
cleanup (e.g., disposing event subscriptions from `Bind()`), we propose a simple contract:
**if a View implements `IDisposable`, its `Dispose()` will be called when the view is no longer needed.**
This spec defines when and how disposal happens on each platform.
## Current State
- **Android:** Views are C# partial classes wrapping `Android.Views.ViewGroup`
- **iOS:** Views are C# partial classes wrapping `UIView`
- **Lifecycle:** Managed implicitly by platform (Activity destruction on Android, ARC on iOS)
- **Disposal:** Currently no explicit cleanup contract — memory leaks possible if custom Views hold subscriptions
## Proposed: IDisposable Contract
**Key principle:** Only custom Views that hold resources implement `IDisposable` (opt-in).
Built-in Views (Button, Label, StackLayout, etc.) do **not** implement `IDisposable`.
### What Gets Disposed
1. **Custom Views that implement `IDisposable`** — `Dispose()` is called when the view is destroyed
2. **Children of a disposed view** — if a parent is disposed, it recursively disposes children that are `IDisposable`
3. **Resources:** Event subscriptions, timers, and `Bind()` subscriptions can be freed this way
### Platform Semantics
#### Android
When the `Application`'s `Activity` is destroyed (user backs out, etc.):
1. Each View's `NativeView` (underlying `ViewGroup`) is removed from the hierarchy
2. **Top-level app View** — call `Dispose()` if it implements `IDisposable`
3. **Recursively dispose children** — foreach child in `Children`, call `Dispose()` if it's `IDisposable`
4. **Bottom-up** — children disposed before parents
```csharp
// Pseudo-code in MainActivity.OnDestroy or Activity.OnDestroy equivalent
protected override void OnDestroy()
{
if (_appView is IDisposable disposable)
disposable.Dispose();
base.OnDestroy();
}
```
#### iOS
When a View is removed from the hierarchy (e.g., navigation pop, cell recycle):
1. View is **no longer strongly referenced** by its parent's `Children` collection
2. **ARC (Automatic Reference Counting) deinit** is called on the Spice View wrapper
3. In the Spice View's `deinit` (C# finalizer or explicit cleanup), call `Dispose()` if it's `IDisposable`
4. **Recursively dispose children** — same as Android
Since Spice Views are managed objects in a `Children` collection, we can wrap the collection
removal to trigger cleanup:
```csharp
// In iOS View.cs
void OnChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems ?? [])
{
if (item is View view && view is IDisposable disposable)
disposable.Dispose();
}
}
// ... also handle Replace, etc.
}
```
#### CollectionView Recycling
**Special case:** CollectionView recycles ItemTemplate views. When a template view is recycled:
1. The item stays alive (kept in `ItemsSource`)
2. The **view wrapper** is removed from the hierarchy
3. Any `Bind()` subscriptions on the item should be disposed **OR** left alive if the item is reused
**Recommendation:** For CollectionView, don't dispose item ViewModels (they're recycled).
Instead, use weak references or check `IsVisible` before updating:
```csharp
// Don't dispose the TodoItem itself — it will be recycled
// The Bind() subscription will be garbage collected when the view is recycled
```
## Implementing IDisposable in Spice Views
### Pattern 1: Single IDisposable Resource
```csharp
public partial class TimerView : StackLayout, IDisposable
{
private System.Timers.Timer? _timer;
private IDisposable? _binding;
public TimerView()
{
var vm = new TimerViewModel();
var label = new Label();
// This subscription needs cleanup
_binding = vm.Bind(nameof(vm.Elapsed), v => v.Elapsed,
elapsed => label.Text = $"{elapsed}s");
// And a timer that needs stopping
_timer = new System.Timers.Timer(1000);
_timer.Elapsed += (_, _) => vm.Tick();
Children.Add(label);
}
public void Dispose()
{
_binding?.Dispose();
_timer?.Dispose();
}
}
```
### Pattern 2: CompositeDisposable
```csharp
public partial class FormView : StackLayout, IDisposable
{
private readonly List<IDisposable> _subscriptions = new();
public FormView()
{
var vm = new FormViewModel();
// ... create UI ...
_subscriptions.Add(vm.Bind(nameof(vm.IsValid), ...));
_subscriptions.Add(vm.Bind(nameof(vm.ErrorMessage), ...));
}
public void Dispose()
{
foreach (var sub in _subscriptions)
sub?.Dispose();
_subscriptions.Clear();
}
}
```
## When to Dispose
### ✅ DO dispose:
- Custom `Bind()` subscriptions when the binding outlives the view
- Event subscriptions (timers, HTTP clients, etc.)
- File handles, database connections
- WeakReference holders that prevent collection
### ❌ DON'T dispose:
- Items in `ItemsSource` (they're reused across recycled views)
- Shared singletons (Application state, Services)
- Views that are still in the hierarchy (parent disposes them)
## Default Behavior (No Explicit Dispose)
If a View does **not** implement `IDisposable`, nothing special happens—the view is garbage
collected when no longer referenced, and any subscriptions are dropped naturally.
This is fine for simple Views. Only implement `IDisposable` if your View holds resources
that need explicit cleanup.
## Implementation Roadmap
### Phase 1: Documentation (this spec) ✓
- Establish the contract: custom Views can implement `IDisposable`
- Show patterns and examples
- Guide developers on when to implement `IDisposable`
### Phase 2: Platform Integration (future)
**Android:** Call `Dispose()` on the app's top-level View during `Activity.OnDestroy()`
```csharp
protected override void OnDestroy()
{
if (_appView is IDisposable disposable)
disposable.Dispose();
base.OnDestroy();
}
```
**iOS:** Hook `Children.CollectionChanged` to dispose removed views
```csharp
// In View.cs
private void OnChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems ?? [])
{
if (item is IDisposable disposable)
disposable.Dispose();
}
}
// ... also handle Replace, etc.
}
```
## Example: Todo App with Cleanup
```csharp
public partial class TodoItemView : StackLayout, IDisposable
{
private IDisposable? _binding;
public TodoItemView(TodoItem item)
{
var label = new Label();
var checkbox = new CheckBox();
// This subscription must be cleaned up when the view is recycled
_binding = item.Bind(nameof(item.Title), t => t.Title,
text => label.Text = text);
item.Bind(nameof(item.IsCompleted), t => t.IsCompleted,
done => checkbox.IsChecked = done);
checkbox.CheckedChanged = cb => item.IsCompleted = cb.IsChecked;
Children.Add(new StackLayout { label, checkbox });
}
public void Dispose()
{
_binding?.Dispose();
// Bindings to checkbox are implicitly cleaned up with the view
}
}
public class TodoListApp : Application
{
public TodoListApp()
{
var vm = new TodoListViewModel();
var collectionView = new CollectionView
{
ItemsSource = vm.Items,
ItemTemplate = item => new TodoItemView((TodoItem)item)
};
Main = new StackLayout { collectionView };
}
}
```
## Notes
- **No finalizers:** Avoid finalizers in Views — they create GC pressure. Rely on explicit
disposal or being kept alive with the view until it's cleared.
- **Parent owns children:** When a parent View is disposed, it should dispose its children.
- **Weak references:** For internal caches or event handlers, use WeakReference to avoid
circular dependencies.
## Summary
- Only custom Views implement `IDisposable` (opt-in) — built-in Views do not
- Disposal is recursive: when a View is disposed, children that implement `IDisposable` are disposed too
- Use this contract to clean up `Bind()` subscriptions and other resources
- Platform integration will make this automatic (future)
================================================
FILE: global.json
================================================
{
"msbuild-sdks": {
"Microsoft.Build.NoTargets": "3.7.56"
}
}
================================================
FILE: samples/HeadToHeadMaui/App.xaml
================================================
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:HeadToHeadMaui"
x:Class="HeadToHeadMaui.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
================================================
FILE: samples/HeadToHeadMaui/App.xaml.cs
================================================
namespace HeadToHeadMaui;
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
}
================================================
FILE: samples/HeadToHeadMaui/AppShell.xaml
================================================
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="HeadToHeadMaui.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:HeadToHeadMaui"
Shell.FlyoutBehavior="Disabled">
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
</Shell>
================================================
FILE: samples/HeadToHeadMaui/AppShell.xaml.cs
================================================
namespace HeadToHeadMaui;
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
}
================================================
FILE: samples/HeadToHeadMaui/HeadToHeadMaui.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net10.0-android;net10.0-ios</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net10.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net10.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType>
<RootNamespace>HeadToHeadMaui</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Display name -->
<ApplicationTitle>HeadToHeadMaui</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId>com.companyname.headtoheadmaui</ApplicationId>
<ApplicationIdGuid>fc6b6cda-cd30-40ab-9968-ef7e9e292c2d</ApplicationIdGuid>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">16.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
<AndroidLinkTool Condition="'$(Configuration)' == 'Release'">r8</AndroidLinkTool>
<RuntimeIdentifier Condition="'$(Configuration)' == 'Release' and $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">android-arm64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\dotnet_bot.svg" BaseSize="168,208" />
<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.3" />
</ItemGroup>
</Project>
================================================
FILE: samples/HeadToHeadMaui/HeadToHeadMaui.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31611.283
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HeadToHeadMaui", "HeadToHeadMaui.csproj", "{B221E782-7C39-468D-8FCB-F16F24A90A2E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B221E782-7C39-468D-8FCB-F16F24A90A2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B221E782-7C39-468D-8FCB-F16F24A90A2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B221E782-7C39-468D-8FCB-F16F24A90A2E}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{B221E782-7C39-468D-8FCB-F16F24A90A2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B221E782-7C39-468D-8FCB-F16F24A90A2E}.Release|Any CPU.Build.0 = Release|Any CPU
{B221E782-7C39-468D-8FCB-F16F24A90A2E}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572}
EndGlobalSection
EndGlobal
================================================
FILE: samples/HeadToHeadMaui/MainPage.xaml
================================================
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="HeadToHeadMaui.MainPage">
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="Hello, World!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Welcome to .NET Multi-platform App UI"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
================================================
FILE: samples/HeadToHeadMaui/MainPage.xaml.cs
================================================
namespace HeadToHeadMaui;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
}
}
================================================
FILE: samples/HeadToHeadMaui/MauiProgram.cs
================================================
using Microsoft.Extensions.Logging;
namespace HeadToHeadMaui;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
================================================
FILE: samples/HeadToHeadMaui/Platforms/Android/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
================================================
FILE: samples/HeadToHeadMaui/Platforms/Android/MainActivity.cs
================================================
using Android.App;
using Android.Content.PM;
using Android.OS;
namespace HeadToHeadMaui;
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
}
================================================
FILE: samples/HeadToHeadMaui/Platforms/Android/MainApplication.cs
================================================
using Android.App;
using Android.Runtime;
namespace HeadToHeadMaui;
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
================================================
FILE: samples/HeadToHeadMaui/Platforms/Android/Resources/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#512BD4</color>
<color name="colorPrimaryDark">#2B0B98</color>
<color name="colorAccent">#2B0B98</color>
</resources>
================================================
FILE: samples/HeadToHeadMaui/Platforms/MacCatalyst/AppDelegate.cs
================================================
using Foundation;
namespace HeadToHeadMaui;
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
================================================
FILE: samples/HeadToHeadMaui/Platforms/MacCatalyst/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>
================================================
FILE: samples/HeadToHeadMaui/Platforms/MacCatalyst/Program.cs
================================================
using ObjCRuntime;
using UIKit;
namespace HeadToHeadMaui;
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}
================================================
FILE: samples/HeadToHeadMaui/Platforms/Tizen/Main.cs
================================================
using System;
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
namespace HeadToHeadMaui;
class Program : MauiApplication
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
static void Main(string[] args)
{
var app = new Program();
app.Run(args);
}
}
================================================
FILE: samples/HeadToHeadMaui/Platforms/Tizen/tizen-manifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest package="maui-application-id-placeholder" version="0.0.0" api-version="7" xmlns="http://tizen.org/ns/packages">
<profile name="common" />
<ui-application appid="maui-application-id-placeholder" exec="HeadToHeadMaui.dll" multiple="false" nodisplay="false" taskmanage="true" type="dotnet" launch_mode="single">
<label>maui-application-title-placeholder</label>
<icon>maui-appicon-placeholder</icon>
<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
</ui-application>
<shortcut-list />
<privileges>
<privilege>http://tizen.org/privilege/internet</privilege>
</privileges>
<dependencies />
<provides-appdefined-privileges />
</manifest>
================================================
FILE: samples/HeadToHeadMaui/Platforms/Windows/App.xaml
================================================
<maui:MauiWinUIApplication
x:Class="HeadToHeadMaui.WinUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maui="using:Microsoft.Maui"
xmlns:local="using:HeadToHeadMaui.WinUI">
</maui:MauiWinUIApplication>
================================================
FILE: samples/HeadToHeadMaui/Platforms/Windows/App.xaml.cs
================================================
using Microsoft.UI.Xaml;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace HeadToHeadMaui.WinUI;
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : MauiWinUIApplication
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
================================================
FILE: samples/HeadToHeadMaui/Platforms/Windows/Package.appxmanifest
================================================
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
<mp:PhoneIdentity PhoneProductId="C48D4BDF-BAE8-4D50-802E-2C74FA1491C7" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>$placeholder$</DisplayName>
<PublisherDisplayName>User Name</PublisherDisplayName>
<Logo>$placeholder$.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="$placeholder$"
Description="$placeholder$"
Square150x150Logo="$placeholder$.png"
Square44x44Logo="$placeholder$.png"
BackgroundColor="transparent">
<uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" />
<uap:SplashScreen Image="$placeholder$.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
================================================
FILE: samples/HeadToHeadMaui/Platforms/Windows/app.manifest
================================================
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="HeadToHeadMaui.WinUI.app"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- The combination of below two tags have the following effect:
1) Per-Monitor for >= Windows 10 Anniversary Update
2) System < Windows 10 Anniversary Update
-->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>
================================================
FILE: samples/HeadToHeadMaui/Platforms/iOS/AppDelegate.cs
================================================
using Foundation;
namespace HeadToHeadMaui;
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
================================================
FILE: samples/HeadToHeadMaui/Platforms/iOS/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>
================================================
FILE: samples/HeadToHeadMaui/Platforms/iOS/Program.cs
================================================
using ObjCRuntime;
using UIKit;
namespace HeadToHeadMaui;
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}
================================================
FILE: samples/HeadToHeadMaui/Properties/launchSettings.json
================================================
{
"profiles": {
"Windows Machine": {
"commandName": "MsixPackage",
"nativeDebugging": false
}
}
}
================================================
FILE: samples/HeadToHeadMaui/Resources/Raw/AboutAssets.txt
================================================
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories). Deployment of the asset to your application
is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
These files will be deployed with you package and will be accessible using Essentials:
async Task LoadMauiAsset()
{
using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
using var reader = new StreamReader(stream);
var contents = reader.ReadToEnd();
}
================================================
FILE: samples/HeadToHeadMaui/Resources/Styles/Colors.xaml
================================================
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Color x:Key="Primary">#512BD4</Color>
<Color x:Key="Secondary">#DFD8F7</Color>
<Color x:Key="Tertiary">#2B0B98</Color>
<Color x:Key="White">White</Color>
<Color x:Key="Black">Black</Color>
<Color x:Key="Gray100">#E1E1E1</Color>
<Color x:Key="Gray200">#C8C8C8</Color>
<Color x:Key="Gray300">#ACACAC</Color>
<Color x:Key="Gray400">#919191</Color>
<Color x:Key="Gray500">#6E6E6E</Color>
<Color x:Key="Gray600">#404040</Color>
<Color x:Key="Gray900">#212121</Color>
<Color x:Key="Gray950">#141414</Color>
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}"/>
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}"/>
<SolidColorBrush x:Key="TertiaryBrush" Color="{StaticResource Tertiary}"/>
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource White}"/>
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource Black}"/>
<SolidColorBrush x:Key="Gray100Brush" Color="{StaticResource Gray100}"/>
<SolidColorBrush x:Key="Gray200Brush" Color="{StaticResource Gray200}"/>
<SolidColorBrush x:Key="Gray300Brush" Color="{StaticResource Gray300}"/>
<SolidColorBrush x:Key="Gray400Brush" Color="{StaticResource Gray400}"/>
<SolidColorBrush x:Key="Gray500Brush" Color="{StaticResource Gray500}"/>
<SolidColorBrush x:Key="Gray600Brush" Color="{StaticResource Gray600}"/>
<SolidColorBrush x:Key="Gray900Brush" Color="{StaticResource Gray900}"/>
<SolidColorBrush x:Key="Gray950Brush" Color="{StaticResource Gray950}"/>
<Color x:Key="Yellow100Accent">#F7B548</Color>
<Color x:Key="Yellow200Accent">#FFD590</Color>
<Color x:Key="Yellow300Accent">#FFE5B9</Color>
<Color x:Key="Cyan100Accent">#28C2D1</Color>
<Color x:Key="Cyan200Accent">#7BDDEF</Color>
<Color x:Key="Cyan300Accent">#C3F2F4</Color>
<Color x:Key="Blue100Accent">#3E8EED</Color>
<Color x:Key="Blue200Accent">#72ACF1</Color>
<Color x:Key="Blue300Accent">#A7CBF6</Color>
</ResourceDictionary>
================================================
FILE: samples/HeadToHeadMaui/Resources/Styles/Styles.xaml
================================================
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Style TargetType="ActivityIndicator">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="IndicatorView">
<Setter Property="IndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}"/>
<Setter Property="SelectedIndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray100}}"/>
</Style>
<Style TargetType="Border">
<Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="StrokeShape" Value="Rectangle"/>
<Setter Property="StrokeThickness" Value="1"/>
</Style>
<Style TargetType="BoxView">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Button">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Primary}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="CornerRadius" Value="8"/>
<Setter Property="Padding" Value="14,10"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="CheckBox">
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="DatePicker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Editor">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Entry">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Frame">
<Setter Property="HasShadow" Value="False" />
<Setter Property="BorderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="CornerRadius" Value="8" />
</Style>
<Style TargetType="ImageButton">
<Setter Property="Opacity" Value="1" />
<Setter Property="BorderColor" Value="Transparent"/>
<Setter Property="BorderWidth" Value="0"/>
<Setter Property="CornerRadius" Value="0"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="Opacity" Value="0.5" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="ListView">
<Setter Property="SeparatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
<Setter Property="RefreshControlColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="Picker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="ProgressBar">
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RadioButton">
<Setter Property="BackgroundColor" Value="Transparent"/>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="RefreshView">
<Setter Property="RefreshColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="SearchBar">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="CancelButtonColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SearchHandler">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="FontSize" Value="14" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Shadow">
<Setter Property="Radius" Value="15" />
<Setter Property="Opacity" Value="0.5" />
<Setter Property="Brush" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
<Setter Property="Offset" Value="10,10" />
</Style>
<Style TargetType="Slider">
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="SwipeItem">
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
</Style>
<Style TargetType="Switch">
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="ThumbColor" Value="{StaticResource White}" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="On">
<VisualState.Setters>
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Secondary}, Dark={StaticResource Gray200}}" />
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Off">
<VisualState.Setters>
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="TimePicker">
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
<Setter Property="BackgroundColor" Value="Transparent"/>
<Setter Property="FontFamily" Value="OpenSansRegular"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="MinimumHeightRequest" Value="44"/>
<Setter Property="MinimumWidthRequest" Value="44"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Page" ApplyToDerivedTypes="True">
<Setter Property="Padding" Value="0"/>
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
</Style>
<Style TargetType="Shell" ApplyToDerivedTypes="True">
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource Gray950}}" />
<Setter Property="Shell.ForegroundColor" Value="{OnPlatform WinUI={StaticResource Primary}, Default={StaticResource White}}" />
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
<Setter Property="Shell.DisabledColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="Shell.UnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray200}}" />
<Setter Property="Shell.NavBarHasShadow" Value="False" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
<Setter Property="Shell.TabBarForegroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource Gray950}}" />
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
<Setter Property="IconColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
</Style>
<Style TargetType="TabbedPage">
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray950}}" />
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
<Setter Property="UnselectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="SelectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
</Style>
</ResourceDictionary>
================================================
FILE: samples/HeadToHeadSpice/App.cs
================================================
namespace HeadToHeadSpice;
/// <summary>
/// NOTE: this app is for comparing head-to-head `dotnet new maui`
/// </summary>
public class App : Application
{
public App()
{
int count = 0;
Main = new StackLayout
{
new Image { Source = "dotnet_bot" },
new Label { Text = "Hello, World!" },
new Label { Text = "Welcome to Spice 🌶!" },
new Button
{
Text = "Click me",
Clicked = b =>
{
if (++count == 1)
b.Text = $"Clicked {count} time";
else
b.Text = $"Clicked {count} times";
}
}
};
}
}
================================================
FILE: samples/HeadToHeadSpice/GlobalUsings.cs
================================================
global using Microsoft.Maui.Graphics;
global using Spice;
================================================
FILE: samples/HeadToHeadSpice/HeadToHeadSpice.csproj
================================================
<Project>
<Import Project="../../src/Spice/MSBuild/Spice.props" />
<Import Sdk="Microsoft.NET.Sdk" Project="Sdk.props" />
<PropertyGroup>
<TargetFrameworks>net10.0-android;net10.0-ios</TargetFrameworks>
<OutputType>Exe</OutputType>
<UseMauiAssets>true</UseMauiAssets>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<ApplicationTitle>HeadToHeadSpice</ApplicationTitle>
<ApplicationId>com.companyname.HeadToHeadSpice</ApplicationId>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">16.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<AndroidLinkTool Condition="'$(Configuration)' == 'Release'">r8</AndroidLinkTool>
<RuntimeIdentifier Condition="'$(Configuration)' == 'Release' and $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">android-arm64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\spice.svg" BaseSize="168,208" />
<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Spice\Spice.csproj" />
<PackageReference Include="Microsoft.Maui.Resizetizer" />
</ItemGroup>
<Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" />
<Import Project="../../src/Spice/MSBuild/Spice.targets" />
</Project>
================================================
FILE: samples/HeadToHeadSpice/Platforms/Android/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
================================================
FILE: samples/HeadToHeadSpice/Platforms/Android/MainActivity.cs
================================================
using Android.App;
using Android.OS;
namespace HeadToHeadSpice;
[Activity(
Theme = "@style/Theme.Material3.Light.NoActionBar",
MainLauncher = true)]
public class MainActivity : SpiceActivity
{
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(new App());
}
}
================================================
FILE: samples/HeadToHeadSpice/Platforms/iOS/AppDelegate.cs
================================================
using Foundation;
namespace HeadToHeadSpice;
[Register("AppDelegate")]
public class AppDelegate : SpiceAppDelegate
{
public override Application CreateApplication() => new App();
}
================================================
FILE: samples/HeadToHeadSpice/Platforms/iOS/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>SpiceSceneDelegate</string>
</dict>
</array>
</dict>
</dict>
</dict>
</plist>
================================================
FILE: samples/HeadToHeadSpice/Platforms/iOS/Program.cs
================================================
using UIKit;
using HeadToHeadSpice;
UIApplication.Main(args, null, typeof(AppDelegate));
================================================
FILE: samples/README.md
================================================
# Samples
* `Spice.Scenarios` - first sample to get things working, may get renamed
* `HeadToHeadMaui` - for comparing Spice vs Maui
* `HeadToHeadSpice` - for comparing Spice vs Maui
================================================
FILE: samples/Spice.BlazorSample/App.cs
================================================
namespace Spice.BlazorSample;
public class App : Application
{
public App()
{
Main = new BlazorWebView
{
HostPage = "wwwroot/index.html",
RootComponents =
{
new RootComponent { Selector = "#app", ComponentType = typeof(Main) }
},
};
}
}
================================================
FILE: samples/Spice.BlazorSample/GlobalUsings.cs
================================================
global using Microsoft.Maui.Graphics;
global using Spice;
================================================
FILE: samples/Spice.BlazorSample/Main.razor
================================================
<Router AppAssembly="typeof(Main).Assembly">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
<FocusOnNavigate RouteData="routeData" Selector="h1" />
</Found>
<NotFound>
<p role="alert">Sorry, there's nothing at this address.</p>
</NotFound>
</Router>
================================================
FILE: samples/Spice.BlazorSample/Pages/Index.razor
================================================
@page "/"
<h1>Hello, Spice + Blazor 🌶!</h1>
Welcome to your new app.
================================================
FILE: samples/Spice.BlazorSample/Platforms/Android/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
================================================
FILE: samples/Spice.BlazorSample/Platforms/Android/MainActivity.cs
================================================
using Android.App;
using Android.OS;
namespace Spice.BlazorSample;
[Activity(
// TODO: fix splash theme
// Theme = "@style/Maui.SplashTheme",
Theme = "@style/Theme.Material3.Light.NoActionBar",
MainLauncher = true)]
public class MainActivity : SpiceActivity
{
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(new App());
}
}
================================================
FILE: samples/Spice.BlazorSample/Platforms/iOS/AppDelegate.cs
================================================
using Foundation;
namespace Spice.BlazorSample;
[Register("AppDelegate")]
public class AppDelegate : SpiceAppDelegate
{
public override Application CreateApplication() => new App();
}
================================================
FILE: samples/Spice.BlazorSample/Platforms/iOS/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>SpiceSceneDelegate</string>
</dict>
</array>
</dict>
</dict>
</dict>
</plist>
================================================
FILE: samples/Spice.BlazorSample/Platforms/iOS/Program.cs
================================================
using UIKit;
using Spice.BlazorSample;
UIApplication.Main(args, null, typeof(AppDelegate));
================================================
FILE: samples/Spice.BlazorSample/Shared/MainLayout.razor
================================================
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<article class="content px-4">
@Body
</article>
</main>
</div>
================================================
FILE: samples/Spice.BlazorSample/Shared/MainLayout.razor.css
================================================
.page {
position: relative;
display: flex;
flex-direction: column;
}
main {
flex: 1;
}
.sidebar {
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}
.top-row {
background-color: #f7f7f7;
border-bottom: 1px solid #d6d5d5;
justify-content: flex-end;
height: 3.5rem;
display: flex;
align-items: center;
}
.top-row ::deep a, .top-row ::deep .btn-link {
white-space: nowrap;
margin-left: 1.5rem;
text-decoration: none;
}
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
text-decoration: underline;
}
.top-row ::deep a:first-child {
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 640.98px) {
.top-row:not(.auth) {
display: none;
}
.top-row.auth {
justify-content: space-between;
}
.top-row ::deep a, .top-row ::deep .btn-link {
margin-left: 0;
}
}
@media (min-width: 641px) {
.page {
flex-direction: row;
}
.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
}
.top-row {
position: sticky;
top: 0;
z-index: 1;
}
.top-row, article {
padding-left: 2rem !important;
padding-right: 1.5rem !important;
}
}
================================================
FILE: samples/Spice.BlazorSample/Shared/NavMenu.razor
================================================
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">Hello Blazor</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</div>
</nav>
</div>
@code {
private bool collapseNavMenu = true;
private string NavMenuCssClass => collapseNavMenu ? "collapse" : "";
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
================================================
FILE: samples/Spice.BlazorSample/Shared/NavMenu.razor.css
================================================
.navbar-toggler {
background-color: rgba(255, 255, 255, 0.1);
}
.top-row {
height: 3.5rem;
background-color: rgba(0,0,0,0.4);
}
.navbar-brand {
font-size: 1.1rem;
}
.oi {
width: 2rem;
font-size: 1.1rem;
vertical-align: text-top;
top: -2px;
}
.nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}
.nav-item:first-of-type {
padding-top: 1rem;
}
.nav-item:last-of-type {
padding-bottom: 1rem;
}
.nav-item ::deep a {
color: #d7d7d7;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
}
.nav-item ::deep a.active {
background-color: rgba(255,255,255,0.25);
color: white;
}
.nav-item ::deep a:hover {
background-color: rgba(255,255,255,0.1);
color: white;
}
@media (min-width: 641px) {
.navbar-toggler {
display: none;
}
.collapse {
/* Never collapse the sidebar for wide screens */
display: block;
}
}
================================================
FILE: samples/Spice.BlazorSample/Spice.BlazorSample.csproj
================================================
<Project>
<Import Sdk="Microsoft.NET.Sdk.Razor" Project="Sdk.props" />
<Import Project="../../src/Spice/MSBuild/Spice.props" />
<PropertyGroup>
<TargetFrameworks>net10.0-android;net10.0-ios</TargetFrameworks>
<OutputType>Exe</OutputType>
<RootNamespace>Spice.BlazorSample</RootNamespace>
<UseMauiAssets>true</UseMauiAssets>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<ApplicationTitle>Hello Blazor</ApplicationTitle>
<ApplicationId>com.companyname.spice.blazor</ApplicationId>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">16.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">23.0</SupportedOSPlatformVersion>
<RuntimeIdentifier Condition="'$(GITHUB_ACTIONS)' == 'true' and $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">android-arm64</RuntimeIdentifier>
<EnableDefaultCssItems>false</EnableDefaultCssItems>
<AndroidPackageFormat>apk</AndroidPackageFormat>
<!-- https://github.com/dotnet/aspnetcore/issues/63951 — Blazor doesn't support full trimming -->
<NoWarn>$(NoWarn);IL2026;IL2065;IL2067;IL2072;IL2104;IL2110;IL2111;IL2121</NoWarn>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\spice.svg" BaseSize="168,208" />
<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Spice\Spice.csproj" />
<PackageReference Include="Microsoft.Maui.Resizetizer" />
</ItemGroup>
<Import Sdk="Microsoft.NET.Sdk.Razor" Project="Sdk.targets" />
<Import Project="../../src/Spice/MSBuild/Spice.targets" />
</Project>
================================================
FILE: samples/Spice.BlazorSample/_Imports.razor
================================================
@using System.Net.Http
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Spice.BlazorSample
@using Spice.BlazorSample.Shared
================================================
FILE: samples/Spice.BlazorSample/wwwroot/css/app.css
================================================
@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
h1:focus {
outline: none;
}
a, .btn-link {
color: #0071c1;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.content {
padding-top: 1.1rem;
}
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}
.invalid {
outline: 1px solid red;
}
.validation-message {
color: red;
}
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
.blazor-error-boundary {
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
padding: 1rem 1rem 1rem 3.7rem;
color: white;
}
.blazor-error-boundary::after {
content: "An error has occurred."
}
.status-bar-safe-area {
display: none;
}
@supports (-webkit-touch-callout: none) {
.status-bar-safe-area {
display: flex;
position: sticky;
top: 0;
height: env(safe-area-inset-top);
background-color: #f7f7f7;
width: 100%;
z-index: 1;
}
.flex-column, .navbar-brand {
padding-left: env(safe-area-inset-left);
}
}
================================================
FILE: samples/Spice.BlazorSample/wwwroot/css/open-iconic/FONT-LICENSE
================================================
SIL OPEN FONT LICENSE Version 1.1
Copyright (c) 2014 Waybury
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
================================================
FILE: samples/Spice.BlazorSample/wwwroot/css/open-iconic/ICON-LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Waybury
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: samples/Spice.BlazorSample/wwwroot/css/open-iconic/README.md
================================================
[Open Iconic v1.1.1](https://github.com/iconic/open-iconic)
===========
### Open Iconic is the open source sibling of [Iconic](https://github.com/iconic/open-iconic). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](https://github.com/iconic/open-iconic)
## What's in Open Iconic?
* 223 icons designed to be legible down to 8 pixels
* Super-light SVG files - 61.8 for the entire set
* SVG sprite—the modern replacement for icon fonts
* Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats
* Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats
* PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.
## Getting Started
#### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](https://github.com/iconic/open-iconic) and [Reference](https://github.com/iconic/open-iconic) sections.
### General Usage
#### Using Open Iconic's SVGs
We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute).
```
<img src="/open-iconic/svg/icon-name.svg" alt="icon name">
```
#### Using Open Iconic's SVG Sprite
Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack.
Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `<svg>` *tag and a unique class name for each different icon in the* `<use>` *tag.*
```
<svg class="icon">
<use xlink:href="open-iconic.svg#account-login" class="icon-account-login"></use>
</svg>
```
Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `<svg>` tag with equal width and height dimensions.
```
.icon {
width: 16px;
height: 16px;
}
```
Coloring icons is even easier. All you need to do is set the `fill` rule on the `<use>` tag.
```
.icon-account-login {
fill: #f00;
}
```
To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/).
#### Using Open Iconic's Icon Font...
##### …with Bootstrap
You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}`
```
<link href="/open-iconic/font/css/open-iconic-bootstrap.css" rel="stylesheet">
```
```
<span class="oi oi-icon-name" title="icon name" aria-hidden="true"></span>
```
##### …with Foundation
You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}`
```
<link href="/open-iconic/font/css/open-iconic-foundation.css" rel="stylesheet">
```
```
<span class="fi-icon-name" title="icon name" aria-hidden="true"></span>
```
##### …on its own
You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}`
```
<link href="/open-iconic/font/css/open-iconic.css" rel="stylesheet">
```
```
<span class="oi" data-glyph="icon-name" title="icon name" aria-hidden="true"></span>
```
## License
### Icons
All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT).
### Fonts
All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web).
================================================
FILE: samples/Spice.BlazorSample/wwwroot/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<title>Hello Blazor</title>
<base href="/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/app.css" rel="stylesheet" />
<link href="Spice.BlazorSample.styles.css" rel="stylesheet" />
</head>
<body>
<div class="status-bar-safe-area"></div>
<div id="app">Loading...</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webview.js" autostart="false"></script>
</body>
</html>
================================================
FILE: samples/Spice.Scenarios/App.cs
================================================
namespace Spice.Scenarios;
public class App : Application
{
public App()
{
UseSystemTheme = true;
Main = new NavigationView(new ScenarioList());
}
}
class ScenarioList : StackLayout
{
public ScenarioList()
{
Title = "Scenarios";
Add(new Button { Text = "Hello World", Clicked = _ => Navigation!.Push<HelloWorldScenario>() });
Add(new Button { Text = "Ghost Button", Clicked = _ => Navigation!.Push<GhostButtonScenario>() });
Add(new Button { Text = "ImageButton", Clicked = _ => Navigation!.Push<ImageButtonScenario>() });
Add(new Button { Text = "WebView", Clicked = _ => Navigation!.Push<WebViewScenario>() });
Add(new Button { Text = "Entry", Clicked = _ => Navigation!.Push<EntryScenario>() });
Add(new Button { Text = "Editor", Clicked = _ => Navigation!.Push<EditorScenario>() });
Add(new Button { Text = "DatePicker", Clicked = _ => Navigation!.Push<DatePickerScenario>() });
Add(new Button { Text = "TimePicker", Clicked = _ => Navigation!.Push<TimePickerScenario>() });
Add(new Button { Text = "ActivityIndicator", Clicked = _ => Navigation!.Push<ActivityIndicatorScenario>() });
Add(new Button { Text = "BoxView", Clicked = _ => Navigation!.Push<BoxViewScenario>() });
Add(new Button { Text = "Switch", Clicked = _ => Navigation!.Push<SwitchScenario>() });
Add(new Button { Text = "ProgressBar", Clicked =
gitextract_5fqaxoqu/
├── .config/
│ └── dotnet-tools.json
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── copilot-setup-steps.yml
│ └── spice.yml
├── .gitignore
├── .vscode/
│ └── settings.json
├── Directory.Build.props
├── Directory.Build.targets
├── LICENSE
├── NuGet.config
├── README.md
├── docs/
│ ├── DATA-BINDING-SPEC.md
│ ├── MAUI-CONTROLS-COMPARISON.md
│ ├── NAVIGATION-SPEC.md
│ ├── THEME-SPEC.md
│ ├── VIEW-LIFECYCLE-SPEC.md
│ └── spice.pptx
├── global.json
├── samples/
│ ├── HeadToHeadMaui/
│ │ ├── App.xaml
│ │ ├── App.xaml.cs
│ │ ├── AppShell.xaml
│ │ ├── AppShell.xaml.cs
│ │ ├── HeadToHeadMaui.csproj
│ │ ├── HeadToHeadMaui.sln
│ │ ├── MainPage.xaml
│ │ ├── MainPage.xaml.cs
│ │ ├── MauiProgram.cs
│ │ ├── Platforms/
│ │ │ ├── Android/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── MainActivity.cs
│ │ │ │ ├── MainApplication.cs
│ │ │ │ └── Resources/
│ │ │ │ └── values/
│ │ │ │ └── colors.xml
│ │ │ ├── MacCatalyst/
│ │ │ │ ├── AppDelegate.cs
│ │ │ │ ├── Info.plist
│ │ │ │ └── Program.cs
│ │ │ ├── Tizen/
│ │ │ │ ├── Main.cs
│ │ │ │ └── tizen-manifest.xml
│ │ │ ├── Windows/
│ │ │ │ ├── App.xaml
│ │ │ │ ├── App.xaml.cs
│ │ │ │ ├── Package.appxmanifest
│ │ │ │ └── app.manifest
│ │ │ └── iOS/
│ │ │ ├── AppDelegate.cs
│ │ │ ├── Info.plist
│ │ │ └── Program.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ └── Resources/
│ │ ├── Raw/
│ │ │ └── AboutAssets.txt
│ │ └── Styles/
│ │ ├── Colors.xaml
│ │ └── Styles.xaml
│ ├── HeadToHeadSpice/
│ │ ├── App.cs
│ │ ├── GlobalUsings.cs
│ │ ├── HeadToHeadSpice.csproj
│ │ └── Platforms/
│ │ ├── Android/
│ │ │ ├── AndroidManifest.xml
│ │ │ └── MainActivity.cs
│ │ └── iOS/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Program.cs
│ ├── README.md
│ ├── Spice.BlazorSample/
│ │ ├── App.cs
│ │ ├── GlobalUsings.cs
│ │ ├── Main.razor
│ │ ├── Pages/
│ │ │ └── Index.razor
│ │ ├── Platforms/
│ │ │ ├── Android/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── MainActivity.cs
│ │ │ └── iOS/
│ │ │ ├── AppDelegate.cs
│ │ │ ├── Info.plist
│ │ │ └── Program.cs
│ │ ├── Shared/
│ │ │ ├── MainLayout.razor
│ │ │ ├── MainLayout.razor.css
│ │ │ ├── NavMenu.razor
│ │ │ └── NavMenu.razor.css
│ │ ├── Spice.BlazorSample.csproj
│ │ ├── _Imports.razor
│ │ └── wwwroot/
│ │ ├── css/
│ │ │ ├── app.css
│ │ │ └── open-iconic/
│ │ │ ├── FONT-LICENSE
│ │ │ ├── ICON-LICENSE
│ │ │ ├── README.md
│ │ │ └── font/
│ │ │ └── fonts/
│ │ │ └── open-iconic.otf
│ │ └── index.html
│ ├── Spice.Scenarios/
│ │ ├── App.cs
│ │ ├── GlobalUsings.cs
│ │ ├── Platforms/
│ │ │ ├── Android/
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── MainActivity.cs
│ │ │ └── iOS/
│ │ │ ├── AppDelegate.cs
│ │ │ ├── Info.plist
│ │ │ └── Program.cs
│ │ ├── Scenarios/
│ │ │ ├── ActivityIndicatorScenario.cs
│ │ │ ├── BorderScenario.cs
│ │ │ ├── BoxViewScenario.cs
│ │ │ ├── CheckBoxScenario.cs
│ │ │ ├── CollectionViewScenario.cs
│ │ │ ├── ContentViewScenario.cs
│ │ │ ├── DatePickerScenario.cs
│ │ │ ├── EditorScenario.cs
│ │ │ ├── EntryScenario.cs
│ │ │ ├── GhostButtonScenario.cs
│ │ │ ├── HelloWorldScenario.cs
│ │ │ ├── ImageButtonScenario.cs
│ │ │ ├── MarginScenario.cs
│ │ │ ├── PickerScenario.cs
│ │ │ ├── ProgressBarScenario.cs
│ │ │ ├── RadioButtonScenario.cs
│ │ │ ├── RefreshViewScenario.cs
│ │ │ ├── ScrollViewScenario.cs
│ │ │ ├── SearchBarScenario.cs
│ │ │ ├── SliderScenario.cs
│ │ │ ├── SwipeViewScenario.cs
│ │ │ ├── SwitchScenario.cs
│ │ │ ├── ThemeScenario.cs
│ │ │ ├── TimePickerScenario.cs
│ │ │ └── WebViewScenario.cs
│ │ └── Spice.Scenarios.csproj
│ └── samples.slnx
├── sizes/
│ ├── com.companyname.Hello-Signed.apkdesc
│ ├── com.companyname.HelloBlazor-Signed.apkdesc
│ └── startup.md
├── spice.slnx
├── src/
│ ├── ProfiledAot/
│ │ ├── Directory.Build.props
│ │ ├── Directory.Build.targets
│ │ ├── README.md
│ │ ├── build.proj
│ │ └── shared/
│ │ └── nuget.config
│ ├── Spice/
│ │ ├── Blazor/
│ │ │ ├── BlazorWebView.cs
│ │ │ ├── SpiceDispatcher.cs
│ │ │ ├── SpiceServiceProvider.cs
│ │ │ └── UriExtensions.cs
│ │ ├── Core/
│ │ │ ├── ActivityIndicator.cs
│ │ │ ├── Application.cs
│ │ │ ├── BindingExtensions.cs
│ │ │ ├── Border.cs
│ │ │ ├── BoxView.cs
│ │ │ ├── Button.cs
│ │ │ ├── CheckBox.cs
│ │ │ ├── CollectionView.cs
│ │ │ ├── ColumnDefinition.cs
│ │ │ ├── ContentView.cs
│ │ │ ├── DatePicker.cs
│ │ │ ├── Editor.cs
│ │ │ ├── Entry.cs
│ │ │ ├── Grid.cs
│ │ │ ├── GridLength.cs
│ │ │ ├── GridUnitType.cs
│ │ │ ├── Image.cs
│ │ │ ├── ImageButton.cs
│ │ │ ├── Label.cs
│ │ │ ├── LayoutAlignment.cs
│ │ │ ├── LayoutExpandFlag.cs
│ │ │ ├── LayoutOptions.cs
│ │ │ ├── NavigationView.cs
│ │ │ ├── Orientation.cs
│ │ │ ├── Picker.cs
│ │ │ ├── PlatformAppearance.cs
│ │ │ ├── ProgressBar.cs
│ │ │ ├── RadioButton.cs
│ │ │ ├── RefreshView.cs
│ │ │ ├── RootComponent.cs
│ │ │ ├── RowDefinition.cs
│ │ │ ├── ScrollView.cs
│ │ │ ├── SearchBar.cs
│ │ │ ├── SelectionMode.cs
│ │ │ ├── Slider.cs
│ │ │ ├── StackLayout.cs
│ │ │ ├── SwipeBehaviorOnInvoked.cs
│ │ │ ├── SwipeDirection.cs
│ │ │ ├── SwipeItem.cs
│ │ │ ├── SwipeItems.cs
│ │ │ ├── SwipeMode.cs
│ │ │ ├── SwipeView.cs
│ │ │ ├── Switch.cs
│ │ │ ├── TabView.cs
│ │ │ ├── Theme.cs
│ │ │ ├── Thickness.cs
│ │ │ ├── TimePicker.cs
│ │ │ ├── TwoWayBindingExtensions.cs
│ │ │ ├── View.cs
│ │ │ └── WebView.cs
│ │ ├── GlobalUsings.cs
│ │ ├── MSBuild/
│ │ │ ├── Spice.Blazor.targets
│ │ │ ├── Spice.props
│ │ │ ├── Spice.targets
│ │ │ ├── spice-blazor.aotprofile
│ │ │ ├── spice-blazor.aotprofile.txt
│ │ │ ├── spice.aotprofile
│ │ │ └── spice.aotprofile.txt
│ │ ├── Platforms/
│ │ │ ├── Android/
│ │ │ │ ├── ActivityIndicator.cs
│ │ │ │ ├── Application.cs
│ │ │ │ ├── Blazor/
│ │ │ │ │ ├── AndroidAssetFileProvider.cs
│ │ │ │ │ ├── AndroidWebViewManager.cs
│ │ │ │ │ ├── BlazorWebView.cs
│ │ │ │ │ ├── SpiceBlazorWebViewClient.cs
│ │ │ │ │ └── SpiceDispatcher.cs
│ │ │ │ ├── Border.cs
│ │ │ │ ├── BoxView.cs
│ │ │ │ ├── Button.cs
│ │ │ │ ├── CheckBox.cs
│ │ │ │ ├── CollectionView.cs
│ │ │ │ ├── ContentView.cs
│ │ │ │ ├── DatePicker.cs
│ │ │ │ ├── Editor.cs
│ │ │ │ ├── Entry.cs
│ │ │ │ ├── Grid.cs
│ │ │ │ ├── Image.cs
│ │ │ │ ├── ImageButton.cs
│ │ │ │ ├── Interop.java
│ │ │ │ ├── Label.cs
│ │ │ │ ├── NavigationView.cs
│ │ │ │ ├── Picker.cs
│ │ │ │ ├── Platform.cs
│ │ │ │ ├── PlatformAppearance.cs
│ │ │ │ ├── PlatformExtensions.cs
│ │ │ │ ├── ProgressBar.cs
│ │ │ │ ├── RadioButton.cs
│ │ │ │ ├── RefreshView.cs
│ │ │ │ ├── ScrollView.cs
│ │ │ │ ├── SearchBar.cs
│ │ │ │ ├── Slider.cs
│ │ │ │ ├── SpiceActivity.cs
│ │ │ │ ├── StackLayout.cs
│ │ │ │ ├── SwipeView.cs
│ │ │ │ ├── Switch.cs
│ │ │ │ ├── TabView.cs
│ │ │ │ ├── TimePicker.cs
│ │ │ │ ├── Transforms.xml
│ │ │ │ ├── View.cs
│ │ │ │ └── WebView.cs
│ │ │ └── iOS/
│ │ │ ├── ActivityIndicator.cs
│ │ │ ├── Application.cs
│ │ │ ├── Blazor/
│ │ │ │ ├── BlazorWebView.cs
│ │ │ │ ├── SpiceDispatcher.cs
│ │ │ │ ├── iOSFileProvider.cs
│ │ │ │ └── iOSWebViewManager.cs
│ │ │ ├── Border.cs
│ │ │ ├── BoxView.cs
│ │ │ ├── Button.cs
│ │ │ ├── CheckBox.cs
│ │ │ ├── CollectionView.cs
│ │ │ ├── ConstraintHelper.cs
│ │ │ ├── ContentView.cs
│ │ │ ├── DatePicker.cs
│ │ │ ├── Editor.cs
│ │ │ ├── Entry.cs
│ │ │ ├── Grid.cs
│ │ │ ├── Image.cs
│ │ │ ├── ImageButton.cs
│ │ │ ├── Label.cs
│ │ │ ├── NavigationView.cs
│ │ │ ├── Picker.cs
│ │ │ ├── Platform.cs
│ │ │ ├── PlatformAppearance.cs
│ │ │ ├── PlatformExtensions.cs
│ │ │ ├── ProgressBar.cs
│ │ │ ├── RadioButton.cs
│ │ │ ├── RefreshView.cs
│ │ │ ├── ScrollView.cs
│ │ │ ├── SearchBar.cs
│ │ │ ├── Slider.cs
│ │ │ ├── SpiceAppDelegate.cs
│ │ │ ├── SpiceViewController.cs
│ │ │ ├── StackLayout.cs
│ │ │ ├── SwipeView.cs
│ │ │ ├── Switch.cs
│ │ │ ├── TabView.cs
│ │ │ ├── TimePicker.cs
│ │ │ ├── View.cs
│ │ │ └── WebView.cs
│ │ ├── README.md
│ │ └── Spice.csproj
│ └── Spice.Templates/
│ ├── Spice.Templates.csproj
│ └── templates/
│ ├── spice/
│ │ ├── .template.config/
│ │ │ └── template.json
│ │ ├── App.cs
│ │ ├── GlobalUsings.cs
│ │ ├── Hello.csproj
│ │ └── Platforms/
│ │ ├── Android/
│ │ │ ├── AndroidManifest.xml
│ │ │ └── MainActivity.cs
│ │ └── iOS/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Program.cs
│ └── spice-blazor/
│ ├── .template.config/
│ │ └── template.json
│ ├── App.cs
│ ├── GlobalUsings.cs
│ ├── HelloBlazor.csproj
│ ├── Main.razor
│ ├── Pages/
│ │ └── Index.razor
│ ├── Platforms/
│ │ ├── Android/
│ │ │ ├── AndroidManifest.xml
│ │ │ └── MainActivity.cs
│ │ └── iOS/
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Program.cs
│ ├── Shared/
│ │ ├── MainLayout.razor
│ │ ├── MainLayout.razor.css
│ │ ├── NavMenu.razor
│ │ └── NavMenu.razor.css
│ ├── _Imports.razor
│ └── wwwroot/
│ ├── css/
│ │ ├── app.css
│ │ └── open-iconic/
│ │ ├── FONT-LICENSE
│ │ ├── ICON-LICENSE
│ │ ├── README.md
│ │ └── font/
│ │ └── fonts/
│ │ └── open-iconic.otf
│ └── index.html
└── tests/
└── Spice.Tests/
├── ActivityIndicatorTests.cs
├── ApplicationTests.cs
├── AutomationIdTests.cs
├── BindingExtensionsTests.cs
├── BorderTests.cs
├── BoxViewTests.cs
├── ButtonTests.cs
├── CheckBoxTests.cs
├── CollectionViewTests.cs
├── ContentViewTests.cs
├── DatePickerTests.cs
├── EditorTests.cs
├── EntryTests.cs
├── GridLengthTests.cs
├── GridTests.cs
├── ImageButtonTests.cs
├── ImageTests.cs
├── LabelTests.cs
├── LayoutOptionsTests.cs
├── MarginTests.cs
├── ModalPresentationTests.cs
├── NavigationViewTests.cs
├── PickerTests.cs
├── Platforms/
│ ├── Android/
│ │ ├── AndroidManifest.xml
│ │ ├── MainActivity.cs
│ │ ├── TestDevice.cs
│ │ ├── TestEntryPoint.cs
│ │ └── TestInstrumentation.cs
│ └── iOS/
│ ├── AppDelegate.cs
│ ├── Info.plist
│ ├── Program.cs
│ ├── TestDevice.cs
│ └── TestEntryPoint.cs
├── ProgressBarTests.cs
├── PropertyChangedTests.cs
├── RadioButtonTests.cs
├── RefreshViewTests.cs
├── ScrollViewTests.cs
├── SearchBarTests.cs
├── SliderTests.cs
├── Spice.Tests.csproj
├── StackLayoutTests.cs
├── SwipeItemsTests.cs
├── SwipeViewTests.cs
├── SwitchTests.cs
├── TabViewTests.cs
├── TestViewModel.cs
├── ThemeTests.cs
├── ThicknessTests.cs
├── TimePickerTests.cs
├── TwoWayBindingExtensionsTests.cs
├── Usings.cs
├── ViewLifecycleTests.cs
├── ViewOpacityTests.cs
├── ViewSizeTests.cs
├── ViewTests.cs
├── ViewVisibilityTests.cs
└── WebViewTests.cs
SYMBOL INDEX (1812 symbols across 239 files)
FILE: samples/HeadToHeadMaui/App.xaml.cs
class App (line 3) | public partial class App : Application
method App (line 5) | public App()
FILE: samples/HeadToHeadMaui/AppShell.xaml.cs
class AppShell (line 3) | public partial class AppShell : Shell
method AppShell (line 5) | public AppShell()
FILE: samples/HeadToHeadMaui/MainPage.xaml.cs
class MainPage (line 3) | public partial class MainPage : ContentPage
method MainPage (line 7) | public MainPage()
method OnCounterClicked (line 12) | private void OnCounterClicked(object sender, EventArgs e)
FILE: samples/HeadToHeadMaui/MauiProgram.cs
class MauiProgram (line 5) | public static class MauiProgram
method CreateMauiApp (line 7) | public static MauiApp CreateMauiApp()
FILE: samples/HeadToHeadMaui/Platforms/Android/MainActivity.cs
class MainActivity (line 7) | [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, Config...
FILE: samples/HeadToHeadMaui/Platforms/Android/MainApplication.cs
class MainApplication (line 6) | [Application]
method MainApplication (line 9) | public MainApplication(IntPtr handle, JniHandleOwnership ownership)
method CreateMauiApp (line 14) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
FILE: samples/HeadToHeadMaui/Platforms/MacCatalyst/AppDelegate.cs
class AppDelegate (line 5) | [Register("AppDelegate")]
method CreateMauiApp (line 8) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
FILE: samples/HeadToHeadMaui/Platforms/MacCatalyst/Program.cs
class Program (line 6) | public class Program
method Main (line 9) | static void Main(string[] args)
FILE: samples/HeadToHeadMaui/Platforms/Tizen/Main.cs
class Program (line 7) | class Program : MauiApplication
method CreateMauiApp (line 9) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
method Main (line 11) | static void Main(string[] args)
FILE: samples/HeadToHeadMaui/Platforms/Windows/App.xaml.cs
class App (line 11) | public partial class App : MauiWinUIApplication
method App (line 17) | public App()
method CreateMauiApp (line 22) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
FILE: samples/HeadToHeadMaui/Platforms/iOS/AppDelegate.cs
class AppDelegate (line 5) | [Register("AppDelegate")]
method CreateMauiApp (line 8) | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAp...
FILE: samples/HeadToHeadMaui/Platforms/iOS/Program.cs
class Program (line 6) | public class Program
method Main (line 9) | static void Main(string[] args)
FILE: samples/HeadToHeadSpice/App.cs
class App (line 6) | public class App : Application
method App (line 8) | public App()
FILE: samples/HeadToHeadSpice/Platforms/Android/MainActivity.cs
class MainActivity (line 6) | [Activity(
method OnCreate (line 11) | protected override void OnCreate(Bundle? savedInstanceState)
FILE: samples/HeadToHeadSpice/Platforms/iOS/AppDelegate.cs
class AppDelegate (line 5) | [Register("AppDelegate")]
method CreateApplication (line 8) | public override Application CreateApplication() => new App();
FILE: samples/Spice.BlazorSample/App.cs
class App (line 3) | public class App : Application
method App (line 5) | public App()
FILE: samples/Spice.BlazorSample/Platforms/Android/MainActivity.cs
class MainActivity (line 6) | [Activity(
method OnCreate (line 13) | protected override void OnCreate(Bundle? savedInstanceState)
FILE: samples/Spice.BlazorSample/Platforms/iOS/AppDelegate.cs
class AppDelegate (line 5) | [Register("AppDelegate")]
method CreateApplication (line 8) | public override Application CreateApplication() => new App();
FILE: samples/Spice.Scenarios/App.cs
class App (line 3) | public class App : Application
method App (line 5) | public App()
class ScenarioList (line 13) | class ScenarioList : StackLayout
method ScenarioList (line 15) | public ScenarioList()
FILE: samples/Spice.Scenarios/Platforms/Android/MainActivity.cs
class MainActivity (line 6) | [Activity(
method OnCreate (line 13) | protected override void OnCreate(Bundle? savedInstanceState)
FILE: samples/Spice.Scenarios/Platforms/iOS/AppDelegate.cs
class AppDelegate (line 5) | [Register("AppDelegate")]
method CreateApplication (line 8) | public override Application CreateApplication() => new App();
FILE: samples/Spice.Scenarios/Scenarios/ActivityIndicatorScenario.cs
class ActivityIndicatorScenario (line 3) | class ActivityIndicatorScenario : StackLayout
method ActivityIndicatorScenario (line 5) | public ActivityIndicatorScenario()
FILE: samples/Spice.Scenarios/Scenarios/BorderScenario.cs
class BorderScenario (line 6) | class BorderScenario : StackLayout
method BorderScenario (line 8) | public BorderScenario()
FILE: samples/Spice.Scenarios/Scenarios/BoxViewScenario.cs
class BoxViewScenario (line 3) | class BoxViewScenario : StackLayout
method BoxViewScenario (line 5) | public BoxViewScenario()
FILE: samples/Spice.Scenarios/Scenarios/CheckBoxScenario.cs
class CheckBoxScenario (line 6) | class CheckBoxScenario : StackLayout
method CheckBoxScenario (line 8) | public CheckBoxScenario()
FILE: samples/Spice.Scenarios/Scenarios/CollectionViewScenario.cs
class CollectionViewScenario (line 8) | class CollectionViewScenario : StackLayout
method CollectionViewScenario (line 10) | public CollectionViewScenario()
class Person (line 127) | class Person
FILE: samples/Spice.Scenarios/Scenarios/ContentViewScenario.cs
class ContentViewScenario (line 3) | public class ContentViewScenario : Application
method ContentViewScenario (line 5) | public ContentViewScenario()
FILE: samples/Spice.Scenarios/Scenarios/DatePickerScenario.cs
class DatePickerScenario (line 3) | class DatePickerScenario : StackLayout
method DatePickerScenario (line 5) | public DatePickerScenario()
FILE: samples/Spice.Scenarios/Scenarios/EditorScenario.cs
class EditorScenario (line 3) | class EditorScenario : StackLayout
method EditorScenario (line 5) | public EditorScenario()
FILE: samples/Spice.Scenarios/Scenarios/EntryScenario.cs
class EntryScenario (line 3) | class EntryScenario : StackLayout
method EntryScenario (line 5) | public EntryScenario()
FILE: samples/Spice.Scenarios/Scenarios/GhostButtonScenario.cs
class GhostButtonScenario (line 6) | class GhostButtonScenario : StackLayout
method GhostButtonScenario (line 8) | public GhostButtonScenario()
class GhostButton (line 30) | class GhostButton : Button
method GhostButton (line 32) | public GhostButton() => NativeView.Alpha = 0.5f;
FILE: samples/Spice.Scenarios/Scenarios/HelloWorldScenario.cs
class HelloWorldScenario (line 7) | class HelloWorldScenario : StackLayout
method HelloWorldScenario (line 9) | public HelloWorldScenario()
FILE: samples/Spice.Scenarios/Scenarios/ImageButtonScenario.cs
class ImageButtonScenario (line 6) | class ImageButtonScenario : StackLayout
method ImageButtonScenario (line 8) | public ImageButtonScenario()
FILE: samples/Spice.Scenarios/Scenarios/MarginScenario.cs
class MarginScenario (line 3) | class MarginScenario : StackLayout
method MarginScenario (line 5) | public MarginScenario()
FILE: samples/Spice.Scenarios/Scenarios/PickerScenario.cs
class PickerScenario (line 5) | class PickerScenario : StackLayout
method PickerScenario (line 7) | public PickerScenario()
FILE: samples/Spice.Scenarios/Scenarios/ProgressBarScenario.cs
class ProgressBarScenario (line 6) | class ProgressBarScenario : StackLayout
method ProgressBarScenario (line 12) | public ProgressBarScenario()
method IncrementProgress (line 59) | void IncrementProgress()
method SetProgress (line 65) | void SetProgress(double value)
FILE: samples/Spice.Scenarios/Scenarios/RadioButtonScenario.cs
class RadioButtonScenario (line 6) | class RadioButtonScenario : StackLayout
method RadioButtonScenario (line 8) | public RadioButtonScenario()
FILE: samples/Spice.Scenarios/Scenarios/RefreshViewScenario.cs
class RefreshViewScenario (line 6) | class RefreshViewScenario : StackLayout
method RefreshViewScenario (line 10) | public RefreshViewScenario()
FILE: samples/Spice.Scenarios/Scenarios/ScrollViewScenario.cs
class ScrollViewScenario (line 6) | class ScrollViewScenario : ScrollView
method ScrollViewScenario (line 8) | public ScrollViewScenario()
FILE: samples/Spice.Scenarios/Scenarios/SearchBarScenario.cs
class SearchBarScenario (line 3) | class SearchBarScenario : StackLayout
method SearchBarScenario (line 5) | public SearchBarScenario()
FILE: samples/Spice.Scenarios/Scenarios/SliderScenario.cs
class SliderScenario (line 3) | class SliderScenario : StackLayout
method SliderScenario (line 5) | public SliderScenario()
FILE: samples/Spice.Scenarios/Scenarios/SwipeViewScenario.cs
class SwipeViewScenario (line 6) | public class SwipeViewScenario : ContentView
method SwipeViewScenario (line 8) | public SwipeViewScenario()
method CreateSwipeViewItem (line 42) | SwipeView CreateSwipeViewItem(string title, string subtitle)
method CreateSwipeViewWithLeftItems (line 86) | SwipeView CreateSwipeViewWithLeftItems(string title, string subtitle)
method CreateSwipeViewWithBothItems (line 130) | SwipeView CreateSwipeViewWithBothItems(string title, string subtitle)
FILE: samples/Spice.Scenarios/Scenarios/SwitchScenario.cs
class SwitchScenario (line 6) | class SwitchScenario : StackLayout
method SwitchScenario (line 8) | public SwitchScenario()
FILE: samples/Spice.Scenarios/Scenarios/ThemeScenario.cs
class ThemeScenario (line 6) | class ThemeScenario : StackLayout
method ThemeScenario (line 8) | public ThemeScenario()
FILE: samples/Spice.Scenarios/Scenarios/TimePickerScenario.cs
class TimePickerScenario (line 3) | class TimePickerScenario : StackLayout
method TimePickerScenario (line 5) | public TimePickerScenario()
method GetTimeDisplayText (line 39) | static string GetTimeDisplayText(TimeOnly time) =>
FILE: samples/Spice.Scenarios/Scenarios/WebViewScenario.cs
class WebViewScenario (line 6) | class WebViewScenario : WebView
method WebViewScenario (line 8) | public WebViewScenario()
FILE: src/Spice.Templates/templates/spice-blazor/App.cs
class App (line 3) | public class App : Application
method App (line 5) | public App()
FILE: src/Spice.Templates/templates/spice-blazor/Platforms/Android/MainActivity.cs
class MainActivity (line 6) | [Activity(
method OnCreate (line 13) | protected override void OnCreate(Bundle? savedInstanceState)
FILE: src/Spice.Templates/templates/spice-blazor/Platforms/iOS/AppDelegate.cs
class AppDelegate (line 5) | [Register("AppDelegate")]
method CreateApplication (line 8) | public override Application CreateApplication() => new App();
FILE: src/Spice.Templates/templates/spice/App.cs
class App (line 3) | public class App : Application
method App (line 5) | public App()
FILE: src/Spice.Templates/templates/spice/Platforms/Android/MainActivity.cs
class MainActivity (line 6) | [Activity(
method OnCreate (line 11) | protected override void OnCreate(Bundle? savedInstanceState)
FILE: src/Spice.Templates/templates/spice/Platforms/iOS/AppDelegate.cs
class AppDelegate (line 5) | [Register("AppDelegate")]
method CreateApplication (line 8) | public override Application CreateApplication() => new App();
FILE: src/Spice/Blazor/BlazorWebView.cs
class BlazorWebView (line 13) | public partial class BlazorWebView : WebView
method Initialize (line 47) | void Initialize()
method LoadWebView (line 56) | void LoadWebView()
method LoadNativeWebView (line 72) | partial void LoadNativeWebView(string contentRootDir, string hostPageR...
method OnCollectionChanged (line 74) | void OnCollectionChanged(object? sender, NotifyCollectionChangedEventA...
method OnHostPageChanged (line 76) | partial void OnHostPageChanged(string value) => LoadWebView();
method OnRootComponentsChanging (line 78) | partial void OnRootComponentsChanging(ObservableCollection<RootCompone...
method OnRootComponentsChanged (line 84) | partial void OnRootComponentsChanged(ObservableCollection<RootComponen...
FILE: src/Spice/Blazor/SpiceDispatcher.cs
class SpiceDispatcher (line 5) | internal partial class SpiceDispatcher
FILE: src/Spice/Blazor/SpiceServiceProvider.cs
class SpiceServiceProvider (line 8) | internal class SpiceServiceProvider
method SpiceServiceProvider (line 12) | static SpiceServiceProvider()
FILE: src/Spice/Blazor/UriExtensions.cs
class UriExtensions (line 4) | internal static class UriExtensions
method IsBaseOfPage (line 6) | internal static bool IsBaseOfPage(this Uri baseUri, string? uriString)
method RemovePossibleQueryString (line 19) | public static string RemovePossibleQueryString(string? url)
FILE: src/Spice/Core/ActivityIndicator.cs
class ActivityIndicator (line 8) | public partial class ActivityIndicator : View
method ApplyTheme (line 23) | protected override void ApplyTheme(Theme theme)
method OnColorChanging (line 30) | partial void OnColorChanging(Color? value) => TrackExplicit((int)Theme...
FILE: src/Spice/Core/Application.cs
class Application (line 8) | public partial class Application : View
method OnThemeChanging (line 42) | partial void OnThemeChanging(Theme? value)
method OnThemeChanged (line 48) | partial void OnThemeChanged(Theme? oldValue, Theme? newValue)
method OnMainChanged (line 60) | partial void OnMainChanged(View? oldValue, View? newValue)
method OnThemePropertyChanged (line 66) | void OnThemePropertyChanged(object? sender, PropertyChangedEventArgs e)
method OnUseSystemThemeChanged (line 72) | partial void OnUseSystemThemeChanged(bool value)
method OnPlatformAppearanceChanged (line 87) | void OnPlatformAppearanceChanged(bool isDarkMode)
FILE: src/Spice/Core/BindingExtensions.cs
class BindingExtensions (line 9) | public static class BindingExtensions
method Bind (line 30) | public static IDisposable Bind<TSource, TValue>(
class BindingSubscription (line 59) | internal sealed class BindingSubscription : IDisposable
method BindingSubscription (line 65) | public BindingSubscription(INotifyPropertyChanged source, PropertyChan...
method Dispose (line 71) | public void Dispose()
FILE: src/Spice/Core/Border.cs
class Border (line 8) | public partial class Border : View
method ApplyTheme (line 41) | protected override void ApplyTheme(Theme theme)
method OnStrokeChanging (line 48) | partial void OnStrokeChanging(Color? value) => TrackExplicit((int)Them...
FILE: src/Spice/Core/BoxView.cs
class BoxView (line 8) | public partial class BoxView : View
FILE: src/Spice/Core/Button.cs
class Button (line 8) | public partial class Button : View
method ApplyTheme (line 29) | protected override void ApplyTheme(Theme theme)
method OnTextColorChanging (line 38) | partial void OnTextColorChanging(Color? value) => TrackExplicit((int)T...
FILE: src/Spice/Core/CheckBox.cs
class CheckBox (line 8) | public partial class CheckBox : View
FILE: src/Spice/Core/CollectionView.cs
class CollectionView (line 10) | public partial class CollectionView : View, IDisposable
method CreateItemView (line 58) | internal View CreateItemView(object item)
method Dispose (line 69) | public void Dispose()
FILE: src/Spice/Core/ColumnDefinition.cs
class ColumnDefinition (line 6) | public partial class ColumnDefinition : ObservableObject
method ColumnDefinition (line 17) | public ColumnDefinition()
method ColumnDefinition (line 24) | public ColumnDefinition(GridLength width)
FILE: src/Spice/Core/ContentView.cs
class ContentView (line 9) | public partial class ContentView : View
method OnContentChanged (line 37) | partial void OnContentChanged(View? oldContent, View? newContent);
FILE: src/Spice/Core/DatePicker.cs
class DatePicker (line 8) | public partial class DatePicker : View
method ApplyTheme (line 35) | protected override void ApplyTheme(Theme theme)
method OnTextColorChanging (line 42) | partial void OnTextColorChanging(Color? value) => TrackExplicit((int)T...
FILE: src/Spice/Core/Editor.cs
class Editor (line 8) | public partial class Editor : View
method ApplyTheme (line 44) | protected override void ApplyTheme(Theme theme)
method OnTextColorChanging (line 53) | partial void OnTextColorChanging(Color? value) => TrackExplicit((int)T...
method OnPlaceholderColorChanging (line 55) | partial void OnPlaceholderColorChanging(Color? value) => TrackExplicit...
FILE: src/Spice/Core/Entry.cs
class Entry (line 8) | public partial class Entry : View
method ApplyTheme (line 29) | protected override void ApplyTheme(Theme theme)
method OnTextColorChanging (line 36) | partial void OnTextColorChanging(Color? value) => TrackExplicit((int)T...
FILE: src/Spice/Core/Grid.cs
class Grid (line 12) | public partial class Grid : View
method GetRow (line 52) | public static int GetRow(View view) => _rows.TryGetValue(view, out var...
method SetRow (line 57) | public static void SetRow(View view, int row)
method GetColumn (line 67) | public static int GetColumn(View view) => _columns.TryGetValue(view, o...
method SetColumn (line 72) | public static void SetColumn(View view, int column)
method GetRowSpan (line 82) | public static int GetRowSpan(View view) => _rowSpans.TryGetValue(view,...
method SetRowSpan (line 87) | public static void SetRowSpan(View view, int span)
method GetColumnSpan (line 97) | public static int GetColumnSpan(View view) => _columnSpans.TryGetValue...
method SetColumnSpan (line 102) | public static void SetColumnSpan(View view, int span)
FILE: src/Spice/Core/GridLength.cs
type GridLength (line 6) | public struct GridLength : IEquatable<GridLength>
method GridLength (line 11) | public GridLength(double value) : this(value, GridUnitType.Absolute)
method GridLength (line 18) | public GridLength(double value, GridUnitType type)
method Equals (line 68) | public bool Equals(GridLength other) =>
method Equals (line 72) | public override bool Equals(object? obj) => obj is GridLength other &&...
method GetHashCode (line 75) | public override int GetHashCode() => HashCode.Combine(GridUnitType, Va...
method ToString (line 88) | public override string ToString()
FILE: src/Spice/Core/GridUnitType.cs
type GridUnitType (line 6) | public enum GridUnitType
FILE: src/Spice/Core/Image.cs
class Image (line 8) | public partial class Image : View
FILE: src/Spice/Core/ImageButton.cs
class ImageButton (line 8) | public partial class ImageButton : View
FILE: src/Spice/Core/Label.cs
class Label (line 8) | public partial class Label : View
method ApplyTheme (line 23) | protected override void ApplyTheme(Theme theme)
method OnTextColorChanging (line 30) | partial void OnTextColorChanging(Color? value) => TrackExplicit((int)T...
FILE: src/Spice/Core/LayoutAlignment.cs
type LayoutAlignment (line 7) | public enum LayoutAlignment
FILE: src/Spice/Core/LayoutExpandFlag.cs
type LayoutExpandFlag (line 3) | [Flags]
FILE: src/Spice/Core/LayoutOptions.cs
type LayoutOptions (line 9) | public struct LayoutOptions : IEquatable<LayoutOptions>
method LayoutOptions (line 41) | public LayoutOptions(LayoutAlignment alignment, bool expands)
method Equals (line 64) | public bool Equals(LayoutOptions other) => _flags == other._flags;
method Equals (line 67) | public override bool Equals(object? obj) => obj is LayoutOptions other...
method GetHashCode (line 70) | public override int GetHashCode() => _flags.GetHashCode();
FILE: src/Spice/Core/NavigationView.cs
class NavigationView (line 7) | public partial class NavigationView : View
method NavigationView (line 13) | public NavigationView() { }
method NavigationView (line 20) | public NavigationView(View root) : this()
method NavigationView (line 31) | public NavigationView(Func<View> factory) : this()
method Push (line 41) | public void Push(View view)
method Push (line 53) | public void Push(Func<View> factory)
method Push (line 65) | public void Push<T>() where T : View, new()
method Pop (line 73) | public void Pop()
method PopToRoot (line 81) | public void PopToRoot()
method PushCore (line 89) | partial void PushCore(View view);
method PopCore (line 94) | partial void PopCore();
method PopToRootCore (line 99) | partial void PopToRootCore();
method NavigationView (line 111) | public NavigationView() : base(() => new TRoot())
class NavigationView (line 106) | public partial class NavigationView<TRoot> : NavigationView where TRoot ...
method NavigationView (line 13) | public NavigationView() { }
method NavigationView (line 20) | public NavigationView(View root) : this()
method NavigationView (line 31) | public NavigationView(Func<View> factory) : this()
method Push (line 41) | public void Push(View view)
method Push (line 53) | public void Push(Func<View> factory)
method Push (line 65) | public void Push<T>() where T : View, new()
method Pop (line 73) | public void Pop()
method PopToRoot (line 81) | public void PopToRoot()
method PushCore (line 89) | partial void PushCore(View view);
method PopCore (line 94) | partial void PopCore();
method PopToRootCore (line 99) | partial void PopToRootCore();
method NavigationView (line 111) | public NavigationView() : base(() => new TRoot())
FILE: src/Spice/Core/Orientation.cs
type Orientation (line 7) | public enum Orientation
FILE: src/Spice/Core/Picker.cs
class Picker (line 10) | public partial class Picker : View
method OnSelectedIndexChanged (line 29) | partial void OnSelectedIndexChanged(int oldValue, int newValue)
method OnItemsChanged (line 34) | partial void OnItemsChanged(ObservableCollection<string> value)
method ApplyTheme (line 52) | protected override void ApplyTheme(Theme theme)
method OnTextColorChanging (line 59) | partial void OnTextColorChanging(Color? value) => TrackExplicit((int)T...
FILE: src/Spice/Core/PlatformAppearance.cs
class PlatformAppearance (line 7) | public static partial class PlatformAppearance
method OnChanged (line 15) | internal static void OnChanged(bool isDarkMode) => Changed?.Invoke(isD...
FILE: src/Spice/Core/ProgressBar.cs
class ProgressBar (line 8) | public partial class ProgressBar : View
method OnProgressChanged (line 32) | partial void OnProgressChanged(double value);
FILE: src/Spice/Core/RadioButton.cs
class RadioButton (line 12) | public partial class RadioButton : View
method OnIsCheckedChanged (line 40) | partial void OnIsCheckedChanged(bool value)
method OnGroupNameChanged (line 51) | partial void OnGroupNameChanged(string? oldValue, string? newValue)
method UncheckOthersInGroup (line 78) | void UncheckOthersInGroup()
method OnIsCheckedChangedPartial (line 133) | partial void OnIsCheckedChangedPartial(bool value);
FILE: src/Spice/Core/RefreshView.cs
class RefreshView (line 9) | public partial class RefreshView : View
method OnContentChanged (line 57) | partial void OnContentChanged(View? oldContent, View? newContent);
FILE: src/Spice/Core/RootComponent.cs
class RootComponent (line 13) | public class RootComponent
method AddToWebViewManagerAsync (line 31) | internal Task AddToWebViewManagerAsync(WebViewManager webViewManager)
method RemoveFromWebViewManagerAsync (line 51) | internal Task RemoveFromWebViewManagerAsync(WebViewManager webviewMana...
FILE: src/Spice/Core/RowDefinition.cs
class RowDefinition (line 6) | public partial class RowDefinition : ObservableObject
method RowDefinition (line 17) | public RowDefinition()
method RowDefinition (line 24) | public RowDefinition(GridLength height)
FILE: src/Spice/Core/ScrollView.cs
class ScrollView (line 8) | public partial class ScrollView : View
FILE: src/Spice/Core/SearchBar.cs
class SearchBar (line 8) | public partial class SearchBar : View
method ApplyTheme (line 47) | protected override void ApplyTheme(Theme theme)
method OnTextColorChanging (line 56) | partial void OnTextColorChanging(Color? value) => TrackExplicit((int)T...
method OnPlaceholderColorChanging (line 58) | partial void OnPlaceholderColorChanging(Color? value) => TrackExplicit...
FILE: src/Spice/Core/SelectionMode.cs
type SelectionMode (line 6) | public enum SelectionMode
FILE: src/Spice/Core/Slider.cs
class Slider (line 13) | public partial class Slider : View
FILE: src/Spice/Core/StackLayout.cs
class StackLayout (line 8) | public partial class StackLayout : View
FILE: src/Spice/Core/SwipeBehaviorOnInvoked.cs
type SwipeBehaviorOnInvoked (line 6) | public enum SwipeBehaviorOnInvoked
FILE: src/Spice/Core/SwipeDirection.cs
type SwipeDirection (line 6) | public enum SwipeDirection
FILE: src/Spice/Core/SwipeItem.cs
class SwipeItem (line 7) | public partial class SwipeItem : ObservableObject
FILE: src/Spice/Core/SwipeItems.cs
class SwipeItems (line 9) | public partial class SwipeItems : ObservableObject
method SwipeItems (line 32) | public SwipeItems()
method SwipeItems (line 40) | public SwipeItems(IEnumerable<SwipeItem> items)
FILE: src/Spice/Core/SwipeMode.cs
type SwipeMode (line 6) | public enum SwipeMode
FILE: src/Spice/Core/SwipeView.cs
class SwipeView (line 9) | public partial class SwipeView : View
method OnContentChanged (line 99) | partial void OnContentChanged(View? oldContent, View? newContent);
method Open (line 105) | public void Open(SwipeDirection direction)
method Close (line 113) | public void Close()
method OnOpen (line 118) | partial void OnOpen(SwipeDirection direction);
method OnClose (line 119) | partial void OnClose();
FILE: src/Spice/Core/Switch.cs
class Switch (line 8) | public partial class Switch : View
FILE: src/Spice/Core/TabView.cs
class TabView (line 7) | public partial class TabView : View
method Add (line 13) | public void Add(Tab tab)
class Tab (line 23) | public partial class Tab : View
method Tab (line 58) | public Tab(string title, string icon, View content)
method Tab (line 76) | public Tab(string title, string icon, Func<View> factory)
method EnsureContent (line 93) | public void EnsureContent()
method Tab (line 114) | public Tab(string title, string icon) : base(title, icon, () => new TC...
class Tab (line 107) | public partial class Tab<TContent> : Tab where TContent : View, new()
method Tab (line 58) | public Tab(string title, string icon, View content)
method Tab (line 76) | public Tab(string title, string icon, Func<View> factory)
method EnsureContent (line 93) | public void EnsureContent()
method Tab (line 114) | public Tab(string title, string icon) : base(title, icon, () => new TC...
FILE: src/Spice/Core/Theme.cs
class Theme (line 8) | public partial class Theme : ObservableObject
FILE: src/Spice/Core/Thickness.cs
type Thickness (line 7) | public struct Thickness : IEquatable<Thickness>
method Thickness (line 33) | public Thickness(double uniformSize)
method Thickness (line 43) | public Thickness(double horizontalSize, double verticalSize)
method Thickness (line 56) | public Thickness(double left, double top, double right, double bottom)
method Equals (line 97) | public bool Equals(Thickness other) =>
method Equals (line 103) | public override bool Equals(object? obj) => obj is Thickness other && ...
method GetHashCode (line 108) | public override int GetHashCode() => HashCode.Combine(Left, Top, Right...
method ToString (line 113) | public override string ToString()
FILE: src/Spice/Core/TimePicker.cs
class TimePicker (line 8) | public partial class TimePicker : View
FILE: src/Spice/Core/TwoWayBindingExtensions.cs
class TwoWayBindingExtensions (line 8) | public static class TwoWayBindingExtensions
method BindTwoWay (line 36) | public static IDisposable BindTwoWay<TSource, TValue>(
class TwoWayBindingSubscription (line 103) | internal sealed class TwoWayBindingSubscription : IDisposable
method TwoWayBindingSubscription (line 111) | public TwoWayBindingSubscription(
method Dispose (line 123) | public void Dispose()
FILE: src/Spice/Core/View.cs
class View (line 10) | public partial class View : ObservableObject, IEnumerable<View>
type ThemeProperty (line 16) | [Flags]
method TrackExplicit (line 42) | public void TrackExplicit(int property, object? value)
method CanApplyTheme (line 56) | public bool CanApplyTheme(int property) => (_explicitProps & property)...
method ApplyTheme (line 64) | protected virtual void ApplyTheme(Theme theme)
method ApplyThemeInternal (line 70) | internal void ApplyThemeInternal(Theme theme)
method OnBackgroundColorChanging (line 85) | partial void OnBackgroundColorChanging(Color? value) => TrackExplicit(...
method OnThemeChildrenChanged (line 87) | void OnThemeChildrenChanged(object? sender, NotifyCollectionChangedEve...
method ApplyThemeToTree (line 96) | internal static void ApplyThemeToTree(View? view, Theme theme)
method Add (line 112) | public void Add(View item) => Children.Add(item);
method GetEnumerator (line 117) | public IEnumerator<View> GetEnumerator() => Children.GetEnumerator();
method GetEnumerator (line 119) | IEnumerator IEnumerable.GetEnumerator() => Children.GetEnumerator();
method PresentAsync (line 197) | public Task PresentAsync(View view)
method PresentAsync (line 208) | public Task PresentAsync(Func<View> factory)
method PresentAsync (line 221) | public Task PresentAsync<T>() where T : View, new()
method DismissAsync (line 230) | public Task DismissAsync()
method PresentAsyncCore (line 239) | private Task PresentAsyncCore(View view) => Task.CompletedTask;
method PresentAsyncCore (line 241) | private partial Task PresentAsyncCore(View view);
method DismissAsyncCore (line 248) | private Task DismissAsyncCore() => Task.CompletedTask;
method DismissAsyncCore (line 250) | private partial Task DismissAsyncCore();
method OnOpacityChanged (line 256) | partial void OnOpacityChanged(double value);
method GetWidth (line 303) | private partial double GetWidth();
method GetHeight (line 308) | private partial double GetHeight();
method DisposeRecursive (line 317) | internal static void DisposeRecursive(View view)
FILE: src/Spice/Core/WebView.cs
class WebView (line 8) | public partial class WebView : View
FILE: src/Spice/Platforms/Android/ActivityIndicator.cs
class ActivityIndicator (line 6) | public partial class ActivityIndicator
method Create (line 14) | static AndroidProgressBar Create(Context context)
method ActivityIndicator (line 27) | public ActivityIndicator() : base(Platform.Context, Create) { }
method ActivityIndicator (line 31) | public ActivityIndicator(Context context) : base(context, Create) { }
method ActivityIndicator (line 35) | protected ActivityIndicator(Func<Context, Android.Views.View> creator)...
method ActivityIndicator (line 40) | protected ActivityIndicator(Context context, Func<Context, Android.Vie...
method OnIsRunningChanged (line 47) | partial void OnIsRunningChanged(bool value)
method OnColorChanged (line 52) | partial void OnColorChanged(Color? value)
FILE: src/Spice/Platforms/Android/Application.cs
class Application (line 5) | public partial class Application
method Application (line 10) | public Application() { }
method Application (line 14) | public Application(Context context) : base(context) { }
method CreateLayoutParameters (line 17) | protected override Android.Views.ViewGroup.LayoutParams CreateLayoutPa...
method OnMainChanging (line 20) | partial void OnMainChanging(View? value)
method OnMainChanged (line 28) | partial void OnMainChanged(View? value)
FILE: src/Spice/Platforms/Android/Blazor/AndroidAssetFileProvider.cs
class AndroidAssetFileProvider (line 16) | internal sealed class AndroidAssetFileProvider : IFileProvider
method AndroidAssetFileProvider (line 21) | public AndroidAssetFileProvider(AssetManager? assets, string contentRo...
method GetDirectoryContents (line 27) | public IDirectoryContents GetDirectoryContents(string subpath)
method GetFileInfo (line 30) | public IFileInfo GetFileInfo(string subpath)
method Watch (line 33) | public IChangeToken Watch(string filter)
class AndroidMauiAssetFileInfo (line 36) | private sealed class AndroidMauiAssetFileInfo : IFileInfo
method AndroidMauiAssetFileInfo (line 43) | public AndroidMauiAssetFileInfo(AssetManager assets, string filePath)
method CreateReadStream (line 96) | public Stream CreateReadStream()
class AndroidMauiAssetDirectoryContents (line 101) | private sealed class AndroidMauiAssetDirectoryContents : IDirectoryCon...
method AndroidMauiAssetDirectoryContents (line 103) | public AndroidMauiAssetDirectoryContents(AssetManager assets, string...
method GetEnumerator (line 109) | public IEnumerator<IFileInfo> GetEnumerator()
method GetEnumerator (line 112) | IEnumerator IEnumerable.GetEnumerator()
FILE: src/Spice/Platforms/Android/Blazor/AndroidWebViewManager.cs
class AndroidWebViewManager (line 21) | [SupportedOSPlatform("android23.0")]
method AndroidWebViewManager (line 43) | public AndroidWebViewManager(AWebView webview, IServiceProvider servic...
method NavigateCore (line 52) | protected override void NavigateCore(Uri absoluteUri)
method SendMessage (line 58) | protected override void SendMessage(string message)
method TryGetResponseContentInternal (line 63) | internal bool TryGetResponseContentInternal(string uri, bool allowFall...
method SetUpMessageChannel (line 72) | internal void SetUpMessageChannel()
class BlazorWebMessageCallback (line 89) | private class BlazorWebMessageCallback : WebMessagePort.WebMessageCall...
method BlazorWebMessageCallback (line 93) | public BlazorWebMessageCallback(Action<string?> onMessageReceived)
method OnMessage (line 98) | public override void OnMessage(WebMessagePort? port, WebMessage? mes...
FILE: src/Spice/Platforms/Android/Blazor/BlazorWebView.cs
class BlazorWebView (line 9) | [SupportedOSPlatform("android23.0")]
method BlazorWebView (line 23) | public BlazorWebView() : this(Platform.Context, Create) => Initialize();
method BlazorWebView (line 27) | public BlazorWebView(Context context) : this(context, Create) => Initi...
method BlazorWebView (line 31) | protected BlazorWebView(Func<Context, Android.Views.View> creator) : t...
method BlazorWebView (line 36) | protected BlazorWebView(Context context, Func<Context, Android.Views.V...
method SetClients (line 44) | protected override void SetClients()
method LoadNativeWebView (line 51) | partial void LoadNativeWebView(string contentRootDir, string hostPageR...
FILE: src/Spice/Platforms/Android/Blazor/SpiceBlazorWebViewClient.cs
class SpiceBlazorWebViewClient (line 17) | [SupportedOSPlatform("android23.0")]
method SpiceBlazorWebViewClient (line 27) | public SpiceBlazorWebViewClient(BlazorWebView webView) => _webView = w...
method SpiceBlazorWebViewClient (line 29) | protected SpiceBlazorWebViewClient(IntPtr javaReference, JniHandleOwne...
method ShouldOverrideUrlLoading (line 36) | public override bool ShouldOverrideUrlLoading(AWebView? view, IWebReso...
method ShouldOverrideUrlLoadingCore (line 41) | private bool ShouldOverrideUrlLoadingCore(IWebResourceRequest? request)
method ShouldInterceptRequest (line 72) | public override WebResourceResponse? ShouldInterceptRequest(AWebView? ...
method OnPageFinished (line 94) | public override void OnPageFinished(AWebView? view, string? url)
method RunBlazorStartupScripts (line 106) | private void RunBlazorStartupScripts(AWebView view)
class JavaScriptValueCallback (line 173) | private class JavaScriptValueCallback : Java.Lang.Object, IValueCallback
method JavaScriptValueCallback (line 177) | public JavaScriptValueCallback(Action<Java.Lang.Object?> callback)
method OnReceiveValue (line 183) | public void OnReceiveValue(Java.Lang.Object? value)
FILE: src/Spice/Platforms/Android/Blazor/SpiceDispatcher.cs
class SpiceDispatcher (line 7) | internal partial class SpiceDispatcher : Dispatcher
method SpiceDispatcher (line 12) | public SpiceDispatcher()
method CheckAccess (line 18) | public override bool CheckAccess() => _looper == Looper.MyLooper();
method InvokeAsync (line 20) | public override Task InvokeAsync(Action workItem)
method InvokeAsync (line 40) | public override Task InvokeAsync(Func<Task> workItem)
method InvokeAsync (line 60) | public override Task<TResult> InvokeAsync<TResult>(Func<TResult> workI...
method InvokeAsync (line 79) | public override Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>>...
FILE: src/Spice/Platforms/Android/Border.cs
class Border (line 7) | public partial class Border
method Create (line 15) | static Android.Widget.FrameLayout Create(Context context) => new(conte...
method Border (line 21) | public Border() : base(Platform.Context, Create)
method Border (line 30) | public Border(Context context) : base(context, Create)
method Border (line 40) | protected Border(Context context, Func<Context, Android.Views.View> cr...
method GetOrCreateBorderDrawable (line 54) | GradientDrawable GetOrCreateBorderDrawable()
method OnContentChanged (line 68) | partial void OnContentChanged(View? oldValue, View? newValue)
method OnStrokeChanged (line 82) | partial void OnStrokeChanged(Color? value)
method OnStrokeThicknessChanged (line 95) | partial void OnStrokeThicknessChanged(double value)
method OnCornerRadiusChanged (line 109) | partial void OnCornerRadiusChanged(double value)
method OnPaddingChanged (line 115) | partial void OnPaddingChanged(double value)
method UpdateContentPadding (line 120) | void UpdateContentPadding()
method OnPropertyChanged (line 126) | void OnPropertyChanged(object? sender, System.ComponentModel.PropertyC...
FILE: src/Spice/Platforms/Android/BoxView.cs
class BoxView (line 5) | public partial class BoxView
method Create (line 13) | static Android.Views.View Create(Context context) => new(context);
method BoxView (line 20) | public BoxView() : base(Platform.Context, Create) { }
method BoxView (line 24) | public BoxView(Context context) : base(context, Create) { }
method BoxView (line 28) | protected BoxView(Func<Context, Android.Views.View> creator) : base(Pl...
method BoxView (line 33) | protected BoxView(Context context, Func<Context, Android.Views.View> c...
method OnColorChanged (line 40) | partial void OnColorChanged(Color? value) => NativeView.SetBackgroundC...
FILE: src/Spice/Platforms/Android/Button.cs
class Button (line 5) | public partial class Button
method Create (line 13) | static Android.Widget.Button Create(Context context) => new(context);
method Button (line 20) | public Button() : this(Platform.Context, Create) { }
method Button (line 24) | public Button(Context context) : this(context, Create) { }
method Button (line 28) | protected Button(Func<Context, Android.Views.View> creator) : this(Pla...
method Button (line 33) | protected Button(Context context, Func<Context, Android.Views.View> cr...
method OnTextChanged (line 40) | partial void OnTextChanged(string value) => NativeView.Text = value;
method OnTextColorChanged (line 42) | partial void OnTextColorChanged(Color? value)
method OnClickedChanged (line 50) | partial void OnClickedChanged(Action<Button>? value)
FILE: src/Spice/Platforms/Android/CheckBox.cs
class CheckBox (line 7) | public partial class CheckBox
method Create (line 15) | static AndroidCheckBox Create(Context context) => new(context);
method CheckBox (line 22) | public CheckBox() : this(Platform.Context, Create) { }
method CheckBox (line 26) | public CheckBox(Context context) : this(context, Create) { }
method CheckBox (line 30) | protected CheckBox(Func<Context, Android.Views.View> creator) : this(P...
method CheckBox (line 35) | protected CheckBox(Context context, Func<Context, Android.Views.View> ...
method OnIsCheckedChanged (line 48) | partial void OnIsCheckedChanged(bool value)
method OnCheckedChange (line 58) | void OnCheckedChange(object? sender, CompoundButton.CheckedChangeEvent...
method OnCheckedChangedChanged (line 69) | partial void OnCheckedChangedChanged(Action<CheckBox>? value)
FILE: src/Spice/Platforms/Android/CollectionView.cs
class CollectionView (line 9) | public partial class CollectionView
method Create (line 17) | static RecyclerView Create(Context context) => new(context);
method CollectionView (line 24) | public CollectionView() : this(Platform.Context, Create) { }
method CollectionView (line 28) | public CollectionView(Context context) : this(context, Create) { }
method CollectionView (line 32) | protected CollectionView(Func<Context, Android.Views.View> creator) : ...
method CollectionView (line 37) | protected CollectionView(Context context, Func<Context, Android.Views....
method OnItemsSourceChanged (line 52) | partial void OnItemsSourceChanged(IEnumerable? value)
method OnItemTemplateChanged (line 71) | partial void OnItemTemplateChanged(Func<object, View>? value)
method OnOrientationChanged (line 76) | partial void OnOrientationChanged(Orientation value)
method OnSelectionModeChanged (line 92) | partial void OnSelectionModeChanged(SelectionMode value)
method OnSelectedItemChanged (line 98) | partial void OnSelectedItemChanged(object? value)
method OnItemSpacingChanged (line 106) | partial void OnItemSpacingChanged(double value)
method OnCollectionChanged (line 124) | void OnCollectionChanged(object? sender, NotifyCollectionChangedEventA...
method RefreshData (line 129) | void RefreshData()
class SpiceRecyclerViewAdapter (line 146) | class SpiceRecyclerViewAdapter : RecyclerView.Adapter
method SpiceRecyclerViewAdapter (line 151) | public SpiceRecyclerViewAdapter(CollectionView parent)
method UpdateItems (line 157) | public void UpdateItems(CollectionView parent)
method OnBindViewHolder (line 171) | public override void OnBindViewHolder(RecyclerView.ViewHolder holder...
method OnCreateViewHolder (line 198) | public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup...
class SpiceViewHolder (line 212) | class SpiceViewHolder : RecyclerView.ViewHolder
method SpiceViewHolder (line 218) | public SpiceViewHolder(Android.Widget.FrameLayout container, WeakRef...
method OnItemClick (line 227) | void OnItemClick(object? sender, EventArgs e)
method Dispose (line 254) | protected override void Dispose(bool disposing)
class SpaceItemDecoration (line 264) | class SpaceItemDecoration : RecyclerView.ItemDecoration
method SpaceItemDecoration (line 268) | public SpaceItemDecoration(int space)
method GetItemOffsets (line 273) | public override void GetItemOffsets(Android.Graphics.Rect outRect, A...
FILE: src/Spice/Platforms/Android/ContentView.cs
class ContentView (line 5) | public partial class ContentView
method Create (line 13) | static FrameLayout Create(Context context) => new(context);
method ContentView (line 20) | public ContentView() : this(Platform.Context, Create) { }
method ContentView (line 24) | public ContentView(Context context) : this(context, Create) { }
method ContentView (line 28) | protected ContentView(Func<Context, Android.Views.View> creator) : thi...
method ContentView (line 33) | protected ContentView(Context context, Func<Context, Android.Views.Vie...
method OnContentChanged (line 40) | partial void OnContentChanged(View? oldContent, View? newContent)
method OnPaddingChanged (line 55) | partial void OnPaddingChanged(double value)
FILE: src/Spice/Platforms/Android/DatePicker.cs
class DatePicker (line 7) | public partial class DatePicker
method Create (line 15) | static Android.Widget.Button Create(Context context) => new(context);
method DatePicker (line 22) | public DatePicker() : this(Platform.Context, Create) { }
method DatePicker (line 26) | public DatePicker(Context context) : this(context, Create) { }
method DatePicker (line 30) | protected DatePicker(Func<Context, Android.Views.View> creator) : this...
method DatePicker (line 35) | protected DatePicker(Context context, Func<Context, Android.Views.View...
method OnClick (line 46) | void OnClick(object? sender, EventArgs e)
method UpdateText (line 77) | void UpdateText()
method OnDateChanged (line 82) | partial void OnDateChanged(DateTime value)
method OnMinimumDateChanged (line 87) | partial void OnMinimumDateChanged(DateTime? value)
method OnMaximumDateChanged (line 92) | partial void OnMaximumDateChanged(DateTime? value)
method OnTextColorChanged (line 97) | partial void OnTextColorChanged(Color? value)
FILE: src/Spice/Platforms/Android/Editor.cs
class Editor (line 6) | public partial class Editor
method Create (line 14) | static EditText Create(Context context)
method Editor (line 27) | public Editor() : base(Platform.Context, Create)
method Editor (line 34) | public Editor(Context context) : base(context, Create)
method Editor (line 41) | protected Editor(Func<Context, Android.Views.View> creator) : base(Pla...
method Editor (line 46) | protected Editor(Context context, Func<Context, Android.Views.View> cr...
method OnTextChanged (line 53) | partial void OnTextChanged(string value)
method OnTextColorChanged (line 59) | partial void OnTextColorChanged(Color? value)
method OnPlaceholderChanged (line 68) | partial void OnPlaceholderChanged(string? value) => NativeView.Hint = ...
method OnPlaceholderColorChanged (line 70) | partial void OnPlaceholderColorChanged(Color? value)
method OnAutoSizeChanged (line 81) | partial void OnAutoSizeChanged(bool value)
method EnsureTextWatcher (line 89) | void EnsureTextWatcher()
class EditorTextWatcher (line 98) | class EditorTextWatcher : Java.Lang.Object, ITextWatcher
method EditorTextWatcher (line 102) | public EditorTextWatcher(Editor editor)
method AfterTextChanged (line 107) | public void AfterTextChanged(IEditable? s)
method BeforeTextChanged (line 115) | public void BeforeTextChanged(Java.Lang.ICharSequence? s, int start,...
method OnTextChanged (line 117) | public void OnTextChanged(Java.Lang.ICharSequence? s, int start, int...
FILE: src/Spice/Platforms/Android/Entry.cs
class Entry (line 6) | public partial class Entry
method Create (line 14) | static EditText Create(Context context) => new(context);
method Entry (line 21) | public Entry() : base(Platform.Context, Create) { }
method Entry (line 25) | public Entry(Context context) : base(context, Create) { }
method Entry (line 29) | protected Entry(Func<Context, Android.Views.View> creator) : base(Plat...
method Entry (line 34) | protected Entry(Context context, Func<Context, Android.Views.View> cre...
method OnTextChanged (line 41) | partial void OnTextChanged(string value) => NativeView.Text = value;
method OnTextColorChanged (line 43) | partial void OnTextColorChanged(Color? value)
method OnIsPasswordChanged (line 52) | partial void OnIsPasswordChanged(bool value) =>
FILE: src/Spice/Platforms/Android/Grid.cs
class Grid (line 7) | public partial class Grid
method Create (line 15) | static GridLayout Create(Context context) => new(context);
method Grid (line 21) | public Grid() : this(Platform.Context, Create)
method Grid (line 32) | public Grid(Context context) : this(context, Create)
method Grid (line 43) | protected Grid(Func<Context, Android.Views.View> creator) : this(Platf...
method Grid (line 48) | protected Grid(Context context, Func<Context, Android.Views.View> crea...
method OnRowSpacingChanged (line 55) | partial void OnRowSpacingChanged(double value)
method OnColumnSpacingChanged (line 62) | partial void OnColumnSpacingChanged(double value)
method OnPaddingChanged (line 69) | partial void OnPaddingChanged(double value)
method OnDefinitionsChanged (line 75) | void OnDefinitionsChanged(object? sender, NotifyCollectionChangedEvent...
method OnGridChildrenChanged (line 82) | void OnGridChildrenChanged(object? sender, NotifyCollectionChangedEven...
method ConfigureGridChild (line 93) | void ConfigureGridChild(View view)
method CreateGridLayoutParams (line 119) | GridLayout.LayoutParams CreateGridLayoutParams(int row, int column, in...
method UpdateChildMargins (line 185) | void UpdateChildMargins()
method UpdateLayout (line 224) | void UpdateLayout()
FILE: src/Spice/Platforms/Android/Image.cs
class Image (line 5) | public partial class Image
method Create (line 13) | static ImageView Create(Context context) => new(context);
method Image (line 20) | public Image() : this(Platform.Context, Create) { }
method Image (line 24) | public Image(Context context) : this(context, Create) { }
method Image (line 28) | protected Image(Func<Context, Android.Views.View> creator) : this(Plat...
method Image (line 33) | protected Image(Context context, Func<Context, Android.Views.View> cre...
method OnSourceChanged (line 40) | partial void OnSourceChanged(string value) => Interop.SetImage(NativeV...
FILE: src/Spice/Platforms/Android/ImageButton.cs
class ImageButton (line 5) | public partial class ImageButton
method Create (line 13) | static Android.Widget.ImageButton Create(Context context) => new(conte...
method ImageButton (line 20) | public ImageButton() : this(Platform.Context, Create) { }
method ImageButton (line 24) | public ImageButton(Context context) : this(context, Create) { }
method ImageButton (line 28) | protected ImageButton(Func<Context, Android.Views.View> creator) : thi...
method ImageButton (line 33) | protected ImageButton(Context context, Func<Context, Android.Views.Vie...
method OnSourceChanged (line 40) | partial void OnSourceChanged(string value)
method OnClickedChanged (line 50) | partial void OnClickedChanged(Action<ImageButton>? value)
FILE: src/Spice/Platforms/Android/Interop.java
class Interop (line 7) | public class Interop {
method setImage (line 8) | public static void setImage(ImageView image, String value)
method getDefaultColorStateList (line 18) | public static ColorStateList getDefaultColorStateList(int color)
method getEditTextColorStateList (line 24) | public static ColorStateList getEditTextColorStateList(int enabled, in...
class ColorStates (line 29) | private static class ColorStates
method getEditTextState (line 36) | static int[][] getEditTextState()
FILE: src/Spice/Platforms/Android/Label.cs
class Label (line 5) | public partial class Label
method Create (line 13) | static TextView Create(Context context) => new(context);
method Label (line 20) | public Label() : base(Platform.Context, Create) { }
method Label (line 24) | public Label(Context context) : base(context, Create) { }
method Label (line 28) | protected Label(Func<Context, Android.Views.View> creator) : base(Plat...
method Label (line 33) | protected Label(Context context, Func<Context, Android.Views.View> cre...
method OnTextChanged (line 40) | partial void OnTextChanged(string value) => NativeView.Text = value;
method OnTextColorChanged (line 42) | partial void OnTextColorChanged(Color? value)
FILE: src/Spice/Platforms/Android/NavigationView.cs
class NavigationView (line 7) | public partial class NavigationView
method NavigationView (line 12) | public NavigationView() : this(Platform.Context) { }
method NavigationView (line 18) | public NavigationView(Context context) : base(context, ctx => new Andr...
method PushCore (line 79) | partial void PushCore(View view)
method PopCore (line 105) | partial void PopCore()
method PopToRootCore (line 130) | partial void PopToRootCore()
method GetBackIcon (line 150) | Android.Graphics.Drawables.Drawable? GetBackIcon()
FILE: src/Spice/Platforms/Android/Picker.cs
class Picker (line 8) | public partial class Picker
method Create (line 16) | static Spinner Create(Context context) => new(context);
method Picker (line 23) | public Picker() : base(Platform.Context, Create)
method Picker (line 30) | public Picker(Context context) : base(context, Create)
method Picker (line 37) | protected Picker(Func<Context, Android.Views.View> creator) : base(Pla...
method Picker (line 45) | protected Picker(Context context, Func<Context, Android.Views.View> cr...
method SetupAdapter (line 55) | void SetupAdapter()
method OnItemSelected (line 67) | void OnItemSelected(object? sender, AdapterView.ItemSelectedEventArgs e)
method OnItemsCollectionChanged (line 75) | void OnItemsCollectionChanged(object? sender, NotifyCollectionChangedE...
method OnItemsChanged (line 80) | partial void OnItemsChanged(ObservableCollection<string>? oldValue, Ob...
method RefreshAdapter (line 89) | void RefreshAdapter()
method OnSelectedIndexChanged (line 107) | partial void OnSelectedIndexChanged(int value)
method OnTitleChanged (line 115) | partial void OnTitleChanged(string value)
method OnTextColorChanged (line 120) | partial void OnTextColorChanged(Color? value)
FILE: src/Spice/Platforms/Android/Platform.cs
class Platform (line 5) | class Platform
FILE: src/Spice/Platforms/Android/PlatformAppearance.cs
class PlatformAppearance (line 5) | public static partial class PlatformAppearance
FILE: src/Spice/Platforms/Android/PlatformExtensions.cs
class PlatformExtensions (line 6) | public static class PlatformExtensions
method ToPixels (line 15) | public static int ToPixels(this int value) => (int)Math.Round(value * ...
method ToPixels (line 22) | public static int ToPixels(this double value) => (int)Math.Round(value...
method ToAndroidInt (line 29) | public static int ToAndroidInt(this Color? color) => color.ToAndroidCo...
method ToAndroidColor (line 36) | public static Android.Graphics.Color ToAndroidColor(this Color? color)
FILE: src/Spice/Platforms/Android/ProgressBar.cs
class ProgressBar (line 6) | public partial class ProgressBar
method Create (line 14) | static AndroidProgressBar Create(Context context)
method ProgressBar (line 28) | public ProgressBar() : base(Platform.Context, Create) { }
method ProgressBar (line 32) | public ProgressBar(Context context) : base(context, Create) { }
method ProgressBar (line 36) | protected ProgressBar(Func<Context, Android.Views.View> creator) : bas...
method ProgressBar (line 41) | protected ProgressBar(Context context, Func<Context, Android.Views.Vie...
method OnProgressChanged (line 48) | partial void OnProgressChanged(double value)
FILE: src/Spice/Platforms/Android/RadioButton.cs
class RadioButton (line 7) | public partial class RadioButton
method Create (line 15) | static AndroidRadioButton Create(Context context) => new(context);
method RadioButton (line 22) | public RadioButton() : this(Platform.Context, Create) { }
method RadioButton (line 26) | public RadioButton(Context context) : this(context, Create) { }
method RadioButton (line 30) | protected RadioButton(Func<Context, Android.Views.View> creator) : thi...
method RadioButton (line 35) | protected RadioButton(Context context, Func<Context, Android.Views.Vie...
method OnIsCheckedChangedPartial (line 48) | partial void OnIsCheckedChangedPartial(bool value)
method OnContentChanged (line 60) | partial void OnContentChanged(string? value)
method OnCheckedChange (line 65) | void OnCheckedChange(object? sender, CompoundButton.CheckedChangeEvent...
method OnCheckedChangedChanged (line 93) | partial void OnCheckedChangedChanged(Action<RadioButton>? value)
FILE: src/Spice/Platforms/Android/RefreshView.cs
class RefreshView (line 6) | public partial class RefreshView
method Create (line 14) | static SwipeRefreshLayout Create(Context context)
method RefreshView (line 26) | public RefreshView() : this(Platform.Context, Create) { }
method RefreshView (line 30) | public RefreshView(Context context) : this(context, Create) { }
method RefreshView (line 34) | protected RefreshView(Func<Context, Android.Views.View> creator) : thi...
method RefreshView (line 39) | protected RefreshView(Context context, Func<Context, Android.Views.Vie...
method OnRefresh (line 50) | void OnRefresh(object? sender, EventArgs e)
method OnContentChanged (line 63) | partial void OnContentChanged(View? oldContent, View? newContent)
method OnIsRefreshingChanged (line 78) | partial void OnIsRefreshingChanged(bool value)
method OnRefreshColorChanged (line 83) | partial void OnRefreshColorChanged(Color? value)
method OnPaddingChanged (line 91) | partial void OnPaddingChanged(double value)
FILE: src/Spice/Platforms/Android/ScrollView.cs
class ScrollView (line 5) | public partial class ScrollView
method CreateVertical (line 13) | static Android.Views.View CreateVertical(Context context) => new Andro...
method CreateHorizontal (line 15) | static Android.Views.View CreateHorizontal(Context context) => new Hor...
method GetCreator (line 17) | static Func<Context, Android.Views.View> GetCreator(Orientation orient...
method ScrollView (line 25) | public ScrollView() : this(Platform.Context, Orientation.Vertical) { }
method ScrollView (line 29) | public ScrollView(Orientation orientation) : this(Platform.Context, or...
method ScrollView (line 33) | public ScrollView(Context context) : this(context, Orientation.Vertica...
method ScrollView (line 38) | protected ScrollView(Context context, Orientation orientation) : base(...
method ScrollView (line 45) | protected ScrollView(Func<Context, Android.Views.View> creator) : this...
method ScrollView (line 50) | protected ScrollView(Context context, Func<Context, Android.Views.View...
method OnOrientationChanging (line 57) | partial void OnOrientationChanging(Orientation value)
method OnPaddingChanged (line 66) | partial void OnPaddingChanged(double value)
FILE: src/Spice/Platforms/Android/SearchBar.cs
class SearchBar (line 5) | public partial class SearchBar
method Create (line 13) | static SearchView Create(Context context) => new(context) { Iconified ...
method SearchBar (line 20) | public SearchBar() : base(Platform.Context, Create) { }
method SearchBar (line 24) | public SearchBar(Context context) : base(context, Create) { }
method SearchBar (line 28) | protected SearchBar(Func<Context, Android.Views.View> creator) : base(...
method SearchBar (line 33) | protected SearchBar(Context context, Func<Context, Android.Views.View>...
method OnTextChanged (line 40) | partial void OnTextChanged(string value)
method OnPlaceholderChanged (line 46) | partial void OnPlaceholderChanged(string? value) => NativeView.SetQuer...
method OnTextColorChanged (line 48) | partial void OnTextColorChanged(Color? value)
method OnPlaceholderColorChanged (line 63) | partial void OnPlaceholderColorChanged(Color? value)
method UpdateQueryTextListener (line 82) | void UpdateQueryTextListener()
method OnSearchButtonPressedChanged (line 99) | partial void OnSearchButtonPressedChanged(Action<SearchBar>? value) =>...
method OnTextChangedChanged (line 101) | partial void OnTextChangedChanged(Action<SearchBar>? value) => UpdateQ...
class QueryTextListener (line 103) | class QueryTextListener : Java.Lang.Object, SearchView.IOnQueryTextLis...
method QueryTextListener (line 107) | public QueryTextListener(SearchBar searchBar)
method OnQueryTextSubmit (line 112) | public bool OnQueryTextSubmit(string? query)
method OnQueryTextChange (line 122) | public bool OnQueryTextChange(string? newText)
FILE: src/Spice/Platforms/Android/Slider.cs
class Slider (line 6) | public partial class Slider
method Create (line 14) | static SeekBar Create(Context context) => new(context);
method Slider (line 21) | public Slider() : this(Platform.Context, Create) { }
method Slider (line 25) | public Slider(Context context) : this(context, Create) { }
method Slider (line 29) | protected Slider(Func<Context, Android.Views.View> creator) : this(Pla...
method Slider (line 34) | protected Slider(Context context, Func<Context, Android.Views.View> cr...
method OnMinimumChanged (line 41) | partial void OnMinimumChanged(double value)
method OnMaximumChanged (line 48) | partial void OnMaximumChanged(double value)
method OnValueChanged (line 55) | partial void OnValueChanged(double value)
method OnValueChangedChanged (line 66) | partial void OnValueChangedChanged(Action<Slider>? value)
class SeekBarChangeListener (line 83) | class SeekBarChangeListener : Java.Lang.Object, SeekBar.IOnSeekBarChan...
method SeekBarChangeListener (line 87) | public SeekBarChangeListener(Slider slider)
method OnProgressChanged (line 92) | public void OnProgressChanged(SeekBar? seekBar, int progress, bool f...
method OnStartTrackingTouch (line 98) | public void OnStartTrackingTouch(SeekBar? seekBar) { }
method OnStopTrackingTouch (line 100) | public void OnStopTrackingTouch(SeekBar? seekBar) { }
FILE: src/Spice/Platforms/Android/SpiceActivity.cs
class SpiceActivity (line 10) | public class SpiceActivity : AppCompatActivity
method OnCreate (line 18) | protected override void OnCreate(Bundle? savedInstanceState)
method SetContentView (line 32) | public void SetContentView(View view)
method OnConfigurationChanged (line 39) | public override void OnConfigurationChanged(Configuration newConfig)
method OnDestroy (line 48) | protected override void OnDestroy()
FILE: src/Spice/Platforms/Android/StackLayout.cs
class StackLayout (line 5) | public partial class StackLayout
method Create (line 13) | static LinearLayout Create(Context context)
method StackLayout (line 28) | public StackLayout() : this(Platform.Context, Create) { }
method StackLayout (line 32) | public StackLayout(Context context) : this(context, Create) { }
method StackLayout (line 36) | protected StackLayout(Func<Context, Android.Views.View> creator) : thi...
method StackLayout (line 41) | protected StackLayout(Context context, Func<Context, Android.Views.Vie...
method OnOrientationChanging (line 48) | partial void OnOrientationChanging(Orientation value)
method OnSpacingChanged (line 63) | partial void OnSpacingChanged(double value) => NativeView.DividerPaddi...
method OnPaddingChanged (line 65) | partial void OnPaddingChanged(double value)
FILE: src/Spice/Platforms/Android/SwipeView.cs
class SwipeView (line 7) | public partial class SwipeView
method Create (line 15) | static FrameLayout Create(Context context) => new(context);
method SwipeView (line 22) | public SwipeView() : this(Platform.Context, Create) { }
method SwipeView (line 26) | public SwipeView(Context context) : this(context, Create) { }
method SwipeView (line 30) | protected SwipeView(Func<Context, Android.Views.View> creator) : this(...
method SwipeView (line 35) | protected SwipeView(Context context, Func<Context, Android.Views.View>...
method SetupGestureDetector (line 52) | void SetupGestureDetector()
class SwipeGestureListener (line 68) | class SwipeGestureListener : GestureDetector.SimpleOnGestureListener
method SwipeGestureListener (line 72) | public SwipeGestureListener(SwipeView swipeView)
method OnDown (line 77) | public override bool OnDown(MotionEvent? e)
method OnScroll (line 88) | public override bool OnScroll(MotionEvent? e1, MotionEvent? e2, floa...
method HandleTouchEnd (line 125) | void HandleTouchEnd(MotionEvent? e)
method ShowSwipeItems (line 152) | void ShowSwipeItems(SwipeItems items, SwipeDirection direction)
method ResetPosition (line 224) | void ResetPosition()
method OnContentChanged (line 241) | partial void OnContentChanged(View? oldContent, View? newContent)
method OnOpen (line 266) | partial void OnOpen(SwipeDirection direction)
method OnClose (line 283) | partial void OnClose()
FILE: src/Spice/Platforms/Android/Switch.cs
class Switch (line 6) | public partial class Switch
method Create (line 14) | static SwitchCompat Create(Context context) => new(context);
method Switch (line 21) | public Switch() : this(Platform.Context, Create) { }
method Switch (line 25) | public Switch(Context context) : this(context, Create) { }
method Switch (line 29) | protected Switch(Func<Context, Android.Views.View> creator) : this(Pla...
method Switch (line 34) | protected Switch(Context context, Func<Context, Android.Views.View> cr...
method OnIsOnChanged (line 43) | partial void OnIsOnChanged(bool value)
method OnToggledChanged (line 52) | partial void OnToggledChanged(Action<Switch>? value)
FILE: src/Spice/Platforms/Android/TabView.cs
class TabView (line 8) | public partial class TabView
method TabView (line 13) | public TabView() : this(Platform.Context) { }
method TabView (line 19) | public TabView(Context context) : base(context, ctx => new AndroidX.Ap...
method OnTabsChanged (line 83) | void OnTabsChanged(object? sender, NotifyCollectionChangedEventArgs e)
method UpdateTabs (line 88) | void UpdateTabs()
method OnNavigationItemSelected (line 127) | void OnNavigationItemSelected(object? sender, Google.Android.Material....
method ShowTab (line 133) | void ShowTab(int index)
class Tab (line 158) | public partial class Tab
method Tab (line 163) | public Tab() : this(Platform.Context) { }
method Tab (line 169) | public Tab(Context context) : base(context, ctx => new Android.Widget....
FILE: src/Spice/Platforms/Android/TimePicker.cs
class TimePicker (line 8) | public partial class TimePicker
method Create (line 16) | static AndroidButton Create(Context context) => new(context);
method TimePicker (line 23) | public TimePicker() : base(Platform.Context, Create)
method TimePicker (line 31) | public TimePicker(Context context) : base(context, Create)
method TimePicker (line 39) | protected TimePicker(Func<Context, Android.Views.View> creator) : base...
method TimePicker (line 44) | protected TimePicker(Context context, Func<Context, Android.Views.View...
method OnTimeChanged (line 51) | partial void OnTimeChanged(TimeOnly value)
method OnNativeClick (line 56) | void OnNativeClick(object? sender, EventArgs e)
method OnTimeSet (line 72) | void OnTimeSet(object? sender, TimePickerDialog.TimeSetEventArgs e)
method UpdateButtonText (line 77) | void UpdateButtonText()
FILE: src/Spice/Platforms/Android/View.cs
class View (line 6) | public partial class View
method Create (line 14) | static RelativeLayout Create(Context context) => new(context);
method View (line 19) | public View() : this(Platform.Context, Create) { }
method View (line 25) | public View(Context context) : this(context, Create) { }
method View (line 31) | protected View(Func<Context, Android.Views.View> creator) : this(Platf...
method View (line 38) | protected View(Context context, Func<Context, Android.Views.View> crea...
method CreateLayoutParameters (line 64) | protected virtual Android.Views.ViewGroup.LayoutParams CreateLayoutPar...
method OnChildrenChanged (line 77) | void OnChildrenChanged(object? sender, NotifyCollectionChangedEventArg...
method OnHorizontalOptionsChanged (line 96) | partial void OnHorizontalOptionsChanged(LayoutOptions value)
method OnVerticalOptionsChanged (line 131) | partial void OnVerticalOptionsChanged(LayoutOptions value)
method OnBackgroundColorChanged (line 168) | partial void OnBackgroundColorChanged(Color? value) => _nativeView.Val...
method OnIsVisibleChanged (line 170) | partial void OnIsVisibleChanged(bool value) => _nativeView.Value.Visib...
method OnIsEnabledChanged (line 172) | partial void OnIsEnabledChanged(bool value) => _nativeView.Value.Enabl...
method OnOpacityChanged (line 174) | partial void OnOpacityChanged(double value) => _nativeView.Value.Alpha...
method OnAutomationIdChanged (line 176) | partial void OnAutomationIdChanged(string? value) => _nativeView.Value...
method OnMarginChanged (line 178) | partial void OnMarginChanged(Thickness value)
method OnWidthRequestChanged (line 195) | partial void OnWidthRequestChanged(double value)
method OnHeightRequestChanged (line 213) | partial void OnHeightRequestChanged(double value)
method GetWidthInPixels (line 231) | int GetWidthInPixels()
method GetHeightInPixels (line 237) | int GetHeightInPixels()
method GetWidth (line 243) | private partial double GetWidth()
method GetHeight (line 255) | private partial double GetHeight()
method PresentAsyncCore (line 269) | private partial Task PresentAsyncCore(View view)
method DismissAsyncCore (line 283) | private partial Task DismissAsyncCore()
class SpiceModalFragment (line 294) | class SpiceModalFragment : AndroidX.Fragment.App.DialogFragment
method SpiceModalFragment (line 298) | public SpiceModalFragment(View spiceView)
method OnCreateView (line 303) | public override Android.Views.View OnCreateView(Android.Views.Layout...
method OnStart (line 315) | public override void OnStart()
FILE: src/Spice/Platforms/Android/WebView.cs
class WebView (line 8) | public partial class WebView
method Create (line 16) | internal static Android.Webkit.WebView Create(Context context)
method WebView (line 31) | public WebView() : this(Platform.Context, Create) { }
method WebView (line 35) | public WebView(Context context) : this(context, Create) { }
method WebView (line 39) | protected WebView(Func<Context, Android.Views.View> creator) : this(Pl...
method WebView (line 44) | protected WebView(Context context, Func<Context, Android.Views.View> c...
method Initialize (line 47) | void Initialize()
method SetClients (line 59) | protected virtual void SetClients()
method OnSourceChanged (line 71) | partial void OnSourceChanged(string value) => NativeView.LoadUrl(value);
method OnIsJavaScriptEnabledChanged (line 73) | partial void OnIsJavaScriptEnabledChanged(bool value) => NativeView.Se...
method Back (line 83) | public void Back()
method Forward (line 97) | public void Forward()
class SpiceWebViewClient (line 103) | internal class SpiceWebViewClient : WebViewClient
method SpiceWebViewClient (line 105) | public SpiceWebViewClient() { }
method SpiceWebViewClient (line 107) | protected SpiceWebViewClient(nint javaReference, JniHandleOwnership ...
method ShouldOverrideUrlLoading (line 109) | public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView...
class SpiceWebChromeClient (line 118) | internal class SpiceWebChromeClient : WebChromeClient
method SpiceWebChromeClient (line 120) | public SpiceWebChromeClient() { }
method SpiceWebChromeClient (line 122) | protected SpiceWebChromeClient(nint javaReference, JniHandleOwnershi...
method OnCreateWindow (line 125) | public override bool OnCreateWindow(Android.Webkit.WebView? view, bo...
FILE: src/Spice/Platforms/iOS/ActivityIndicator.cs
class ActivityIndicator (line 3) | public partial class ActivityIndicator
method ActivityIndicator (line 16) | public ActivityIndicator() : base(_ => new UIActivityIndicatorView { A...
method ActivityIndicator (line 20) | public ActivityIndicator(CGRect frame) : base(_ => new UIActivityIndic...
method ActivityIndicator (line 24) | protected ActivityIndicator(Func<View, UIView> creator) : base(creator...
method OnIsRunningChanged (line 31) | partial void OnIsRunningChanged(bool value)
method OnColorChanged (line 43) | partial void OnColorChanged(Color? value) => NativeView.Color = value....
FILE: src/Spice/Platforms/iOS/Application.cs
class Application (line 3) | public partial class Application
method Application (line 8) | public Application() : base(_ => new UIView(Platform.Window!.Frame) { ...
method Application (line 12) | public Application(CGRect frame) : base(_ => new UIView(frame) { Autor...
method OnMainChanging (line 16) | partial void OnMainChanging(View? value)
method OnMainChanged (line 26) | partial void OnMainChanged(View? value)
FILE: src/Spice/Platforms/iOS/Blazor/BlazorWebView.cs
class BlazorWebView (line 8) | public partial class BlazorWebView
method CreateConfiguration (line 43) | static new WKWebViewConfiguration CreateConfiguration()
method BlazorWebView (line 63) | public BlazorWebView() : this(_ => Create(CGRect.Empty, CreateConfigur...
method BlazorWebView (line 67) | public BlazorWebView(CGRect frame) : this(_ => Create(frame, CreateCon...
method BlazorWebView (line 71) | protected BlazorWebView(Func<View, UIView> creator) : base(creator)
method LoadNativeWebView (line 92) | partial void LoadNativeWebView(string contentRootDir, string hostPageR...
class WebViewScriptMessageHandler (line 109) | private class WebViewScriptMessageHandler : NSObject, IWKScriptMessage...
method WebViewScriptMessageHandler (line 113) | public WebViewScriptMessageHandler(SchemeHandler schemeHandler) => _...
method DidReceiveScriptMessage (line 115) | public void DidReceiveScriptMessage(WKUserContentController userCont...
class SchemeHandler (line 124) | private class SchemeHandler : NSObject, IWKUrlSchemeHandler
method StartUrlSchemeTask (line 134) | [Export("webView:startURLSchemeTask:")]
method GetResponseBytes (line 159) | byte[] GetResponseBytes(string? url, out string contentType, out int...
method StopUrlSchemeTask (line 183) | [Export("webView:stopURLSchemeTask:")]
FILE: src/Spice/Platforms/iOS/Blazor/SpiceDispatcher.cs
class SpiceDispatcher (line 10) | internal partial class SpiceDispatcher : Dispatcher
method SpiceDispatcher (line 14) | public SpiceDispatcher()
method CheckAccess (line 19) | public override bool CheckAccess() => DispatchQueue.CurrentQueueLabel ...
method InvokeAsync (line 21) | public override Task InvokeAsync(Action workItem)
method InvokeAsync (line 41) | public override Task InvokeAsync(Func<Task> workItem)
method InvokeAsync (line 61) | public override Task<TResult> InvokeAsync<TResult>(Func<TResult> workI...
method InvokeAsync (line 80) | public override Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>>...
FILE: src/Spice/Platforms/iOS/Blazor/iOSFileProvider.cs
class iOSFileProvider (line 12) | internal sealed class iOSFileProvider : IFileProvider
method iOSFileProvider (line 16) | public iOSFileProvider(string contentRootDir)
method GetDirectoryContents (line 21) | public IDirectoryContents GetDirectoryContents(string subpath)
method GetFileInfo (line 24) | public IFileInfo GetFileInfo(string subpath)
method Watch (line 27) | public IChangeToken Watch(string filter)
class iOSMauiAssetFileInfo (line 30) | private sealed class iOSMauiAssetFileInfo : IFileInfo
method iOSMauiAssetFileInfo (line 34) | public iOSMauiAssetFileInfo(string filePath)
method CreateReadStream (line 52) | public Stream CreateReadStream()
class iOSMauiAssetDirectoryContents (line 57) | private sealed class iOSMauiAssetDirectoryContents : IDirectoryContents
method iOSMauiAssetDirectoryContents (line 59) | public iOSMauiAssetDirectoryContents(string filePath)
method GetEnumerator (line 65) | public IEnumerator<IFileInfo> GetEnumerator()
method GetEnumerator (line 68) | IEnumerator IEnumerable.GetEnumerator()
FILE: src/Spice/Platforms/iOS/Blazor/iOSWebViewManager.cs
class iOSWebViewManager (line 22) | internal class iOSWebViewManager : WebViewManager
method iOSWebViewManager (line 38) | public iOSWebViewManager(WKWebView webview, IServiceProvider provider,...
method NavigateCore (line 50) | protected override void NavigateCore(Uri absoluteUri)
method TryGetResponseContentInternal (line 57) | internal bool TryGetResponseContentInternal(string uri, bool allowFall...
method SendMessage (line 67) | protected override void SendMessage(string message)
method MessageReceivedInternal (line 75) | internal void MessageReceivedInternal(Uri uri, string message)
method InitializeWebView (line 80) | private void InitializeWebView()
class WebViewUIDelegate (line 86) | internal sealed class WebViewUIDelegate : WKUIDelegate
method RunJavaScriptAlertPanel (line 91) | public override void RunJavaScriptAlertPanel(WKWebView webView, stri...
method RunJavaScriptConfirmPanel (line 100) | public override void RunJavaScriptConfirmPanel(WKWebView webView, st...
method RunJavaScriptTextInputPanelWithPrompt (line 113) | [Export("webView:runJavaScriptTextInputPanelWithPrompt:defaultText:i...
method GetJsAlertTitle (line 131) | private static string GetJsAlertTitle(WKWebView webView)
method AddOkAction (line 142) | private static UIAlertAction AddOkAction(UIAlertController controlle...
method AddCancelAction (line 150) | private static UIAlertAction AddCancelAction(UIAlertController contr...
method PresentAlertController (line 157) | private static void PresentAlertController(
method GetTopViewController (line 181) | private static UIViewController? GetTopViewController(UIViewControll...
class ActionStringTrampolineBlock (line 198) | sealed class ActionStringTrampolineBlock : TrampolineBlockBase
method ActionStringTrampolineBlock (line 206) | public unsafe ActionStringTrampolineBlock(BlockLiteral* block)
method Create (line 212) | [Preserve(Conditional = true)]
method Invoke (line 224) | void Invoke(string? obj)
class WebViewNavigationDelegate (line 233) | internal class WebViewNavigationDelegate : WKNavigationDelegate
method DidStartProvisionalNavigation (line 238) | public override void DidStartProvisionalNavigation(WKWebView webView...
method DecidePolicy (line 243) | public override void DecidePolicy(WKWebView webView, WKNavigationAct...
method DidReceiveServerRedirectForProvisionalNavigation (line 278) | public override void DidReceiveServerRedirectForProvisionalNavigatio...
method DidFailNavigation (line 295) | public override void DidFailNavigation(WKWebView webView, WKNavigati...
method DidFailProvisionalNavigation (line 301) | public override void DidFailProvisionalNavigation(WKWebView webView,...
method DidCommitNavigation (line 307) | public override void DidCommitNavigation(WKWebView webView, WKNaviga...
method DidFinishNavigation (line 316) | public override void DidFinishNavigation(WKWebView webView, WKNaviga...
FILE: src/Spice/Platforms/iOS/Border.cs
class Border (line 3) | public partial class Border
method Border (line 15) | public Border() : base(v => new UIView { AutoresizingMask = UIViewAuto...
method Border (line 19) | public Border(CGRect frame) : base(v => new UIView(frame) { Autoresizi...
method Border (line 23) | protected Border(Func<View, UIView> creator) : base(creator) { }
method OnContentChanged (line 27) | partial void OnContentChanged(View? oldValue, View? newValue)
method OnStrokeChanged (line 45) | partial void OnStrokeChanged(Color? value)
method OnStrokeThicknessChanged (line 59) | partial void OnStrokeThicknessChanged(double value)
method OnCornerRadiusChanged (line 64) | partial void OnCornerRadiusChanged(double value)
method OnPaddingChanged (line 70) | partial void OnPaddingChanged(double value)
method AddSubview (line 84) | protected override void AddSubview(View view)
FILE: src/Spice/Platforms/iOS/BoxView.cs
class BoxView (line 3) | public partial class BoxView
method BoxView (line 16) | public BoxView() : base(_ => new UIView { AutoresizingMask = UIViewAut...
method BoxView (line 20) | public BoxView(CGRect frame) : base(_ => new UIView(frame) { Autoresiz...
method BoxView (line 24) | protected BoxView(Func<View, UIView> creator) : base(creator) { }
method OnColorChanged (line 26) | partial void OnColorChanged(Color? value) => NativeView.BackgroundColo...
FILE: src/Spice/Platforms/iOS/Button.cs
class Button (line 3) | public partial class Button
method Button (line 16) | public Button() : base(_ => new UIButton { AutoresizingMask = UIViewAu...
method Button (line 20) | public Button(CGRect frame) : base(_ => new UIButton(frame) { Autoresi...
method Button (line 24) | protected Button(Func<View, UIView> creator) : base(creator) { }
method OnTextChanged (line 31) | partial void OnTextChanged(string value)
method OnTextColorChanged (line 40) | partial void OnTextColorChanged(Color? value) => NativeView.SetTitleCo...
method OnClickedChanged (line 44) | partial void OnClickedChanged(Action<Button>? value)
FILE: src/Spice/Platforms/iOS/CheckBox.cs
class CheckBox (line 3) | public partial class CheckBox
method CheckBox (line 16) | public CheckBox() : base(_ => new UIButton(UIButtonType.System) { Auto...
method CheckBox (line 23) | public CheckBox(CGRect frame) : base(_ =>
method CheckBox (line 38) | protected CheckBox(Func<View, UIView> creator) : base(creator)
method InitializeCheckBox (line 48) | void InitializeCheckBox()
method OnIsCheckedChanged (line 55) | partial void OnIsCheckedChanged(bool value)
method OnTouchUpInside (line 60) | void OnTouchUpInside(object? sender, EventArgs e)
method OnCheckedChangedChanged (line 66) | partial void OnCheckedChangedChanged(Action<CheckBox>? value)
FILE: src/Spice/Platforms/iOS/CollectionView.cs
class CollectionView (line 6) | public partial class CollectionView
method CollectionView (line 19) | public CollectionView() : base(v => new SpiceCollectionView((Collectio...
method CollectionView (line 23) | protected CollectionView(Func<View, UIView> creator) : base(creator) { }
method OnItemsSourceChanged (line 34) | partial void OnItemsSourceChanged(IEnumerable? value)
method OnItemTemplateChanged (line 53) | partial void OnItemTemplateChanged(Func<object, View>? value)
method OnOrientationChanged (line 58) | partial void OnOrientationChanged(Orientation value)
method OnSelectionModeChanged (line 71) | partial void OnSelectionModeChanged(SelectionMode value)
method OnSelectedItemChanged (line 80) | partial void OnSelectedItemChanged(object? value)
method OnItemSpacingChanged (line 109) | partial void OnItemSpacingChanged(double value)
method OnCollectionChanged (line 119) | void OnCollectionChanged(object? sender, NotifyCollectionChangedEventA...
method RefreshData (line 124) | void RefreshData()
class SpiceCollectionView (line 135) | class SpiceCollectionView : UICollectionView
method SpiceCollectionView (line 139) | public SpiceCollectionView(CollectionView parent) : base(CGRect.Empt...
class SpiceCollectionViewDataSource (line 158) | class SpiceCollectionViewDataSource : UICollectionViewDataSource
method SpiceCollectionViewDataSource (line 163) | public SpiceCollectionViewDataSource(CollectionView parent)
method UpdateItemsCache (line 169) | public void UpdateItemsCache(CollectionView parent)
method GetItemsCount (line 179) | public override nint GetItemsCount(UICollectionView collectionView, ...
method GetCell (line 184) | public override UICollectionViewCell GetCell(UICollectionView collec...
class SpiceCollectionViewDelegate (line 210) | class SpiceCollectionViewDelegate : UICollectionViewDelegateFlowLayout
method SpiceCollectionViewDelegate (line 214) | public SpiceCollectionViewDelegate(CollectionView parent)
method GetSizeForItem (line 219) | public override CGSize GetSizeForItem(UICollectionView collectionVie...
method ItemSelected (line 239) | public override void ItemSelected(UICollectionView collectionView, N...
class SpiceCollectionViewCell (line 258) | class SpiceCollectionViewCell : UICollectionViewCell
method SpiceCollectionViewCell (line 260) | public SpiceCollectionViewCell(IntPtr handle) : base(handle) { }
FILE: src/Spice/Platforms/iOS/ConstraintHelper.cs
class ConstraintHelper (line 7) | static class ConstraintHelper
method PinEdges (line 14) | public static NSLayoutConstraint[] PinEdges(UIView child, UIView paren...
method PinEdges (line 33) | public static NSLayoutConstraint[] PinEdges(UIView child, UIView paren...
method UpdateInsets (line 42) | public static void UpdateInsets(NSLayoutConstraint[] constraints, nflo...
method UpdateInsets (line 56) | public static void UpdateInsets(NSLayoutConstraint[] constraints, nflo...
method RemoveConstraints (line 64) | public static void RemoveConstraints(NSLayoutConstraint[]? constraints)
method ApplyAlignment (line 76) | public static NSLayoutConstraint[] ApplyAlignment(
FILE: src/Spice/Platforms/iOS/ContentView.cs
class ContentView (line 3) | public partial class ContentView
method ContentView (line 16) | public ContentView() : base(v => new UIView { AutoresizingMask = UIVie...
method ContentView (line 20) | public ContentView(CGRect frame) : base(v => new UIView(frame) { Autor...
method ContentView (line 24) | protected ContentView(Func<View, UIView> creator) : base(creator) { }
method OnContentChanged (line 28) | partial void OnContentChanged(View? oldContent, View? newContent)
method OnPaddingChanged (line 48) | partial void OnPaddingChanged(double value)
FILE: src/Spice/Platforms/iOS/DatePicker.cs
class DatePicker (line 3) | public partial class DatePicker
method DatePicker (line 16) | public DatePicker() : base(_ => new UIDatePicker
method DatePicker (line 28) | public DatePicker(CGRect frame) : base(_ => new UIDatePicker(frame)
method DatePicker (line 40) | protected DatePicker(Func<View, UIView> creator) : base(creator) { }
method OnValueChanged (line 47) | void OnValueChanged(object? sender, EventArgs e)
method OnDateChanged (line 52) | partial void OnDateChanged(DateTime value)
method OnMinimumDateChanged (line 68) | partial void OnMinimumDateChanged(DateTime? value)
method OnMaximumDateChanged (line 85) | partial void OnMaximumDateChanged(DateTime? value)
method OnTextColorChanged (line 102) | partial void OnTextColorChanged(Color? value)
FILE: src/Spice/Platforms/iOS/Editor.cs
class Editor (line 3) | public partial class Editor
method Editor (line 16) | public Editor() : base(_ => new UITextView { AutoresizingMask = UIView...
method Editor (line 23) | public Editor(CGRect frame) : base(_ => new UITextView(frame) { Autore...
method Editor (line 30) | protected Editor(Func<View, UIView> creator) : base(creator) { }
method OnTextChanged (line 37) | partial void OnTextChanged(string value)
method OnTextColorChanged (line 43) | partial void OnTextColorChanged(Color? value) => NativeView.TextColor ...
method OnPlaceholderChanged (line 45) | partial void OnPlaceholderChanged(string? value)
method OnPlaceholderColorChanged (line 50) | partial void OnPlaceholderColorChanged(Color? value)
method OnAutoSizeChanged (line 55) | partial void OnAutoSizeChanged(bool value)
method EnsureDelegate (line 63) | void EnsureDelegate()
class EditorDelegate (line 72) | class EditorDelegate : UITextViewDelegate
method EditorDelegate (line 76) | public EditorDelegate(Editor editor)
method Changed (line 81) | public override void Changed(UITextView textView)
FILE: src/Spice/Platforms/iOS/Entry.cs
class Entry (line 3) | public partial class Entry
method Entry (line 16) | public Entry() : base(_ => new UITextField { AutoresizingMask = UIView...
method Entry (line 20) | public Entry(CGRect frame) : base(_ => new UITextField(frame) { Autore...
method Entry (line 24) | protected Entry(Func<View, UIView> creator) : base(creator) { }
method OnTextChanged (line 31) | partial void OnTextChanged(string value) => NativeView.Text = value;
method OnTextColorChanged (line 33) | partial void OnTextColorChanged(Color? value) => NativeView.TextColor ...
method OnIsPasswordChanged (line 35) | partial void OnIsPasswordChanged(bool value) => NativeView.SecureTextE...
FILE: src/Spice/Platforms/iOS/Grid.cs
class Grid (line 5) | public partial class Grid
method Grid (line 17) | public Grid() : this(v => new SpiceGridView((Grid)v) { AutoresizingMas...
method Grid (line 25) | public Grid(CGRect frame) : this(v => new SpiceGridView((Grid)v, frame...
method Grid (line 33) | protected Grid(Func<View, UIView> creator) : base(creator) { }
method OnRowSpacingChanged (line 40) | partial void OnRowSpacingChanged(double value) => NativeView.Invalidat...
method OnColumnSpacingChanged (line 42) | partial void OnColumnSpacingChanged(double value) => NativeView.Invali...
method OnPaddingChanged (line 44) | partial void OnPaddingChanged(double value) => NativeView.InvalidateLa...
method OnDefinitionsChanged (line 46) | void OnDefinitionsChanged(object? sender, NotifyCollectionChangedEvent...
method AddSubview (line 52) | protected override void AddSubview(View view)
class SpiceGridView (line 61) | public class SpiceGridView : UIView
method SpiceGridView (line 68) | public SpiceGridView(Grid parent) => _parent = parent;
method SpiceGridView (line 73) | public SpiceGridView(Grid parent, CGRect frame) : base(frame) => _pa...
method InvalidateLayout (line 78) | public void InvalidateLayout()
method LayoutSubviews (line 84) | public override void LayoutSubviews()
FILE: src/Spice/Platforms/iOS/Image.cs
class Image (line 3) | public partial class Image
method Image (line 16) | public Image() : base(_ => new UIImageView { AutoresizingMask = UIView...
method Image (line 20) | public Image(CGRect frame) : base(_ => new UIImageView(frame) { Autore...
method Image (line 24) | protected Image(Func<View, UIView> creator) : base(creator) { }
method OnSourceChanged (line 31) | partial void OnSourceChanged(string value) => NativeView.Image = UIIma...
FILE: src/Spice/Platforms/iOS/ImageButton.cs
class ImageButton (line 3) | public partial class ImageButton
method ImageButton (line 16) | public ImageButton() : base(_ => new UIButton { AutoresizingMask = UIV...
method ImageButton (line 20) | public ImageButton(CGRect frame) : base(_ => new UIButton(frame) { Aut...
method ImageButton (line 24) | protected ImageButton(Func<View, UIView> creator) : base(creator) { }
method OnSourceChanged (line 31) | partial void OnSourceChanged(string value)
method OnClickedChanged (line 51) | partial void OnClickedChanged(Action<ImageButton>? value)
FILE: src/Spice/Platforms/iOS/Label.cs
class Label (line 3) | public partial class Label
method Label (line 16) | public Label() : base(_ => new UILabel { AutoresizingMask = UIViewAuto...
method Label (line 20) | public Label(CGRect frame) : base(_ => new UILabel(frame) { Autoresizi...
method Label (line 24) | protected Label(Func<View, UIView> creator) : base(creator) { }
method OnTextChanged (line 31) | partial void OnTextChanged(string value)
method OnTextColorChanged (line 40) | partial void OnTextColorChanged(Color? value) => NativeView.TextColor ...
FILE: src/Spice/Platforms/iOS/NavigationView.cs
class NavigationView (line 3) | public partial class NavigationView
method NavigationView (line 13) | public NavigationView() : base(_ => new UIView { AutoresizingMask = UI...
method PushCore (line 39) | partial void PushCore(View view)
method PopCore (line 55) | partial void PopCore()
method PopToRootCore (line 60) | partial void PopToRootCore()
FILE: src/Spice/Platforms/iOS/Picker.cs
class Picker (line 6) | public partial class Picker
method Picker (line 19) | public Picker() : base(_ => new UIPickerView { AutoresizingMask = UIVi...
method Picker (line 27) | public Picker(CGRect frame) : base(_ => new UIPickerView(frame) { Auto...
method Picker (line 35) | protected Picker(Func<View, UIView> creator) : base(creator)
method OnItemsChanged (line 46) | partial void OnItemsChanged(ObservableCollection<string>? oldValue, Ob...
method OnItemsCollectionChanged (line 55) | void OnItemsCollectionChanged(object? sender, NotifyCollectionChangedE...
method ReloadItems (line 60) | void ReloadItems()
method OnSelectedIndexChanged (line 78) | partial void OnSelectedIndexChanged(int value)
method OnTitleChanged (line 91) | partial void OnTitleChanged(string value)
method OnTextColorChanged (line 96) | partial void OnTextColorChanged(Color? value)
class PickerModel (line 101) | class PickerModel : UIPickerViewModel
method PickerModel (line 105) | public PickerModel(Picker picker)
method GetComponentCount (line 110) | public override nint GetComponentCount(UIPickerView pickerView) => 1;
method GetRowsInComponent (line 112) | public override nint GetRowsInComponent(UIPickerView pickerView, nin...
method GetAttributedTitle (line 121) | public override NSAttributedString GetAttributedTitle(UIPickerView p...
method Selected (line 142) | public override void Selected(UIPickerView pickerView, nint row, nin...
FILE: src/Spice/Platforms/iOS/Platform.cs
class Platform (line 3) | class Platform
FILE: src/Spice/Platforms/iOS/PlatformAppearance.cs
class PlatformAppearance (line 3) | public static partial class PlatformAppearance
FILE: src/Spice/Platforms/iOS/PlatformExtensions.cs
class PlatformExtensions (line 8) | public static class PlatformExtensions
method ToUIColor (line 15) | public static UIColor? ToUIColor(this Color? color)
method ToCGColor (line 32) | public static CGColor? ToCGColor(this Color? color)
method DumpHierarchy (line 41) | [Conditional("DEBUG")]
method ToNSDate (line 56) | public static NSDate ToNSDate(this DateTime dateTime)
method ToDateTime (line 67) | public static DateTime ToDateTime(this NSDate nsDate)
FILE: src/Spice/Platforms/iOS/ProgressBar.cs
class ProgressBar (line 3) | public partial class ProgressBar
method ProgressBar (line 16) | public ProgressBar() : base(_ => new UIProgressView { AutoresizingMask...
method ProgressBar (line 20) | public ProgressBar(CGRect frame) : base(_ => new UIProgressView(frame)...
method ProgressBar (line 24) | protected ProgressBar(Func<View, UIView> creator) : base(creator) { }
method OnProgressChanged (line 31) | partial void OnProgressChanged(double value) => NativeView.Progress = ...
FILE: src/Spice/Platforms/iOS/RadioButton.cs
class RadioButton (line 3) | public partial class RadioButton
method RadioButton (line 16) | public RadioButton() : base(_ => new UIButton(UIButtonType.System) { A...
method RadioButton (line 23) | public RadioButton(CGRect frame) : base(_ =>
method RadioButton (line 38) | protected RadioButton(Func<View, UIView> creator) : base(creator)
method InitializeRadioButton (line 48) | void InitializeRadioButton()
method OnIsCheckedChangedPartial (line 55) | partial void OnIsCheckedChangedPartial(bool value)
method OnContentChanged (line 60) | partial void OnContentChanged(string? value)
method OnTouchUpInside (line 65) | void OnTouchUpInside(object? sender, EventArgs e)
method OnCheckedChangedChanged (line 77) | partial void OnCheckedChangedChanged(Action<RadioButton>? value)
FILE: src/Spice/Platforms/iOS/RefreshView.cs
class RefreshView (line 3) | public partial class RefreshView
method RefreshView (line 17) | public RefreshView() : base(v => new UIView { AutoresizingMask = UIVie...
method RefreshView (line 21) | public RefreshView(CGRect frame) : base(v => new UIView(frame) { Autor...
method RefreshView (line 25) | protected RefreshView(Func<View, UIView> creator) : base(creator) { }
method GetOrCreateRefreshControl (line 30) | UIRefreshControl GetOrCreateRefreshControl()
method OnRefreshControlValueChanged (line 43) | void OnRefreshControlValueChanged(object? sender, EventArgs e)
method TryAttachRefreshControl (line 56) | bool TryAttachRefreshControl(UIView view)
method TryDetachRefreshControl (line 83) | void TryDetachRefreshControl()
method OnContentChanged (line 100) | partial void OnContentChanged(View? oldContent, View? newContent)
method OnPaddingChanged (line 126) | partial void OnPaddingChanged(double value)
method OnIsRefreshingChanged (line 135) | partial void OnIsRefreshingChanged(bool value)
method OnRefreshColorChanged (line 156) | partial void OnRefreshColorChanged(Color? value)
FILE: src/Spice/Platforms/iOS/ScrollView.cs
class ScrollView (line 3) | public partial class ScrollView
method ScrollView (line 16) | public ScrollView() : base(v => new SpiceScrollView((ScrollView)v) { A...
method ScrollView (line 20) | public ScrollView(Orientation orientation) : this()
method ScrollView (line 27) | public ScrollView(CGRect frame) : base(v => new SpiceScrollView((Scrol...
method ScrollView (line 31) | protected ScrollView(Func<View, UIView> creator) : base(creator) { }
method OnOrientationChanging (line 40) | partial void OnOrientationChanging(Orientation value)
method OnPaddingChanged (line 65) | partial void OnPaddingChanged(double value)
method AddSubview (line 72) | protected override void AddSubview(View view)
method UpdateContentSize (line 86) | void UpdateContentSize(View view)
class SpiceScrollView (line 102) | class SpiceScrollView : UIScrollView
method SpiceScrollView (line 106) | public SpiceScrollView(ScrollView parent) => _parent = parent;
method SpiceScrollView (line 108) | public SpiceScrollView(ScrollView parent, CGRect frame) : base(frame...
method LayoutSubviews (line 110) | public override void LayoutSubviews()
FILE: src/Spice/Platforms/iOS/SearchBar.cs
class SearchBar (line 3) | public partial class SearchBar
method SearchBar (line 16) | public SearchBar() : base(_ => new UISearchBar { AutoresizingMask = UI...
method SearchBar (line 20) | public SearchBar(CGRect frame) : base(_ => new UISearchBar(frame) { Au...
method SearchBar (line 24) | protected SearchBar(Func<View, UIView> creator) : base(creator) { }
method OnTextChanged (line 31) | partial void OnTextChanged(string value) => NativeView.Text = value;
method OnPlaceholderChanged (line 33) | partial void OnPlaceholderChanged(string? value)
method OnTextColorChanged (line 41) | partial void OnTextColorChanged(Color? value)
method OnPlaceholderColorChanged (line 48) | partial void OnPlaceholderColorChanged(Color? value)
method UpdateDelegate (line 69) | void UpdateDelegate()
method OnSearchButtonPressedChanged (line 86) | partial void OnSearchButtonPressedChanged(Action<SearchBar>? value) =>...
method OnTextChangedChanged (line 88) | partial void OnTextChangedChanged(Action<SearchBar>? value) => UpdateD...
class SearchBarDelegate (line 90) | class SearchBarDelegate : UISearchBarDelegate
method SearchBarDelegate (line 94) | public SearchBarDelegate(SearchBar searchBar)
method SearchButtonClicked (line 99) | public override void SearchButtonClicked(UISearchBar uiSearchBar)
method TextChanged (line 108) | public override void TextChanged(UISearchBar uiSearchBar, string sea...
FILE: src/Spice/Platforms/iOS/Slider.cs
class Slider (line 3) | public partial class Slider
method Slider (line 16) | public Slider() : base(_ => new UISlider { AutoresizingMask = UIViewAu...
method Slider (line 20) | public Slider(CGRect frame) : base(_ => new UISlider(frame) { Autoresi...
method Slider (line 24) | protected Slider(Func<View, UIView> creator) : base(creator) { }
method OnMinimumChanged (line 31) | partial void OnMinimumChanged(double value) => NativeView.MinValue = (...
method OnMaximumChanged (line 33) | partial void OnMaximumChanged(double value) => NativeView.MaxValue = (...
method OnValueChanged (line 35) | partial void OnValueChanged(double value)
method OnValueChangedChanged (line 45) | partial void OnValueChangedChanged(Action<Slider>? value)
FILE: src/Spice/Platforms/iOS/SpiceAppDelegate.cs
class SpiceSceneDelegate (line 12) | [Register("SpiceSceneDelegate")]
method WillConnect (line 24) | [Export("scene:willConnectToSession:options:")]
class SpiceAppDelegate (line 48) | public abstract class SpiceAppDelegate : UIApplicationDelegate
method CreateApplication (line 53) | public abstract Application CreateApplication();
FILE: src/Spice/Platforms/iOS/SpiceViewController.cs
class SpiceViewController (line 7) | class SpiceViewController : UIViewController
method ViewDidLoad (line 9) | public override void ViewDidLoad()
method TraitCollectionDidChange (line 22) | public override void TraitCollectionDidChange(UITraitCollection? previ...
FILE: src/Spice/Platforms/iOS/StackLayout.cs
class StackLayout (line 3) | public partial class StackLayout
method StackLayout (line 16) | public StackLayout() : this(v => new SpiceStackView((StackLayout)v) { ...
method StackLayout (line 20) | public StackLayout(CGRect frame) : this(v => new SpiceStackView((Stack...
method StackLayout (line 24) | protected StackLayout(Func<View, UIView> creator) : base(creator) { }
method OnOrientationChanging (line 31) | partial void OnOrientationChanging(Orientation value)
method OnSpacingChanged (line 46) | partial void OnSpacingChanged(double value) => NativeView.Spacing = (n...
method OnPaddingChanged (line 48) | partial void OnPaddingChanged(double value)
method AddSubview (line 56) | protected override void AddSubview(View view)
class SpiceStackView (line 62) | class SpiceStackView : UIStackView
method SpiceStackView (line 66) | public SpiceStackView(StackLayout parent) => _parent = parent;
method SpiceStackView (line 68) | public SpiceStackView(StackLayout parent, CGRect frame) : base(frame...
method SizeThatFits (line 70) | public override CGSize SizeThatFits(CGSize size)
FILE: src/Spice/Platforms/iOS/SwipeView.cs
class SwipeView (line 3) | public partial class SwipeView
method SwipeView (line 16) | public SwipeView() : base(_ => new UIView { AutoresizingMask = UIViewA...
method SwipeView (line 23) | public SwipeView(CGRect frame) : base(_ => new UIView(frame) { Autores...
method SwipeView (line 32) | protected SwipeView(Func<View, UIView> creator) : base(creator)
method SetupGestureRecognizers (line 43) | void SetupGestureRecognizers()
method HandlePan (line 49) | void HandlePan(UIPanGestureRecognizer gesture)
method ShowSwipeItems (line 122) | void ShowSwipeItems(SwipeItems items, SwipeDirection direction)
method ResetPosition (line 186) | void ResetPosition()
method OnContentChanged (line 201) | partial void OnContentChanged(View? oldContent, View? newContent)
method OnOpen (line 225) | partial void OnOpen(SwipeDirection direction)
method OnClose (line 242) | partial void OnClose()
FILE: src/Spice/Platforms/iOS/Switch.cs
class Switch (line 3) | public partial class Switch
method Switch (line 16) | public Switch() : base(_ => new UISwitch { AutoresizingMask = UIViewAu...
method Switch (line 20) | public Switch(CGRect frame) : base(_ => new UISwitch(frame) { Autoresi...
method Switch (line 24) | protected Switch(Func<View, UIView> creator) : base(creator) { }
method OnIsOnChanged (line 31) | partial void OnIsOnChanged(bool value) => NativeView.SetState(value, t...
method OnToggledChanged (line 35) | partial void OnToggledChanged(Action<Switch>? value)
FILE: src/Spice/Platforms/iOS/TabView.cs
class TabView (line 5) | public partial class TabView
method TabView (line 15) | public TabView() : base(_ => new UIView { AutoresizingMask = UIViewAut...
method OnTabsChanged (line 42) | void OnTabsChanged(object? sender, NotifyCollectionChangedEventArgs e)
method UpdateTabs (line 47) | void UpdateTabs()
class Tab (line 86) | public partial class Tab
method Tab (line 91) | public Tab() : base(_ => new UIView { AutoresizingMask = UIViewAutores...
FILE: src/Spice/Platforms/iOS/TimePicker.cs
class TimePicker (line 3) | public partial class TimePicker
method TimePicker (line 16) | public TimePicker() : base(_ => new UIDatePicker
method TimePicker (line 28) | public TimePicker(CGRect frame) : base(_ => new UIDatePicker(frame)
method TimePicker (line 40) | protected TimePicker(Func<View, UIView> creator) : base(creator) { }
method OnTimeChanged (line 47) | partial void OnTimeChanged(TimeOnly value)
method OnNativeValueChanged (line 54) | void OnNativeValueChanged(object? sender, EventArgs e)
FILE: src/Spice/Platforms/iOS/View.cs
class View (line 7) | public partial class View
method View (line 18) | public View() : this(_ => new UIView { AutoresizingMask = UIViewAutore...
method View (line 24) | public View(CGRect frame) : this(_ => new UIView(frame) { Autoresizing...
method View (line 30) | protected View(Func<View, UIView> creator)
method AddSubview (line 60) | protected virtual void AddSubview(View view)
method OnChildrenChanged (line 66) | void OnChildrenChanged(object? sender, NotifyCollectionChangedEventArg...
method OnBackgroundColorChanged (line 85) | partial void OnBackgroundColorChanged(Color? value) => NativeView.Back...
method OnVerticalOptionsChanged (line 87) | partial void OnVerticalOptionsChanged(LayoutOptions value) => ApplyCon...
method OnHorizontalOptionsChanged (line 89) | partial void OnHorizontalOptionsChanged(LayoutOptions value) => ApplyC...
method OnIsVisibleChanged (line 91) | partial void OnIsVisibleChanged(bool value) => NativeView.Hidden = !va...
method OnIsEnabledChanged (line 93) | partial void OnIsEnabledChanged(bool value) => NativeView.UserInteract...
method OnOpacityChanged (line 95) | partial void OnOpacityChanged(double value) => NativeView.Alpha = (nfl...
method OnAutomationIdChanged (line 97) | partial void OnAutomationIdChanged(string? value) => NativeView.Access...
method OnMarginChanged (line 99) | partial void OnMarginChanged(Thickness value) => ApplyConstraints();
method OnWidthRequestChanged (line 101) | partial void OnWidthRequestChanged(double value)
method OnHeightRequestChanged (line 110) | partial void OnHeightRequestChanged(double value)
method GetWidth (line 119) | private partial double GetWidth() => (double)NativeView.Frame.Width;
method GetHeight (line 121) | private partial double GetHeight() => (double)NativeView.Frame.Height;
method PresentAsyncCore (line 125) | private partial Task PresentAsyncCore(View view)
method DismissAsyncCore (line 154) | private partial Task DismissAsyncCore()
method ApplyConstraints (line 166) | internal void ApplyConstraints()
method UpdateAlign (line 187) | internal void UpdateAlign() => ApplyConstraints();
FILE: src/Spice/Platforms/iOS/WebView.cs
class WebView (line 5) | public partial class WebView
method CreateConfiguration (line 13) | internal static WKWebViewConfiguration CreateConfiguration()
method Create (line 34) | internal static WKWebView Create(CGRect frame, Func<WKWebViewConfigura...
method WebView (line 48) | public WebView() : this(_ => Create(CGRect.Empty, CreateConfiguration)...
method WebView (line 52) | public WebView(CGRect frame) : this(_ => Create(frame, CreateConfigura...
method WebView (line 56) | protected WebView(Func<View, UIView> creator) : base(creator) => Initi...
method Initialize (line 59) | void Initialize()
method OnSourceChanged (line 71) | partial void OnSourceChanged(string value) => NativeView.LoadRequest(n...
method Back (line 81) | public void Back()
method Forward (line 95) | public void Forward()
FILE: tests/Spice.Tests/ActivityIndicatorTests.cs
class ActivityIndicatorTests (line 6) | public class ActivityIndicatorTests
method ActivityIndicatorCreation (line 8) | [Fact]
method IsRunningProperty (line 17) | [Fact]
method ColorProperty (line 30) | [Fact]
method PropertyChangedEventsWork (line 48) | [Fact]
method ActivityIndicatorInStackLayout (line 62) | [Fact]
FILE: tests/Spice.Tests/ApplicationTests.cs
class ApplicationTests (line 6) | public class ApplicationTests
class App (line 8) | class App : Application
method App (line 10) | public App()
method Application (line 29) | [Fact]
FILE: tests/Spice.Tests/AutomationIdTests.cs
class AutomationIdTests (line 6) | public class AutomationIdTests
method AutomationIdDefaultsToNull (line 8) | [Fact]
method AutomationIdCanBeSet (line 15) | [Fact]
method AutomationIdPropertyChangedEventFires (line 25) | [Fact]
method AutomationIdWorksOnButton (line 37) | [Fact]
method AutomationIdWorksOnLabel (line 49) | [Fact]
method AutomationIdWorksOnEntry (line 61) | [Fact]
method AutomationIdWorksOnActivityIndicator (line 73) | [Fact]
method CanChangeAutomationId (line 85) | [Fact]
method AutomationIdWorksInStackLayout (line 98) | [Fact]
method AutomationIdCanBeSetAfterCreation (line 114) | [Fact]
method AutomationIdWorksWithMultipleViews (line 124) | [Fact]
method AutomationIdWorksOnImage (line 136) | [Fact]
method AutomationIdWorksOnImageButton (line 146) | [Fact]
FILE: tests/Spice.Tests/BindingExtensionsTests.cs
class BindingExtensionsTests (line 6) | public class BindingExtensionsTests
method Bind_SyncsInitialValue (line 8) | [Fact]
method Bind_UpdatesWhenPropertyChanges (line 22) | [Fact]
method Bind_DoesNotUpdateForOtherProperties (line 37) | [Fact]
method Bind_SupportsMultipleBindings (line 52) | [Fact]
method Bind_DisposalStopsUpdates (line 76) | [Fact]
method Bind_MultipleDisposalsSafe (line 92) | [Fact]
method Bind_ThrowsOnNullSource (line 106) | [Fact]
method Bind_ThrowsOnNullPropertyName (line 118) | [Fact]
method Bind_ThrowsOnNullGetter (line 130) | [Fact]
method Bind_ThrowsOnNullApply (line 142) | [Fact]
method Bind_WorksWithViewToView (line 153) | [Fact]
method Bind_WorksWithValueTypes (line 171) | [Fact]
method Bind_WorksWithBooleans (line 189) | [Fact]
FILE: tests/Spice.Tests/BorderTests.cs
class BorderTests (line 6) | public class BorderTests
method Constructor (line 8) | [Fact]
method DefaultProperties (line 15) | [Fact]
method SetContent (line 26) | [Fact]
method SetStroke (line 35) | [Fact]
method SetStrokeThickness (line 45) | [Fact]
method SetCornerRadius (line 55) | [Fact]
method SetPadding (line 65) | [Fact]
method PropertyChangedFires (line 75) | [Fact]
method CanSetAllProperties (line 86) | [Fact]
method ContentCanBeChanged (line 108) | [Fact]
method ContentCanBeCleared (line 122) | [Fact]
method AddingToChildrenDoesNotSetContent (line 135) | [Fact]
method BackgroundColorCanBeSet (line 152) | [Fact]
method BackgroundColorCanBeChanged (line 162) | [Fact]
method StrokeThicknessCanBeSetWhenStrokeIsNull (line 178) | [Fact]
FILE: tests/Spice.Tests/BoxViewTests.cs
class BoxViewTests (line 6) | public class BoxViewTests
method BoxViewCreation (line 8) | [Fact]
method ColorProperty (line 16) | [Fact]
method PropertyChangedEventsWork (line 34) | [Fact]
method BoxViewInStackLayout (line 45) | [Fact]
FILE: tests/Spice.Tests/ButtonTests.cs
class ButtonTests (line 7) | public class ButtonTests
method ButtonCanBeCreated (line 9) | [Fact]
method ButtonInheritsFromView (line 16) | [Fact]
method TextPropertyDefaultsToEmptyString (line 23) | [Fact]
method TextPropertyCanBeSet (line 30) | [Fact]
method TextColorPropertyDefaultsToNull (line 37) | [Fact]
method TextColorPropertyCanBeSet (line 44) | [Fact]
method ClickedActionDefaultsToNull (line 52) | [Fact]
method ClickedActionCanBeSet (line 59) | [Fact]
method PropertyChangedFiresOnTextChange (line 73) | [Fact]
method PropertyChangedFiresOnTextColorChange (line 88) | [Fact]
method PropertyChangedFiresOnClickedChange (line 103) | [Fact]
method ClickedCanBeReplacedWithoutStaleHandler (line 118) | [Fact]
method ClickedCanBeSetToNullAfterNonNull (line 137) | [Fact]
FILE: tests/Spice.Tests/CheckBoxTests.cs
class CheckBoxTests (line 6) | public class CheckBoxTests
method IsCheckedPropertyChanged (line 8) | [Fact]
method CheckedChangedAssignmentRaisesPropertyChanged (line 20) | [Fact]
method DefaultIsCheckedIsFalse (line 32) | [Fact]
method IsCheckedCanBeSet (line 39) | [Fact]
method CheckedChangedCanBeSet (line 49) | [Fact]
FILE: tests/Spice.Tests/CollectionViewTests.cs
class CollectionViewTests (line 6) | public class CollectionViewTests
method CanCreate (line 8) | [Fact]
method DefaultOrientationIsVertical (line 15) | [Fact]
method DefaultSelectionModeIsNone (line 22) | [Fact]
method DefaultItemSpacingIsZero (line 29) | [Fact]
method ItemsSourceIsNullByDefault (line 36) | [Fact]
method ItemTemplateIsNullByDefault (line 43) | [Fact]
method SelectedItemIsNullByDefault (line 50) | [Fact]
method CanSetItemsSource (line 57) | [Fact]
method CanSetItemTemplate (line 69) | [Fact]
method CanSetOrientation (line 81) | [Fact]
method CanSetSelectionMode (line 91) | [Fact]
method CanSetItemSpacing (line 101) | [Fact]
method CanSetSelectedItem (line 111) | [Fact]
method PropertyChangedFiresOnItemsSourceChange (line 125) | [Fact]
method PropertyChangedFiresOnItemTemplateChange (line 137) | [Fact]
method PropertyChangedFiresOnOrientationChange (line 149) | [Fact]
method PropertyChangedFiresOnSelectionModeChange (line 161) | [Fact]
method PropertyChangedFiresOnSelectedItemChange (line 173) | [Fact]
method PropertyChangedFiresOnItemSpacingChange (line 185) | [Fact]
method ItemTemplateCreatesViewForItem (line 197) | [Fact]
method ItemTemplateCanReturnDifferentViewTypes (line 212) | [Fact]
method CanUseObservableCollectionAsItemsSource (line 233) | [Fact]
method CanReplaceItemsSource (line 248) | [Fact]
method CanClearItemsSource (line 262) | [Fact]
method MultipleSelectionModeAllowsMultipleItems (line 275) | [Fact]
method CanCreateCompleteCollectionView (line 286) | [Fact]
FILE: tests/Spice.Tests/ContentViewTests.cs
class ContentViewTests (line 6) | public class ContentViewTests
method CanCreate (line 8) | [Fact]
method ContentIsNullByDefault (line 15) | [Fact]
method CanSetContent (line 22) | [Fact]
method CanReplaceContent (line 34) | [Fact]
method CanClearContent (line 48) | [Fact]
method PropertyChangedFiresOnContentChange (line 61) | [Fact]
method SettingSameContentDoesNotFirePropertyChanged (line 74) | [Fact]
method CanContainStackLayout (line 88) | [Fact]
method CanContainComplexLayout (line 106) | [Fact]
method ContentViewCanBeNestedInOtherViews (line 126) | [Fact]
method MultipleContentViewsCanExist (line 142) | [Fact]
method DefaultPaddingIsZero (line 162) | [Fact]
method CanSetPadding (line 169) | [Fact]
method PropertyChangedFiresOnPaddingChange (line 179) | [Fact]
FILE: tests/Spice.Tests/DatePickerTests.cs
class DatePickerTests (line 6) | public class DatePickerTests
method DatePicker_DefaultDate_IsToday (line 8) | [Fact]
method DatePicker_SetDate_UpdatesProperty (line 18) | [Fact]
method DatePicker_SetMinimumDate_UpdatesProperty (line 27) | [Fact]
method DatePicker_SetMaximumDate_UpdatesProperty (line 36) | [Fact]
method DatePicker_SetTextColor_UpdatesProperty (line 45) | [Fact]
method DatePicker_PropertyChanged_Fires (line 54) | [Fact]
method DatePicker_MinMaxDates_CanBeNull (line 67) | [Fact]
FILE: tests/Spice.Tests/EditorTests.cs
class EditorTests (line 7) | public class EditorTests
method EditorCanBeCreated (line 9) | [Fact]
method EditorInheritsFromView (line 16) | [Fact]
method TextPropertyDefaultsToEmptyString (line 23) | [Fact]
method TextPropertyCanBeSet (line 30) | [Fact]
method TextColorPropertyDefaultsToNull (line 37) | [Fact]
method TextColorPropertyCanBeSet (line 44) | [Fact]
method PlaceholderPropertyDefaultsToNull (line 52) | [Fact]
method PlaceholderPropertyCanBeSet (line 59) | [Fact]
method PlaceholderColorPropertyDefaultsToNull (line 66) | [Fact]
method PlaceholderColorPropertyCanBeSet (line 73) | [Fact]
method AutoSizePropertyDefaultsToFalse (line 81) | [Fact]
method AutoSizePropertyCanBeSet (line 88) | [Fact]
method PropertyChangedFiresOnTextChange (line 95) | [Fact]
method PropertyChangedFiresOnTextColorChange (line 110) | [Fact]
method PropertyChangedFiresOnPlaceholderChange (line 125) | [Fact]
method PropertyChangedFiresOnPlaceholderColorChange (line 140) | [Fact]
method PropertyChangedFiresOnAutoSizeChange (line 155) | [Fact]
method TextCanBeSetMultipleTimes (line 170) | [Fact]
method MultiplePropertiesCanBeSetTogether (line 183) | [Fact]
FILE: tests/Spice.Tests/EntryTests.cs
class EntryTests (line 7) | public class EntryTests
method EntryCanBeCreated (line 9) | [Fact]
method EntryInheritsFromView (line 16) | [Fact]
method TextPropertyDefaultsToEmptyString (line 23) | [Fact]
method TextPropertyCanBeSet (line 30) | [Fact]
method TextColorPropertyDefaultsToNull (line 37) | [Fact]
method TextColorPropertyCanBeSet (line 44) | [Fact]
method IsPasswordPropertyDefaultsToFalse (line 52) | [Fact]
method IsPasswordPropertyCanBeSet (line 59) | [Fact]
method PropertyChangedFiresOnTextChange (line 66) | [Fact]
method PropertyChangedFiresOnTextColorChange (line 81) | [Fact]
method PropertyChangedFiresOnIsPasswordChange (line 96) | [Fact]
method TextCanBeSetMultipleTimes (line 111) | [Fact]
FILE: tests/Spice.Tests/GridLengthTests.cs
class GridLengthTests (line 6) | public class GridLengthTests
method AutoPropertyIsAuto (line 8) | [Fact]
method StarPropertyIsStar (line 19) | [Fact]
method CanCreateAbsoluteLength (line 30) | [Fact]
method CanCreateStarLength (line 41) | [Fact]
method CanCreateAutoLength (line 52) | [Fact]
method NegativeValueThrows (line 63) | [Fact]
method NaNValueThrows (line 69) | [Fact]
method InfinityValueThrows (line 75) | [Fact]
method EqualityWorks (line 81) | [Fact]
method AutoToStringIsAuto (line 96) | [Fact]
method SingleStarToStringIsStar (line 103) | [Fact]
method MultipleStarToStringHasMultiplier (line 110) | [Fact]
method AbsoluteToStringIsValue (line 117) | [Fact]
method GetHashCodeWorks (line 124) | [Fact]
method EqualsWithObjectWorks (line 135) | [Fact]
FILE: tests/Spice.Tests/GridTests.cs
class GridTests (line 6) | public class GridTests
method CanCreate (line 8) | [Fact]
method DefaultSpacingIsZero (line 15) | [Fact]
method CanSetSpacing (line 23) | [Fact]
method RowDefinitionsStartsEmpty (line 35) | [Fact]
method ColumnDefinitionsStartsEmpty (line 42) | [Fact]
method CanAddRowDefinitions (line 49) | [Fact]
method CanAddColumnDefinitions (line 64) | [Fact]
method CanAddChildren (line 80) | [Fact]
method DefaultRowIsZero (line 95) | [Fact]
method DefaultColumnIsZero (line 102) | [Fact]
method DefaultRowSpanIsOne (line 109) | [Fact]
method DefaultColumnSpanIsOne (line 116) | [Fact]
method CanSetRow (line 123) | [Fact]
method CanSetColumn (line 131) | [Fact]
method CanSetRowSpan (line 139) | [Fact]
method CanSetColumnSpan (line 147) | [Fact]
method RowCannotBeNegative (line 155) | [Fact]
method ColumnCannotBeNegative (line 162) | [Fact]
method RowSpanCannotBeLessThanOne (line 169) | [Fact]
method ColumnSpanCannotBeLessThanOne (line 176) | [Fact]
method CanCreateComplexGrid (line 183) | [Fact]
method PropertyChangedFiresOnRowSpacingChange (line 234) | [Fact]
method PropertyChangedFiresOnColumnSpacingChange (line 245) | [Fact]
method DefaultPaddingIsZero (line 256) | [Fact]
method CanSetPadding (line 263) | [Fact]
method PropertyChangedFiresOnPaddingChange (line 273) | [Fact]
FILE: tests/Spice.Tests/ImageButtonTests.cs
class ImageButtonTests (line 6) | public class ImageButtonTests
method ImageButtonCreation (line 8) | [Fact]
method SourcePropertyWorks (line 17) | [Fact]
method SourcePropertyChangedEvent (line 24) | [Fact]
method ClickedActionWorks (line 36) | [Fact]
method ClickedActionCanBeCleared (line 46) | [Fact]
method ImageButtonInheritsFromView (line 58) | [Fact]
FILE: tests/Spice.Tests/ImageTests.cs
class ImageTests (line 7) | public class ImageTests
method ImageCanBeCreated (line 9) | [Fact]
method ImageInheritsFromView (line 16) | [Fact]
method SourcePropertyDefaultsToEmptyString (line 23) | [Fact]
method SourcePropertyCanBeSet (line 30) | [Fact]
method PropertyChangedFiresOnSourceChange (line 37) | [Fact]
method SourceCanBeSetMultipleTimes (line 52) | [Fact]
method MultipleImageInstancesAreIndependent (line 65) | [Fact]
FILE: tests/Spice.Tests/LabelTests.cs
class LabelTests (line 7) | public class LabelTests
method LabelCanBeCreated (line 9) | [Fact]
method LabelInheritsFromView (line 16) | [Fact]
method TextPropertyDefaultsToEmptyString (line 23) | [Fact]
method TextPropertyCanBeSet (line 30) | [Fact]
method TextColorPropertyDefaultsToNull (line 37) | [Fact]
method TextColorPropertyCanBeSet (line 44) | [Fact]
method PropertyChangedFiresOnTextChange (line 52) | [Fact]
method PropertyChangedFiresOnTextColorChange (line 67) | [Fact]
method TextCanBeSetToLongString (line 82) | [Fact]
method TextCanBeSetMultipleTimes (line 91) | [Fact]
method MultipleLabelInstancesAreIndependent (line 104) | [Fact]
FILE: tests/Spice.Tests/LayoutOptionsTests.cs
class LayoutOptionsTests (line 6) | public class LayoutOptionsTests
method LayoutOptionsStartHasCorrectAlignment (line 8) | [Fact]
method LayoutOptionsCenterHasCorrectAlignment (line 15) | [Fact]
method LayoutOptionsEndHasCorrectAlignment (line 22) | [Fact]
method LayoutOptionsFillHasCorrectAlignment (line 29) | [Fact]
method LayoutOptionsCanBeConstructed (line 36) | [Fact]
method LayoutOptionsCanBeConstructedWithExpands (line 44) | [Fact]
method LayoutOptionsEqualityWorks (line 52) | [Fact]
method LayoutOptionsAlignmentCanBeSet (line 67) | [Fact]
method LayoutOptionsExpandsCanBeSet (line 75) | [Fact]
method LayoutOptionsGetHashCodeWorks (line 83) | [Fact]
method LayoutOptionsEqualsWorksWithObject (line 94) | [Fact]
FILE: tests/Spice.Tests/MarginTests.cs
class MarginTests (line 6) | public class MarginTests
method MarginDefaultsToZero (line 8) | [Fact]
method CanSetUniformMargin (line 16) | [Fact]
method CanSetHorizontalVerticalMargin (line 30) | [Fact]
method CanSetIndividualMargins (line 43) | [Fact]
method MarginPropertyChangedEventFires (line 56) | [Fact]
method MarginWorksOnButton (line 68) | [Fact]
method MarginWorksOnLabel (line 80) | [Fact]
method MarginWorksOnContentView (line 95) | [Fact]
method MarginWorksOnBoxView (line 107) | [Fact]
method CanChangeMargin (line 119) | [Fact]
method MarginWorksWithAlignment (line 135) | [Fact]
method MarginWorksWithBackgroundColor (line 149) | [Fact]
method MarginAndPaddingAreSeparateProperties (line 161) | [Fact]
method CanSetMarginInStackLayout (line 173) | [Fact]
method MultipleChildrenCanHaveDifferentMargins (line 189) | [Fact]
FILE: tests/Spice.Tests/ModalPresentationTests.cs
class ModalPresentationTests (line 6) | public class ModalPresentationTests
class TestView (line 8) | class TestView : View
method TestView (line 10) | public TestView()
class SecondView (line 16) | class SecondView : View
method SecondView (line 18) | public SecondView()
method PresentAsyncWithViewDoesNotThrow (line 24) | [Fact]
method PresentAsyncWithFactoryDoesNotThrow (line 34) | [Fact]
method PresentAsyncGenericDoesNotThrow (line 43) | [Fact]
method DismissAsyncDoesNotThrow (line 52) | [Fact]
method PresentAsyncWithNullViewThrows (line 61) | [Fact]
method PresentAsyncWithNullFactoryThrows (line 68) | [Fact]
method PresentAsyncWithFactoryCallsFactory (line 75) | [Fact]
method PresentAsyncReturnsCompletedTask (line 90) | [Fact]
method DismissAsyncReturnsCompletedTask (line 100) | [Fact]
method PresentAsyncIsAvailableOnAnyView (line 109) | [Fact]
method PresentAsyncGenericCreatesCorrectType (line 118) | [Fact]
method ApplicationIsJustAViewWithMain (line 128) | [Fact]
FILE: tests/Spice.Tests/NavigationViewTests.cs
class NavigationViewTests (line 6) | public class NavigationViewTests
class TestView (line 8) | class TestView : View
method TestView (line 10) | public TestView()
class SecondView (line 16) | class SecondView : View
method SecondView (line 18) | public SecondView()
method NavigationViewCanBeCreated (line 24) | [Fact]
method NavigationViewInheritsFromView (line 32) | [Fact]
method NavigationViewCanBeCreatedWithFactory (line 40) | [Fact]
method NavigationViewGenericCanBeCreated (line 47) | [Fact]
method NavigationViewGenericInheritsFromNavigationView (line 54) | [Fact]
method PushSetsNavigationProperty (line 61) | [Fact]
method PushWithViewSetsNavigation (line 70) | [Fact]
method PushWithFactorySetsNavigation (line 82) | [Fact]
method PushGenericSetsNavigation (line 99) | [Fact]
method PopDoesNotThrow (line 110) | [Fact]
method PopToRootDoesNotThrow (line 117) | [Fact]
method PushWithNullViewThrows (line 124) | [Fact]
method PushWithNullFactoryThrows (line 131) | [Fact]
method NavigationViewConstructorWithNullRootThrows (line 138) | [Fact]
method NavigationViewConstructorWithNullFactoryThrows (line 144) | [Fact]
method TitlePropertyDefaultsToEmptyString (line 150) | [Fact]
method TitlePropertyCanBeSet (line 157) | [Fact]
method NavigationPropertyDefaultsToNull (line 164) | [Fact]
method PropertyChangedFiresOnTitleChange (line 171) | [Fact]
FILE: tests/Spice.Tests/PickerTests.cs
class PickerTests (line 9) | public class PickerTests
method PickerPropertyChangedWorks (line 11) | [Fact]
method PickerItemsCanBeAdded (line 22) | [Fact]
method PickerSelectedIndexDefault (line 34) | [Fact]
method PickerSelectedIndexUpdates (line 43) | [Fact]
method PickerSelectedItemReturnsNull (line 57) | [Fact]
method PickerSelectedItemReturnsNullForOutOfRange (line 68) | [Fact]
method PickerTextColorCanBeSet (line 79) | [Fact]
method PickerItemsCollectionNotifiesChange (line 88) | [Fact]
method PickerTitleCanBeSet (line 100) | [Fact]
method PickerSelectedItemNotifiesPropertyChanged (line 108) | [Fact]
FILE: tests/Spice.Tests/Platforms/Android/MainActivity.cs
class MainActivity (line 6) | [Activity(Label = "Spice.Tests", MainLauncher = true)]
method OnCreate (line 9) | protected override void OnCreate(Bundle? savedInstanceState)
FILE: tests/Spice.Tests/Platforms/Android/TestDevice.cs
class TestDevice (line 6) | class TestDevice : IDevice
FILE: tests/Spice.Tests/Platforms/Android/TestEntryPoint.cs
class TestEntryPoint (line 6) | class TestEntryPoint : AndroidApplicationEntryPoint
method TestEntryPoint (line 10) | public TestEntryPoint(string cacheDir)
method GetTestAssemblies (line 25) | protected override IEnumerable<TestAssemblyInfo> GetTestAssemblies()
method TerminateWithSuccess (line 36) | protected override void TerminateWithSuccess() { }
FILE: tests/Spice.Tests/Platforms/Android/TestInstrumentation.cs
class TestInstrumentation (line 7) | [Instrumentation(Name = "com.jonathanpeppers.spice.tests.TestInstrumenta...
method TestInstrumentation (line 10) | protected TestInstrumentation(IntPtr handle, JniHandleOwnership owners...
method OnCreate (line 13) | public override void OnCreate(Bundle? arguments)
method OnStart (line 19) | public override void OnStart()
FILE: tests/Spice.Tests/Platforms/iOS/AppDelegate.cs
class AppDelegate (line 7) | [Register("AppDelegate")]
method FinishedLaunching (line 12) | public override bool FinishedLaunching(UIApplication application, NSDi...
FILE: tests/Spice.Tests/Platforms/iOS/TestDevice.cs
class TestDevice (line 7) | class TestDevice : IDevice
FILE: tests/Spice.Tests/Platforms/iOS/TestEntryPoint.cs
class TestEntryPoint (line 8) | class TestEntryPoint : iOSApplicationEntryPoint
method GetTestAssemblies (line 16) | protected override IEnumerable<TestAssemblyInfo> GetTestAssemblies()
method TerminateWithSuccess (line 23) | protected override void TerminateWithSuccess()
FILE: tests/Spice.Tests/ProgressBarTests.cs
class ProgressBarTests (line 6) | public class ProgressBarTests
method Constructor (line 8) | [Fact]
method DefaultProgress (line 15) | [Fact]
method SetProgress (line 22) | [Fact]
method ProgressRange (line 32) | [Fact]
method PropertyChangedFires (line 50) | [Fact]
method ProgressClamping (line 61) | [Fact]
FILE: tests/Spice.Tests/PropertyChangedTests.cs
class PropertyChangedTests (line 6) | public class PropertyChangedTests
method PropertyChangedWorks (line 8) | [Fact]
method PropertyChangingWorks (line 19) | [Fact]
FILE: tests/Spice.Tests/RadioButtonTests.cs
class RadioButtonTests (line 6) | public class RadioButtonTests
method IsCheckedPropertyChanged (line 8) | [Fact]
method CheckedChangedAssignmentRaisesPropertyChanged (line 20) | [Fact]
method DefaultIsCheckedIsFalse (line 32) | [Fact]
method IsCheckedCanBeSet (line 39) | [Fact]
method CheckedChangedCanBeSet (line 49) | [Fact]
method GroupNamePropertyChanged (line 60) | [Fact]
method GroupNameCanBeSet (line 72) | [Fact]
method ContentPropertyChanged (line 82) | [Fact]
method ContentCanBeSet (line 94) | [Fact]
method GroupExclusivity (line 104) | [Fact]
method DifferentGroupsAreIndependent (line 132) | [Fact]
method NoGroupNameAllowsMultipleChecked (line 145) | [Fact]
method ObjectInitializerWithIsCheckedBeforeGroupName (line 158) | [Fact]
method ChangingGroupNameRemovesFromOldGroup (line 173) | [Fact]
method ChangingGroupNameToSameGroupEnforcesExclusivity (line 191) | [Fact]
FILE: tests/Spice.Tests/RefreshViewTests.cs
class RefreshViewTests (line 6) | public class RefreshViewTests
method CanCreate (line 8) | [Fact]
method ContentIsNullByDefault (line 15) | [Fact]
method IsRefreshingIsFalseByDefault (line 22) | [Fact]
method CommandIsNullByDefault (line 29) | [Fact]
method RefreshColorIsNullByDefault (line 36) | [Fact]
method CanSetContent (line 43) | [Fact]
method CanReplaceContent (line 55) | [Fact]
method CanClearContent (line 69) | [Fact]
method CanSetIsRefreshing (line 82) | [Fact]
method CanSetCommand (line 95) | [Fact]
method CanSetRefreshColor (line 111) | [Fact]
method PropertyChangedFiresOnContentChange (line 129) | [Fact]
method PropertyChangedFiresOnIsRefreshingChange (line 142) | [Fact]
method PropertyChangedFiresOnCommandChange (line 154) | [Fact]
method PropertyChangedFiresOnRefreshColorChange (line 167) | [Fact]
method SettingSameContentDoesNotFirePropertyChanged (line 179) | [Fact]
method CanContainScrollView (line 193) | [Fact]
method CanContainStackLayout (line 208) | [Fact]
method CanSetAllPropertiesAtOnce (line 226) | [Fact]
method RefreshViewCanBeNestedInOtherViews (line 248) | [Fact]
method MultipleRefreshViewsCanExist (line 264) | [Fact]
method DefaultPaddingIsZero (line 284) | [Fact]
method CanSetPadding (line 291) | [Fact]
method PropertyChangedFiresOnPaddingChange (line 301) | [Fact]
FILE: tests/Spice.Tests/ScrollViewTests.cs
class ScrollViewTests (line 6) | public class ScrollViewTests
method CanCreate (line 8) | [Fact]
method DefaultOrientationIsVertical (line 15) | [Fact]
method CanSetOrientation (line 22) | [Fact]
method CanAddChild (line 34) | [Fact]
method AddingMultipleChildrenTracksAll (line 45) | [Fact]
method PropertyChangedFiresOnOrientationChange (line 62) | [Fact]
method CanContainStackLayout (line 75) | [Fact]
method DefaultPaddingIsZero (line 92) | [Fact]
method CanSetPadding (line 99) | [Fact]
method PropertyChangedFiresOnPaddingChange (line 109) | [Fact]
FILE: tests/Spice.Tests/SearchBarTests.cs
class SearchBarTests (line 3) | public class SearchBarTests
method Text_DefaultsToEmpty (line 5) | [Fact]
method Placeholder_DefaultsToNull (line 12) | [Fact]
method TextColor_DefaultsToNull (line 19) | [Fact]
method SearchButtonPressed_DefaultsToNull (line 26) | [Fact]
method PlaceholderColor_DefaultsToNull (line 33) | [Fact]
method TextChanged_DefaultsToNull (line 40) | [Fact]
method Text_CanBeSet (line 47) | [Fact]
method Placeholder_CanBeSet (line 55) | [Fact]
method TextColor_CanBeSet (line 63) | [Fact]
method SearchButtonPressed_CanBeSet (line 71) | [Fact]
method PlaceholderColor_CanBeSet (line 81) | [Fact]
method TextChanged_CanBeSet (line 89) | [Fact]
method PropertyChanged_Text (line 99) | [Fact]
method PropertyChanged_Placeholder (line 109) | [Fact]
method PropertyChanged_TextColor (line 119) | [Fact]
method PropertyChanged_SearchButtonPressed (line 129) | [Fact]
method PropertyChanged_PlaceholderColor (line 139) | [Fact]
method PropertyChanged_TextChanged (line 149) | [Fact]
FILE: tests/Spice.Tests/SliderTests.cs
class SliderTests (line 6) | public class SliderTests
method DefaultValues (line 8) | [Fact]
method SetMinimum (line 18) | [Fact]
method SetMaximum (line 26) | [Fact]
method SetValue (line 34) | [Fact]
method SetValueWithRange (line 42) | [Fact]
method ValueChangedEvent (line 56) | [Fact]
method PropertyChangedFires (line 67) | [Fact]
FILE: tests/Spice.Tests/StackLayoutTests.cs
class StackLayoutTests (line 6) | public class StackLayoutTests
method CanCreate (line 8) | [Fact]
method StackLayoutInheritsFromView (line 15) | [Fact]
method DefaultOrientationIsVertical (line 22) | [Fact]
method DefaultSpacingIsZero (line 29) | [Fact]
method CanSetOrientation (line 36) | [Fact]
method CanSetSpacing (line 46) | [Fact]
method DefaultPaddingIsZero (line 56) | [Fact]
method CanSetPadding (line 63) | [Fact]
method PropertyChangedFiresOnPaddingChange (line 73) | [Fact]
method CanAddChildren (line 85) | [Fact]
method CanRemoveChildren (line 100) | [Fact]
method CanClearChildren (line 113) | [Fact]
method PropertyChangedFiresOnOrientationChange (line 126) | [Fact]
method PropertyChangedFiresOnSpacingChange (line 138) | [Fact]
method CanSetAllPropertiesAtOnce (line 150) | [Fact]
method NegativeSpacingIsAllowed (line 163) | [Fact]
FILE: tests/Spice.Tests/SwipeItemsTests.cs
class SwipeItemsTests (line 7) | public class SwipeItemsTests
method SwipeItemsCanBeCreated (line 9) | [Fact]
method ItemsCollectionIsInitialized (line 16) | [Fact]
method ModeDefaultsToReveal (line 24) | [Fact]
method SwipeBehaviorOnInvokedDefaultsToAuto (line 31) | [Fact]
method ModeCanBeSet (line 38) | [Fact]
method SwipeBehaviorOnInvokedCanBeSet (line 45) | [Fact]
method CanAddItemsToCollection (line 52) | [Fact]
method ConstructorWithItemsCollectionWorks (line 64) | [Fact]
method ConstructorWithNullItemsThrows (line 78) | [Fact]
method PropertyChangedFiresOnModeChange (line 84) | [Fact]
method PropertyChangedFiresOnSwipeBehaviorOnInvokedChange (line 99) | [Fact]
method ConstructorWithEmptyCollectionWorks (line 114) | [Fact]
FILE: tests/Spice.Tests/SwipeViewTests.cs
class SwipeViewTests (line 6) | public class SwipeViewTests
method CanCreate (line 8) | [Fact]
method ContentIsNullByDefault (line 15) | [Fact]
method CanSetContent (line 22) | [Fact]
method SwipeItemsAreNullByDefault (line 34) | [Fact]
method CanSetLeftItems (line 44) | [Fact]
method CanSetRightItems (line 57) | [Fact]
method CanSetTopItems (line 70) | [Fact]
method CanSetBottomItems (line 83) | [Fact]
method SwipeItemHasDefaultProperties (line 96) | [Fact]
method CanSetSwipeItemProperties (line 107) | [Fact]
method SwipeItemInvokedFiresAction (line 122) | [Fact]
method SwipeItemsHasDefaultMode (line 137) | [Fact]
method SwipeItemsHasDefaultBehavior (line 144) | [Fact]
method CanSetSwipeItemsMode (line 151) | [Fact]
method CanSetSwipeItemsBehavior (line 158) | [Fact]
method CanCreateSwipeItemsWithCollection (line 165) | [Fact]
method ThresholdDefaultsToZero (line 181) | [Fact]
method CanSetThreshold (line 188) | [Fact]
method PropertyChangedFiresOnContentChange (line 195) | [Fact]
method PropertyChangedFiresOnLeftItemsChange (line 208) | [Fact]
method CanContainComplexContent (line 220) | [Fact]
method SwipeViewCanBeNestedInOtherViews (line 237) | [Fact]
method MultipleSwipeViewsCanExist (line 253) | [Fact]
FILE: tests/Spice.Tests/SwitchTests.cs
class SwitchTests (line 6) | public class SwitchTests
method SwitchCreation (line 8) | [Fact]
method IsOnPropertyWorks (line 16) | [Fact]
method IsOnPropertyChangedEvent (line 23) | [Fact]
method ToggledActionWorks (line 35) | [Fact]
method ToggledActionCanBeCleared (line 45) | [Fact]
method SwitchInheritsFromView (line 57) | [Fact]
FILE: tests/Spice.Tests/TabViewTests.cs
class TabViewTests (line 6) | public class TabViewTests
class TestView (line 8) | class TestView : View
method TestView (line 10) | public TestView()
class SecondView (line 16) | class SecondView : View
method SecondView (line 18) | public SecondView()
method TabViewCanBeCreated (line 24) | [Fact]
method TabViewInheritsFromView (line 31) | [Fact]
method TabCanBeCreated (line 38) | [Fact]
method TabInheritsFromView (line 46) | [Fact]
method TabGenericCanBeCreated (line 54) | [Fact]
method TabGenericInheritsFromTab (line 61) | [Fact]
method TabTitleIsSet (line 68) | [Fact]
method TabIconIsSet (line 76) | [Fact]
method TabContentIsSet (line 84) | [Fact]
method TabWithFactoryCreatesContentLazily (line 92) | [Fact]
method TabGenericCreatesContentLazily (line 112) | [Fact]
method TabViewAddMethodWorks (line 126) | [Fact]
method TabViewCollectionInitializerWorks (line 138) | [Fact]
method TabConstructorWithNullTitleThrows (line 150) | [Fact]
method TabConstructorWithNullIconThrows (line 157) | [Fact]
method TabConstructorWithNullContentThrows (line 164) | [Fact]
method TabConstructorWithNullFactoryThrows (line 170) | [Fact]
method TabViewAddWithNullThrows (line 176) | [Fact]
method PropertyChangedFiresOnIconChange (line 183) | [Fact]
method EnsureContentOnlyCreatesContentOnce (line 199) | [Fact]
method TabContentAddsToChildren (line 216) | [Fact]
FILE: tests/Spice.Tests/TestViewModel.cs
class TestViewModel (line 8) | internal class TestViewModel : System.ComponentModel.INotifyPropertyChanged
FILE: tests/Spice.Tests/ThemeTests.cs
class ThemeTests (line 8) | public class ThemeTests
method ThemeCanBeCreated (line 11) | [Fact]
method ThemeDefaultsToNull (line 18) | [Fact]
method ThemeLightHasExpectedColors (line 29) | [Fact]
method ThemeDarkHasExpectedColors (line 40) | [Fact]
method ThemeFiresPropertyChanged (line 51) | [Fact]
method ApplicationThemeDefaultsToNull (line 62) | [Fact]
method ThemeAppliesBackgroundColorToView (line 69) | [Fact]
method ThemeAppliesTextColorToLabel (line 80) | [Fact]
method ThemeAppliesTextColorAndAccentToButton (line 92) | [Fact]
method ThemeAppliesStrokeColorToBorder (line 105) | [Fact]
method ThemeAppliesTextColorToEntry (line 117) | [Fact]
method ThemeAppliesTextAndPlaceholderColorToEditor (line 128) | [Fact]
method ThemeAppliesTextAndPlaceholderColorToSearchBar (line 140) | [Fact]
method ThemeAppliesTextColorToDatePicker (line 152) | [Fact]
method ThemeAppliesTextColorToPicker (line 163) | [Fact]
method ThemeAppliesAccentColorToActivityIndicator (line 174) | [Fact]
method ThemeAppliedToEntireTree (line 185) | [Fact]
method ThemeAppliedWhenMainSetAfterTheme (line 200) | [Fact]
method SwappingThemeUpdatesAllViews (line 211) | [Fact]
method LiveThemePropertyChangeUpdatesViews (line 227) | [Fact]
method NullThemeDoesNotChangeColors (line 243) | [Fact]
method SettingThemeToNullDoesNotCrash (line 254) | [Fact]
method ExplicitTextColorWins (line 265) | [Fact]
method ExplicitBackgroundColorWins (line 277) | [Fact]
method ExplicitStrokeColorWins (line 288) | [Fact]
method ExplicitButtonBackgroundColorWins (line 299) | [Fact]
method ExplicitActivityIndicatorColorWins (line 310) | [Fact]
method NullResetsToThemeColor (line 321) | [Fact]
method ExplicitOverrideSurvivesThemeSwap (line 338) | [Fact]
method ExplicitSetAfterThemeIsRespected (line 352) | [Fact]
method NewChildrenGetThemed (line 371) | [Fact]
method NestedDynamicChildrenGetThemed (line 387) | [Fact]
method UseSystemThemeSetsTheme (line 406) | [Fact]
method ExplicitThemeDisablesUseSystemTheme (line 419) | [Fact]
method PlatformAppearanceChangedUpdatesTheme (line 431) | [Fact]
method AppearanceChangedCallbackInvoked (line 450) | [Fact]
method CustomThemeApplied (line 468) | [Fact]
method FullScenarioFromSpec (line 495) | [Fact]
FILE: tests/Spice.Tests/ThicknessTests.cs
class ThicknessTests (line 6) | public class ThicknessTests
method DefaultConstructor (line 8) | [Fact]
method UniformConstructor (line 18) | [Fact]
method HorizontalVerticalConstructor (line 28) | [Fact]
method IndividualSidesConstructor (line 38) | [Fact]
method HorizontalThickness (line 48) | [Fact]
method VerticalThickness (line 55) | [Fact]
method IsEmptyWhenAllZero (line 62) | [Fact]
method IsNotEmptyWhenAnyNonZero (line 69) | [Fact]
method ImplicitConversionFromDouble (line 78) | [Fact]
method EqualityOperator (line 88) | [Fact]
method InequalityOperator (line 99) | [Fact]
method EqualsMethod (line 110) | [Fact]
method EqualsObjectMethod (line 121) | [Fact]
method GetHashCodeConsistent (line 135) | [Fact]
method ToStringUniform (line 144) | [Fact]
method ToStringHorizontalVertical (line 151) | [Fact]
method ToStringIndividual (line 158) | [Fact]
method PropertiesCanBeSet (line 165) | [Fact]
FILE: tests/Spice.Tests/TimePickerTests.cs
class TimePickerTests (line 6) | public class TimePickerTests
method TimePickerDefaultTime (line 8) | [Fact]
method TimePickerSetTime (line 16) | [Fact]
method TimePickerPropertyChanged (line 26) | [Fact]
method TimePickerPropertyChanging (line 39) | [Fact]
method TimePickerTimeSpanConversion (line 52) | [Fact]
FILE: tests/Spice.Tests/TwoWayBindingExtensionsTests.cs
class TwoWayBindingExtensionsTests (line 6) | public class TwoWayBindingExtensionsTests
method BindTwoWay_SyncsInitialValue (line 8) | [Fact]
method BindTwoWay_UpdatesTargetWhenSourceChanges (line 25) | [Fact]
method BindTwoWay_UpdatesSourceWhenTargetChanges (line 43) | [Fact]
method BindTwoWay_PreventsInfiniteLoop (line 61) | [Fact]
method BindTwoWay_DoesNotUpdateForOtherProperties (line 100) | [Fact]
method BindTwoWay_DisposalStopsUpdates (line 118) | [Fact]
method BindTwoWay_MultipleDisposalsSafe (line 139) | [Fact]
method BindTwoWay_WorksWithValueTypes (line 156) | [Fact]
method BindTwoWay_WorksWithBooleans (line 181) | [Fact]
method BindTwoWay_ThrowsOnNullSource (line 206) | [Fact]
method BindTwoWay_ThrowsOnNullTarget (line 221) | [Fact]
method BindTwoWay_ThrowsOnNullPropertyNames (line 236) | [Fact]
method BindTwoWay_ThrowsOnNullGettersOrSetters (line 258) | [Fact]
method BindTwoWay_SupportsChainedUpdates (line 294) | [Fact]
FILE: tests/Spice.Tests/ViewLifecycleTests.cs
class ViewLifecycleTests (line 6) | public class ViewLifecycleTests
class DisposableView (line 11) | private class DisposableView : View, IDisposable
method Dispose (line 15) | public void Dispose()
class NonDisposableView (line 24) | private class NonDisposableView : View
method NonDisposableViewDoesNotThrowWhenDisposedRecursively (line 28) | [Fact]
method DisposableViewIsDisposedWhenCallingDisposeRecursive (line 37) | [Fact]
method ChildViewsAreDisposedRecursively (line 48) | [Fact]
method NestedChildViewsAreDisposedRecursively (line 69) | [Fact]
method MixedDisposableAndNonDisposableChildrenAreHandled (line 86) | [Fact]
method ChildrenAreDisposedBeforeParent (line 103) | [Fact]
method MultipleChildrenAreDisposedInOrder (line 120) | [Fact]
method ViewWithNoChildrenIsDisposed (line 145) | [Fact]
method DoubleDisposeDoesNotThrow (line 155) | [Fact]
method CollectionViewDisposesItemViews (line 166) | [Fact]
method CollectionViewTracksAllCreatedViews (line 193) | [Fact]
class DisposableViewWithCallback (line 218) | private class DisposableViewWithCallback : View, IDisposable
method DisposableViewWithCallback (line 223) | public DisposableViewWithCallback(string name, List<string> disposal...
method Dispose (line 229) | public void Dispose()
FILE: tests/Spice.Tests/ViewOpacityTests.cs
class ViewOpacityTests (line 6) | public class ViewOpacityTests
method OpacityDefaultsToOne (line 8) | [Fact]
method OpacityCanBeSetToZero (line 15) | [Fact]
method OpacityCanBeSetToHalf (line 25) | [Fact]
method OpacityCanBeSetToOne (line 35) | [Fact]
method OpacityPropertyChangedEventFires (line 45) | [Fact]
method OpacityWorksOnButton (line 57) | [Fact]
method OpacityWorksOnLabel (line 69) | [Fact]
method OpacityWorksOnBoxView (line 81) | [Fact]
method OpacityWorksOnActivityIndicator (line 93) | [Fact]
method CanToggleOpacity (line 105) | [Fact]
method OpacityWorksInStackLayout (line 121) | [Fact]
method OpacityWorksWithMultipleControls (line 137) | [Fact]
method OpacityCanBeSetAfterCreation (line 149) | [Fact]
method OpacityWorksInContentView (line 159) | [Fact]
method OpacityBelowZeroIsClampedToZero (line 171) | [Fact]
method OpacityAboveOneIsClampedToOne (line 181) | [Fact]
FILE: tests/Spice.Tests/ViewSizeTests.cs
class ViewSizeTests (line 6) | public class ViewSizeTests
method WidthRequestDefaultsToNegativeOne (line 8) | [Fact]
method HeightRequestDefaultsToNegativeOne (line 15) | [Fact]
method WidthRequestCanBeSet (line 22) | [Fact]
method HeightRequestCanBeSet (line 32) | [Fact]
method WidthRequestCanBeSetToZero (line 42) | [Fact]
method HeightRequestCanBeSetToZero (line 52) | [Fact]
method WidthRequestPropertyChangedEventFires (line 62) | [Fact]
method HeightRequestPropertyChangedEventFires (line 74) | [Fact]
method WidthRequestWorksOnButton (line 86) | [Fact]
method HeightRequestWorksOnButton (line 98) | [Fact]
method WidthRequestWorksOnLabel (line 110) | [Fact]
method HeightRequestWorksOnLabel (line 122) | [Fact]
method WidthRequestWorksOnBoxView (line 134) | [Fact]
method HeightRequestWorksOnBoxView (line 145) | [Fact]
method CanToggleWidthRequest (line 156) | [Fact]
method CanToggleHeightRequest (line 169) | [Fact]
method WidthRequestWorksInStackLayout (line 182) | [Fact]
method HeightRequestWorksInStackLayout (line 198) | [Fact]
method WidthAndHeightRequestWorkTogether (line 214) | [Fact]
method SizeRequestsWorkWithVisibility (line 226) | [Fact]
method SizeRequestsWorkWithAlignment (line 240) | [Fact]
method WidthAndHeightPropertiesExist (line 256) | [Fact]
method WidthAndHeightWorkOnButton (line 270) | [Fact]
method WidthAndHeightWorkOnLabel (line 286) | [Fact]
method SettingWidthRequestWithHorizontalOptionsFill (line 302) | [Fact]
method SettingHeightRequestWithVerticalOptionsFill (line 316) | [Fact]
method ChangingAlignmentAfterSizeRequestsAreSetKeepsRequests (line 330) | [Fact]
FILE: tests/Spice.Tests/ViewTests.cs
class ViewTests (line 6) | public class ViewTests
method ViewCanBeCreated (line 8) | [Fact]
method ChildrenCollectionIsInitialized (line 15) | [Fact]
method HorizontalOptionsDefaultsToStart (line 23) | [Fact]
method VerticalOptionsDefaultsToStart (line 30) | [Fact]
method BackgroundColorDefaultsToNull (line 37) | [Fact]
method IsVisibleDefaultsToTrue (line 44) | [Fact]
method IsEnabledDefaultsToTrue (line 51) | [Fact]
method OpacityDefaultsToOne (line 58) | [Fact]
method MarginDefaultsToZero (line 65) | [Fact]
method WidthRequestDefaultsToNegativeOne (line 76) | [Fact]
method HeightRequestDefaultsToNegativeOne (line 83) | [Fact]
method CanSetHorizontalOptions (line 90) | [Fact]
method CanSetVerticalOptions (line 97) | [Fact]
method CanSetBackgroundColor (line 104) | [Fact]
method CanSetIsVisible (line 112) | [Fact]
method CanSetIsEnabled (line 119) | [Fact]
method CanSetOpacity (line 126) | [Fact]
method CanSetMargin (line 133) | [Fact]
method CanSetWidthRequest (line 143) | [Fact]
method CanSetHeightRequest (line 150) | [Fact]
method PropertyChangedFiresOnHorizontalOptionsChange (line 157) | [Fact]
method PropertyChangedFiresOnVerticalOptionsChange (line 172) | [Fact]
method PropertyChangedFiresOnBackgroundColorChange (line 187) | [Fact]
method PropertyChangedFiresOnIsVisibleChange (line 202) | [Fact]
method PropertyChangedFiresOnIsEnabledChange (line 217) | [Fact]
method PropertyChangedFiresOnOpacityChange (line 232) | [Fact]
method PropertyChangedFiresOnMarginChange (line 247) | [Fact]
method PropertyChangedFiresOnWidthRequestChange (line 262) | [Fact]
method PropertyChangedFiresOnHeightRequestChange (line 277) | [Fact]
method CanAddChildToView (line 292) | [Fact]
method CanAddMultipleChildren (line 304) | [Fact]
method CanRemoveChild (line 322) | [Fact]
method AddMethodWorksForCollectionInitializer (line 335) | [Fact]
method ViewIsEnumerable (line 347) | [Fact]
method CanSetAllPropertiesAtOnce (line 368) | [Fact]
FILE: tests/Spice.Tests/ViewVisibilityTests.cs
class ViewVisibilityTests (line 6) | public class ViewVisibilityTests
method IsVisibleDefaultsToTrue (line 8) | [Fact]
method IsEnabledDefaultsToTrue (line 15) | [Fact]
method IsVisibleCanBeSetToFalse (line 22) | [Fact]
method IsEnabledCanBeSetToFalse (line 32) | [Fact]
method IsVisiblePropertyChangedEventFires (line 42) | [Fact]
method IsEnabledPropertyChangedEventFires (line 54) | [Fact]
method IsVisibleWorksOnButton (line 66) | [Fact]
method IsEnabledWorksOnButton (line 78) | [Fact]
method IsVisibleWorksOnLabel (line 90) | [Fact]
method IsEnabledWorksOnLabel (line 102) | [Fact]
method IsVisibleWorksOnActivityIndicator (line 114) | [Fact]
method IsEnabledWorksOnActivityIndicator (line 126) | [Fact]
method CanToggleIsVisible (line 138) | [Fact]
method CanToggleIsEnabled (line 151) | [Fact]
method IsVisibleWorksInStackLayout (line 164) | [Fact]
method IsEnabledWorksInStackLayout (line 180) | [Fact]
FILE: tests/Spice.Tests/WebViewTests.cs
class WebViewTests (line 7) | public class WebViewTests
method WebViewCanBeCreated (line 9) | [Fact]
method WebViewInheritsFromView (line 16) | [Fact]
method SourcePropertyDefaultsToEmptyString (line 23) | [Fact]
method SourcePropertyCanBeSet (line 30) | [Fact]
method IsJavaScriptEnabledDefaultsToTrue (line 37) | [Fact]
method IsJavaScriptEnabledCanBeSet (line 44) | [Fact]
method PropertyChangedFiresOnSourceChange (line 51) | [Fact]
method PropertyChangedFiresOnIsJavaScriptEnabledChange (line 66) | [Fact]
method CanSetAllPropertiesAtOnce (line 81) | [Fact]
method SourceCanBeSetMultipleTimes (line 94) | [Fact]
method MultipleWebViewInstancesAreIndependent (line 104) | [Fact]
Condensed preview — 358 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,591K chars).
[
{
"path": ".config/dotnet-tools.json",
"chars": 352,
"preview": "{\n \"version\": 1,\n \"isRoot\": true,\n \"tools\": {\n \"androidsdk.tool\": {\n \"version\": \"0.25.0\",\n \"commands\": ["
},
{
"path": ".editorconfig",
"chars": 17234,
"preview": "root = true\n\n# All files\n[*]\nindent_style = tab\n\n# Xml files\n[*.xml]\nindent_style = space\nindent_size = 2\n\n# C# files\n[*"
},
{
"path": ".gitattributes",
"chars": 66,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto\n"
},
{
"path": ".github/copilot-instructions.md",
"chars": 3436,
"preview": "# Spice 🌶 — Copilot Instructions\n\nMinimal cross-platform mobile UI framework for .NET (iOS + Android). **No** `Microsoft"
},
{
"path": ".github/dependabot.yml",
"chars": 308,
"preview": "# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repositor"
},
{
"path": ".github/workflows/copilot-setup-steps.yml",
"chars": 668,
"preview": "name: \"Copilot Setup Steps\"\n\non:\n workflow_dispatch:\n push:\n paths:\n - .github/workflows/copilot-setup-steps.y"
},
{
"path": ".github/workflows/spice.yml",
"chars": 8247,
"preview": "name: build\n\non:\n push:\n branches: [ \"main\" ]\n pull_request:\n branches: [ \"main\" ]\n\njobs:\n\n build:\n\n runs-on"
},
{
"path": ".gitignore",
"chars": 6888,
"preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
},
{
"path": ".vscode/settings.json",
"chars": 45,
"preview": "{\n \"dotnet.defaultSolution\": \"spice.sln\"\n}"
},
{
"path": "Directory.Build.props",
"chars": 829,
"preview": "<Project>\n <PropertyGroup>\n <!-- Projects have to opt in -->\n <IsPackable>false</IsPackable>\n <Version>0.2.0</"
},
{
"path": "Directory.Build.targets",
"chars": 292,
"preview": "<Project>\n <PropertyGroup>\n <!-- Weird fix for VS Mac -->\n <CreatePackage Condition=\" '$(TargetFramework)' == 'ne"
},
{
"path": "LICENSE",
"chars": 1073,
"preview": "MIT License\n\nCopyright (c) 2023 Jonathan Peppers\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "NuGet.config",
"chars": 313,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n <packageSources>\n <clear />\n <add key=\"nuget\" value=\"http"
},
{
"path": "README.md",
"chars": 11732,
"preview": "# Spice 🌶, a spicy cross-platform UI framework!\n\nA prototype (and design) of API minimalism for mobile.\n\nIf you like thi"
},
{
"path": "docs/DATA-BINDING-SPEC.md",
"chars": 10041,
"preview": "# Data-Binding in Spice 🌶\n\n**Status:** Design Specification \n**Created:** February 2026\n\n## Overview\n\nSpice views alrea"
},
{
"path": "docs/MAUI-CONTROLS-COMPARISON.md",
"chars": 19102,
"preview": "# .NET MAUI Controls vs Spice Implementation Status\n\nThis document compares the stable/supported controls from .NET MAUI"
},
{
"path": "docs/NAVIGATION-SPEC.md",
"chars": 7634,
"preview": "# Navigation in Spice 🌶\n\nThree new views and two methods on `Application`. That's it.\n\n## Overview\n\n| Type | What it doe"
},
{
"path": "docs/THEME-SPEC.md",
"chars": 19589,
"preview": "# Themes in Spice 🌶\n\n**Status:** Implemented \n**Created:** February 2026\n\n## Overview\n\nSpice provides a built-in `Theme"
},
{
"path": "docs/VIEW-LIFECYCLE-SPEC.md",
"chars": 8553,
"preview": "# View Lifecycle & Cleanup in Spice 🌶\n\n**Status:** Design Specification \n**Created:** February 2026\n\n## Overview\n\nSpice"
},
{
"path": "global.json",
"chars": 69,
"preview": "{\n \"msbuild-sdks\": {\n \"Microsoft.Build.NoTargets\": \"3.7.56\"\n }\n}"
},
{
"path": "samples/HeadToHeadMaui/App.xaml",
"chars": 669,
"preview": "<?xml version = \"1.0\" encoding = \"UTF-8\" ?>\n<Application xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\n "
},
{
"path": "samples/HeadToHeadMaui/App.xaml.cs",
"chars": 146,
"preview": "namespace HeadToHeadMaui;\n\npublic partial class App : Application\n{\n\tpublic App()\n\t{\n\t\tInitializeComponent();\n\n\t\tMainPa"
},
{
"path": "samples/HeadToHeadMaui/AppShell.xaml",
"chars": 420,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<Shell\n x:Class=\"HeadToHeadMaui.AppShell\"\n xmlns=\"http://schemas.microsoft"
},
{
"path": "samples/HeadToHeadMaui/AppShell.xaml.cs",
"chars": 120,
"preview": "namespace HeadToHeadMaui;\n\npublic partial class AppShell : Shell\n{\n\tpublic AppShell()\n\t{\n\t\tInitializeComponent();\n\t}\n}\n"
},
{
"path": "samples/HeadToHeadMaui/HeadToHeadMaui.csproj",
"chars": 2872,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<TargetFrameworks>net10.0-android;net10.0-ios</TargetFrameworks>\n"
},
{
"path": "samples/HeadToHeadMaui/HeadToHeadMaui.sln",
"chars": 1270,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.3161"
},
{
"path": "samples/HeadToHeadMaui/MainPage.xaml",
"chars": 1262,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<ContentPage xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\n "
},
{
"path": "samples/HeadToHeadMaui/MainPage.xaml.cs",
"chars": 391,
"preview": "namespace HeadToHeadMaui;\n\npublic partial class MainPage : ContentPage\n{\n\tint count = 0;\n\n\tpublic MainPage()\n\t{\n\t\tIniti"
},
{
"path": "samples/HeadToHeadMaui/MauiProgram.cs",
"chars": 460,
"preview": "using Microsoft.Extensions.Logging;\n\nnamespace HeadToHeadMaui;\n\npublic static class MauiProgram\n{\n\tpublic static MauiAp"
},
{
"path": "samples/HeadToHeadMaui/Platforms/Android/AndroidManifest.xml",
"chars": 417,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<applicat"
},
{
"path": "samples/HeadToHeadMaui/Platforms/Android/MainActivity.cs",
"chars": 401,
"preview": "using Android.App;\nusing Android.Content.PM;\nusing Android.OS;\n\nnamespace HeadToHeadMaui;\n\n[Activity(Theme = \"@style/Ma"
},
{
"path": "samples/HeadToHeadMaui/Platforms/Android/MainApplication.cs",
"chars": 316,
"preview": "using Android.App;\nusing Android.Runtime;\n\nnamespace HeadToHeadMaui;\n\n[Application]\npublic class MainApplication : Maui"
},
{
"path": "samples/HeadToHeadMaui/Platforms/Android/Resources/values/colors.xml",
"chars": 207,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"colorPrimary\">#512BD4</color>\n <color name=\"color"
},
{
"path": "samples/HeadToHeadMaui/Platforms/MacCatalyst/AppDelegate.cs",
"chars": 206,
"preview": "using Foundation;\n\nnamespace HeadToHeadMaui;\n\n[Register(\"AppDelegate\")]\npublic class AppDelegate : MauiUIApplicationDel"
},
{
"path": "samples/HeadToHeadMaui/Platforms/MacCatalyst/Info.plist",
"chars": 961,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "samples/HeadToHeadMaui/Platforms/MacCatalyst/Program.cs",
"chars": 345,
"preview": "using ObjCRuntime;\nusing UIKit;\n\nnamespace HeadToHeadMaui;\n\npublic class Program\n{\n\t// This is the main entry point of "
},
{
"path": "samples/HeadToHeadMaui/Platforms/Tizen/Main.cs",
"chars": 290,
"preview": "using System;\nusing Microsoft.Maui;\nusing Microsoft.Maui.Hosting;\n\nnamespace HeadToHeadMaui;\n\nclass Program : MauiApplic"
},
{
"path": "samples/HeadToHeadMaui/Platforms/Tizen/tizen-manifest.xml",
"chars": 741,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"maui-application-id-placeholder\" version=\"0.0.0\" api-version="
},
{
"path": "samples/HeadToHeadMaui/Platforms/Windows/App.xaml",
"chars": 310,
"preview": "<maui:MauiWinUIApplication\n x:Class=\"HeadToHeadMaui.WinUI.App\"\n xmlns=\"http://schemas.microsoft.com/winfx/2006/xa"
},
{
"path": "samples/HeadToHeadMaui/Platforms/Windows/App.xaml.cs",
"chars": 697,
"preview": "using Microsoft.UI.Xaml;\n\n// To learn more about WinUI, the WinUI project structure,\n// and more about our project temp"
},
{
"path": "samples/HeadToHeadMaui/Platforms/Windows/Package.appxmanifest",
"chars": 1815,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Package\n xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows1"
},
{
"path": "samples/HeadToHeadMaui/Platforms/Windows/app.manifest",
"chars": 734,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n <asse"
},
{
"path": "samples/HeadToHeadMaui/Platforms/iOS/AppDelegate.cs",
"chars": 206,
"preview": "using Foundation;\n\nnamespace HeadToHeadMaui;\n\n[Register(\"AppDelegate\")]\npublic class AppDelegate : MauiUIApplicationDel"
},
{
"path": "samples/HeadToHeadMaui/Platforms/iOS/Info.plist",
"chars": 1001,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "samples/HeadToHeadMaui/Platforms/iOS/Program.cs",
"chars": 345,
"preview": "using ObjCRuntime;\nusing UIKit;\n\nnamespace HeadToHeadMaui;\n\npublic class Program\n{\n\t// This is the main entry point of "
},
{
"path": "samples/HeadToHeadMaui/Properties/launchSettings.json",
"chars": 121,
"preview": "{\n \"profiles\": {\n \"Windows Machine\": {\n \"commandName\": \"MsixPackage\",\n \"nativeDebugging\": false\n }\n }\n"
},
{
"path": "samples/HeadToHeadMaui/Resources/Raw/AboutAssets.txt",
"chars": 639,
"preview": "Any raw assets you want to be deployed with your application can be placed in\nthis directory (and child directories). D"
},
{
"path": "samples/HeadToHeadMaui/Resources/Styles/Colors.xaml",
"chars": 2234,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<?xaml-comp compile=\"true\" ?>\n<ResourceDictionary \n xmlns=\"http://schemas.mi"
},
{
"path": "samples/HeadToHeadMaui/Resources/Styles/Styles.xaml",
"chars": 23183,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<?xaml-comp compile=\"true\" ?>\n<ResourceDictionary \n xmlns=\"http://schemas.mi"
},
{
"path": "samples/HeadToHeadSpice/App.cs",
"chars": 551,
"preview": "namespace HeadToHeadSpice;\n\n/// <summary>\n/// NOTE: this app is for comparing head-to-head `dotnet new maui`\n/// </summ"
},
{
"path": "samples/HeadToHeadSpice/GlobalUsings.cs",
"chars": 59,
"preview": "global using Microsoft.Maui.Graphics;\nglobal using Spice;\n"
},
{
"path": "samples/HeadToHeadSpice/HeadToHeadSpice.csproj",
"chars": 2120,
"preview": "<Project>\n\n\t<Import Project=\"../../src/Spice/MSBuild/Spice.props\" />\n\t<Import Sdk=\"Microsoft.NET.Sdk\" Project=\"Sdk.props"
},
{
"path": "samples/HeadToHeadSpice/Platforms/Android/AndroidManifest.xml",
"chars": 417,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<applicat"
},
{
"path": "samples/HeadToHeadSpice/Platforms/Android/MainActivity.cs",
"chars": 334,
"preview": "using Android.App;\nusing Android.OS;\n\nnamespace HeadToHeadSpice;\n\n[Activity(\n\tTheme = \"@style/Theme.Material3.Light.NoA"
},
{
"path": "samples/HeadToHeadSpice/Platforms/iOS/AppDelegate.cs",
"chars": 184,
"preview": "using Foundation;\n\nnamespace HeadToHeadSpice;\n\n[Register(\"AppDelegate\")]\npublic class AppDelegate : SpiceAppDelegate\n{\n"
},
{
"path": "samples/HeadToHeadSpice/Platforms/iOS/Info.plist",
"chars": 1434,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "samples/HeadToHeadSpice/Platforms/iOS/Program.cs",
"chars": 90,
"preview": "using UIKit;\nusing HeadToHeadSpice;\n\nUIApplication.Main(args, null, typeof(AppDelegate));"
},
{
"path": "samples/README.md",
"chars": 183,
"preview": "# Samples\n\n* `Spice.Scenarios` - first sample to get things working, may get renamed\n* `HeadToHeadMaui` - for comparing "
},
{
"path": "samples/Spice.BlazorSample/App.cs",
"chars": 263,
"preview": "namespace Spice.BlazorSample;\n\npublic class App : Application\n{\n\tpublic App()\n\t{\n\t\tMain = new BlazorWebView\n\t\t{\n\t\t\tHost"
},
{
"path": "samples/Spice.BlazorSample/GlobalUsings.cs",
"chars": 59,
"preview": "global using Microsoft.Maui.Graphics;\nglobal using Spice;\n"
},
{
"path": "samples/Spice.BlazorSample/Main.razor",
"chars": 341,
"preview": "<Router AppAssembly=\"typeof(Main).Assembly\">\n <Found Context=\"routeData\">\n <RouteView RouteData=\"routeData\" De"
},
{
"path": "samples/Spice.BlazorSample/Pages/Index.razor",
"chars": 71,
"preview": "@page \"/\"\n\n<h1>Hello, Spice + Blazor 🌶!</h1>\n\nWelcome to your new app."
},
{
"path": "samples/Spice.BlazorSample/Platforms/Android/AndroidManifest.xml",
"chars": 417,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<applicat"
},
{
"path": "samples/Spice.BlazorSample/Platforms/Android/MainActivity.cs",
"chars": 404,
"preview": "using Android.App;\nusing Android.OS;\n\nnamespace Spice.BlazorSample;\n\n[Activity(\n\t// TODO: fix splash theme\n\t// Theme = "
},
{
"path": "samples/Spice.BlazorSample/Platforms/iOS/AppDelegate.cs",
"chars": 187,
"preview": "using Foundation;\n\nnamespace Spice.BlazorSample;\n\n[Register(\"AppDelegate\")]\npublic class AppDelegate : SpiceAppDelegate"
},
{
"path": "samples/Spice.BlazorSample/Platforms/iOS/Info.plist",
"chars": 1434,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "samples/Spice.BlazorSample/Platforms/iOS/Program.cs",
"chars": 93,
"preview": "using UIKit;\nusing Spice.BlazorSample;\n\nUIApplication.Main(args, null, typeof(AppDelegate));"
},
{
"path": "samples/Spice.BlazorSample/Shared/MainLayout.razor",
"chars": 348,
"preview": "@inherits LayoutComponentBase\n\n<div class=\"page\">\n <div class=\"sidebar\">\n <NavMenu />\n </div>\n\n <main>\n "
},
{
"path": "samples/Spice.BlazorSample/Shared/MainLayout.razor.css",
"chars": 1352,
"preview": ".page {\n position: relative;\n display: flex;\n flex-direction: column;\n}\n\nmain {\n flex: 1;\n}\n\n.sidebar {\n "
},
{
"path": "samples/Spice.BlazorSample/Shared/NavMenu.razor",
"chars": 856,
"preview": "<div class=\"top-row ps-3 navbar navbar-dark\">\n <div class=\"container-fluid\">\n <a class=\"navbar-brand\" href=\"\">"
},
{
"path": "samples/Spice.BlazorSample/Shared/NavMenu.razor.css",
"chars": 1033,
"preview": ".navbar-toggler {\n background-color: rgba(255, 255, 255, 0.1);\n}\n\n.top-row {\n height: 3.5rem;\n background-color"
},
{
"path": "samples/Spice.BlazorSample/Spice.BlazorSample.csproj",
"chars": 2612,
"preview": "<Project>\n\n <Import Sdk=\"Microsoft.NET.Sdk.Razor\" Project=\"Sdk.props\" />\n <Import Project=\"../../src/Spice/MSBuil"
},
{
"path": "samples/Spice.BlazorSample/_Imports.razor",
"chars": 302,
"preview": "@using System.Net.Http\n@using Microsoft.AspNetCore.Components.Forms\n@using Microsoft.AspNetCore.Components.Routing\n@usi"
},
{
"path": "samples/Spice.BlazorSample/wwwroot/css/app.css",
"chars": 3109,
"preview": "@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');\n\nhtml, body {\n font-family: 'Helvetica Neue', Hel"
},
{
"path": "samples/Spice.BlazorSample/wwwroot/css/open-iconic/FONT-LICENSE",
"chars": 4017,
"preview": "SIL OPEN FONT LICENSE Version 1.1\n\nCopyright (c) 2014 Waybury\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to "
},
{
"path": "samples/Spice.BlazorSample/wwwroot/css/open-iconic/ICON-LICENSE",
"chars": 1073,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Waybury\n\nPermission is hereby granted, free of charge, to any person obtaining"
},
{
"path": "samples/Spice.BlazorSample/wwwroot/css/open-iconic/README.md",
"chars": 3538,
"preview": "[Open Iconic v1.1.1](https://github.com/iconic/open-iconic)\n===========\n\n### Open Iconic is the open source sibling of ["
},
{
"path": "samples/Spice.BlazorSample/wwwroot/index.html",
"chars": 795,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-wid"
},
{
"path": "samples/Spice.Scenarios/App.cs",
"chars": 2547,
"preview": "namespace Spice.Scenarios;\n\npublic class App : Application\n{\n\tpublic App()\n\t{\n\t\tUseSystemTheme = true;\n\n\t\tMain = new Na"
},
{
"path": "samples/Spice.Scenarios/GlobalUsings.cs",
"chars": 59,
"preview": "global using Microsoft.Maui.Graphics;\nglobal using Spice;\n"
},
{
"path": "samples/Spice.Scenarios/Platforms/Android/AndroidManifest.xml",
"chars": 417,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<applicat"
},
{
"path": "samples/Spice.Scenarios/Platforms/Android/MainActivity.cs",
"chars": 401,
"preview": "using Android.App;\nusing Android.OS;\n\nnamespace Spice.Scenarios;\n\n[Activity(\n\t// TODO: fix splash theme\n\t// Theme = \"@s"
},
{
"path": "samples/Spice.Scenarios/Platforms/iOS/AppDelegate.cs",
"chars": 184,
"preview": "using Foundation;\n\nnamespace Spice.Scenarios;\n\n[Register(\"AppDelegate\")]\npublic class AppDelegate : SpiceAppDelegate\n{\n"
},
{
"path": "samples/Spice.Scenarios/Platforms/iOS/Info.plist",
"chars": 1434,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "samples/Spice.Scenarios/Platforms/iOS/Program.cs",
"chars": 90,
"preview": "using UIKit;\nusing Spice.Scenarios;\n\nUIApplication.Main(args, null, typeof(AppDelegate));"
},
{
"path": "samples/Spice.Scenarios/Scenarios/ActivityIndicatorScenario.cs",
"chars": 1020,
"preview": "namespace Spice.Scenarios;\n\nclass ActivityIndicatorScenario : StackLayout\n{\n\tpublic ActivityIndicatorScenario()\n\t{\n\t\tTit"
},
{
"path": "samples/Spice.Scenarios/Scenarios/BorderScenario.cs",
"chars": 2254,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Demonstrates the Border control with various configurations\n/// </summary>"
},
{
"path": "samples/Spice.Scenarios/Scenarios/BoxViewScenario.cs",
"chars": 880,
"preview": "namespace Spice.Scenarios;\n\nclass BoxViewScenario : StackLayout\n{\n\tpublic BoxViewScenario()\n\t{\n\t\tTitle = \"Box View\";\n\t\tS"
},
{
"path": "samples/Spice.Scenarios/Scenarios/CheckBoxScenario.cs",
"chars": 1186,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Example showing CheckBox usage\n/// </summary>\nclass CheckBoxScenario : Sta"
},
{
"path": "samples/Spice.Scenarios/Scenarios/CollectionViewScenario.cs",
"chars": 3112,
"preview": "using System.Collections.ObjectModel;\n\nnamespace Spice.Scenarios;\n\n/// <summary>\n/// Scenario demonstrating CollectionVi"
},
{
"path": "samples/Spice.Scenarios/Scenarios/ContentViewScenario.cs",
"chars": 1299,
"preview": "namespace Spice.Scenarios;\n\npublic class ContentViewScenario : Application\n{\n\tpublic ContentViewScenario()\n\t{\n\t\tTitle = "
},
{
"path": "samples/Spice.Scenarios/Scenarios/DatePickerScenario.cs",
"chars": 1241,
"preview": "namespace Spice.Scenarios;\n\nclass DatePickerScenario : StackLayout\n{\n\tpublic DatePickerScenario()\n\t{\n\t\tTitle = \"Date Pic"
},
{
"path": "samples/Spice.Scenarios/Scenarios/EditorScenario.cs",
"chars": 708,
"preview": "namespace Spice.Scenarios;\n\nclass EditorScenario : StackLayout\n{\n\tpublic EditorScenario()\n\t{\n\t\tTitle = \"Editor\";\n\t\tSpaci"
},
{
"path": "samples/Spice.Scenarios/Scenarios/EntryScenario.cs",
"chars": 268,
"preview": "namespace Spice.Scenarios;\n\nclass EntryScenario : StackLayout\n{\n\tpublic EntryScenario()\n\t{\n\t\tTitle = \"Entry\";\n\t\tSpacing"
},
{
"path": "samples/Spice.Scenarios/Scenarios/GhostButtonScenario.cs",
"chars": 627,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// See GhostButton for an example of platform-specific logic\n/// </summary>\n"
},
{
"path": "samples/Spice.Scenarios/Scenarios/HelloWorldScenario.cs",
"chars": 511,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Most basic scenario\n/// NOTE: my color choices are suspect! 🌈🤢\n/// </summ"
},
{
"path": "samples/Spice.Scenarios/Scenarios/ImageButtonScenario.cs",
"chars": 847,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// ImageButton scenario demonstrating clickable image buttons\n/// </summary>\n"
},
{
"path": "samples/Spice.Scenarios/Scenarios/MarginScenario.cs",
"chars": 1501,
"preview": "namespace Spice.Scenarios;\n\nclass MarginScenario : StackLayout\n{\n\tpublic MarginScenario()\n\t{\n\t\tTitle = \"Margin\";\n\t\tSpaci"
},
{
"path": "samples/Spice.Scenarios/Scenarios/PickerScenario.cs",
"chars": 1338,
"preview": "using System.Collections.ObjectModel;\n\nnamespace Spice.Scenarios;\n\nclass PickerScenario : StackLayout\n{\n\tpublic PickerSc"
},
{
"path": "samples/Spice.Scenarios/Scenarios/ProgressBarScenario.cs",
"chars": 1476,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Demonstrates the ProgressBar control with various progress values\n/// </su"
},
{
"path": "samples/Spice.Scenarios/Scenarios/RadioButtonScenario.cs",
"chars": 1163,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Example showing RadioButton usage\n/// </summary>\nclass RadioButtonScenario"
},
{
"path": "samples/Spice.Scenarios/Scenarios/RefreshViewScenario.cs",
"chars": 2270,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Scenario demonstrating RefreshView with pull-to-refresh functionality\n/// "
},
{
"path": "samples/Spice.Scenarios/Scenarios/ScrollViewScenario.cs",
"chars": 562,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Scenario demonstrating ScrollView with a long list of items\n/// </summary>"
},
{
"path": "samples/Spice.Scenarios/Scenarios/SearchBarScenario.cs",
"chars": 595,
"preview": "namespace Spice.Scenarios;\n\nclass SearchBarScenario : StackLayout\n{\n\tpublic SearchBarScenario()\n\t{\n\t\tTitle = \"Search Bar"
},
{
"path": "samples/Spice.Scenarios/Scenarios/SliderScenario.cs",
"chars": 1167,
"preview": "namespace Spice.Scenarios;\n\nclass SliderScenario : StackLayout\n{\n\tpublic SliderScenario()\n\t{\n\t\tTitle = \"Slider\";\n\t\tSpaci"
},
{
"path": "samples/Spice.Scenarios/Scenarios/SwipeViewScenario.cs",
"chars": 3652,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Demonstrates SwipeView with swipe gestures to reveal action items\n/// </su"
},
{
"path": "samples/Spice.Scenarios/Scenarios/SwitchScenario.cs",
"chars": 872,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Demonstrates Switch control usage\n/// </summary>\nclass SwitchScenario : St"
},
{
"path": "samples/Spice.Scenarios/Scenarios/ThemeScenario.cs",
"chars": 963,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Demonstrates theme switching (light/dark) and explicit per-view overrides"
},
{
"path": "samples/Spice.Scenarios/Scenarios/TimePickerScenario.cs",
"chars": 704,
"preview": "namespace Spice.Scenarios;\n\nclass TimePickerScenario : StackLayout\n{\n\tpublic TimePickerScenario()\n\t{\n\t\tTitle = \"Time Pic"
},
{
"path": "samples/Spice.Scenarios/Scenarios/WebViewScenario.cs",
"chars": 219,
"preview": "namespace Spice.Scenarios;\n\n/// <summary>\n/// Scenario navigating a WebView\n/// </summary>\nclass WebViewScenario : WebV"
},
{
"path": "samples/Spice.Scenarios/Spice.Scenarios.csproj",
"chars": 2341,
"preview": "<Project>\n\n <Import Project=\"../../src/Spice/MSBuild/Spice.props\" />\n <Import Sdk=\"Microsoft.NET.Sdk\" Project=\"Sd"
},
{
"path": "samples/samples.slnx",
"chars": 201,
"preview": "<Solution>\n <Project Path=\"Spice.BlazorSample/Spice.BlazorSample.csproj\">\n <Deploy />\n </Project>\n <Project Path=\""
},
{
"path": "sizes/com.companyname.Hello-Signed.apkdesc",
"chars": 86966,
"preview": "{\n \"Comment\": null,\n \"Entries\": {\n \"AndroidManifest.xml\": {\n \"Size\": 6304\n },\n \"classes.dex\": {\n \"S"
},
{
"path": "sizes/com.companyname.HelloBlazor-Signed.apkdesc",
"chars": 90047,
"preview": "{\n \"Comment\": null,\n \"Entries\": {\n \"AndroidManifest.xml\": {\n \"Size\": 6364\n },\n \"assets/wwwroot/_framewor"
},
{
"path": "sizes/startup.md",
"chars": 6038,
"preview": "# Startup times\n\nJust recording these over time. A `Release` build on a Pixel 5 device.\n\nSpice 🌶:\n```log\n06-01 14:43:20."
},
{
"path": "spice.slnx",
"chars": 269,
"preview": "<Solution>\n <Folder Name=\"/src/\">\n <Project Path=\"src/Spice.Templates/Spice.Templates.csproj\" />\n <Project Path=\""
},
{
"path": "src/ProfiledAot/Directory.Build.props",
"chars": 339,
"preview": "<Project>\n <PropertyGroup>\n <Configuration>Release</Configuration>\n <AndroidNeedsInternetPermission>true</Android"
},
{
"path": "src/ProfiledAot/Directory.Build.targets",
"chars": 2396,
"preview": "<Project>\n <PropertyGroup>\n <AndroidPackageFormat>apk</AndroidPackageFormat>\n <AndroidUseDefaultAotProfile>false<"
},
{
"path": "src/ProfiledAot/README.md",
"chars": 715,
"preview": "# Profiled AOT support for Android\n\nThis is based on the NuGet package found here:\n\nhttps://github.com/jonathanpeppers/M"
},
{
"path": "src/ProfiledAot/build.proj",
"chars": 1120,
"preview": "<Project DefaultTargets=\"Record\">\n <PropertyGroup>\n <!-- The template name -->\n <App Condition=\" '$(App)' == '' \""
},
{
"path": "src/ProfiledAot/shared/nuget.config",
"chars": 327,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n <packageSources>\n <clear />\n <add key=\"local\" value=\"..\\."
},
{
"path": "src/Spice/Blazor/BlazorWebView.cs",
"chars": 2722,
"preview": "using System.Collections.Specialized;\nusing System.Collections.ObjectModel;\n\nusing Microsoft.AspNetCore.Components.Web;"
},
{
"path": "src/Spice/Blazor/SpiceDispatcher.cs",
"chars": 159,
"preview": "using Microsoft.AspNetCore.Components;\n\nnamespace Spice;\n\ninternal partial class SpiceDispatcher\n{\n\tpublic static reado"
},
{
"path": "src/Spice/Blazor/SpiceServiceProvider.cs",
"chars": 408,
"preview": "using Microsoft.Extensions.DependencyInjection;\n\nnamespace Spice;\n\n/// <summary>\n/// Implements IServiceProvider to mak"
},
{
"path": "src/Spice/Blazor/UriExtensions.cs",
"chars": 913,
"preview": "// From: https://github.com/dotnet/maui/blob/c8a6093ee805388732af8d75b437b099a301db22/src/BlazorWebView/src/Maui/Extens"
},
{
"path": "src/Spice/Core/ActivityIndicator.cs",
"chars": 818,
"preview": "namespace Spice;\n\n/// <summary>\n/// Represents a loading spinner on screen. Set the IsRunning property to true to show t"
},
{
"path": "src/Spice/Core/Application.cs",
"chars": 2428,
"preview": "using System.ComponentModel;\n\nnamespace Spice;\n\n/// <summary>\n/// The root \"view\" of a Spice application. Set Main to a "
},
{
"path": "src/Spice/Core/BindingExtensions.cs",
"chars": 2554,
"preview": "using System.ComponentModel;\n\nnamespace Spice;\n\n/// <summary>\n/// Extension methods for data-binding support in Spice.\n/"
},
{
"path": "src/Spice/Core/Border.cs",
"chars": 1321,
"preview": "namespace Spice;\n\n/// <summary>\n/// Represents a border around a single child view. Set Content to a View, and customize"
},
{
"path": "src/Spice/Core/BoxView.cs",
"chars": 324,
"preview": "namespace Spice;\n\n/// <summary>\n/// Represents a colored rectangle used for decoration, backgrounds, or dividing lines.\n"
},
{
"path": "src/Spice/Core/Button.cs",
"chars": 913,
"preview": "namespace Spice;\n\n/// <summary>\n/// You know the button! Use the Clicked event.\n/// Android -> Android.Widget.Button\n///"
},
{
"path": "src/Spice/Core/CheckBox.cs",
"chars": 483,
"preview": "namespace Spice;\n\n/// <summary>\n/// A checkbox control for boolean selection.\n/// Android -> Android.Widget.CheckBox\n///"
},
{
"path": "src/Spice/Core/CollectionView.cs",
"chars": 2011,
"preview": "using System.Collections;\n\nnamespace Spice;\n\n/// <summary>\n/// A view for presenting collections of data using a lambda-"
},
{
"path": "src/Spice/Core/ColumnDefinition.cs",
"chars": 630,
"preview": "namespace Spice;\n\n/// <summary>\n/// Defines column-specific properties that apply to Grid elements.\n/// </summary>\npubli"
},
{
"path": "src/Spice/Core/ContentView.cs",
"chars": 976,
"preview": "namespace Spice;\n\n/// <summary>\n/// A container view that holds a single child view via the Content property.\n/// Used f"
},
{
"path": "src/Spice/Core/DatePicker.cs",
"chars": 916,
"preview": "namespace Spice;\n\n/// <summary>\n/// Control for date selection.\n/// Android -> Android.App.DatePickerDialog\n/// iOS -> U"
},
{
"path": "src/Spice/Core/Editor.cs",
"chars": 1516,
"preview": "namespace Spice;\n\n/// <summary>\n/// Control for multi-line text input.\n/// Android -> Android.Widget.EditText (multiline"
},
{
"path": "src/Spice/Core/Entry.cs",
"chars": 831,
"preview": "namespace Spice;\n\n/// <summary>\n/// Control for text input, like a form field.\n/// Android -> Android.Widget.EditText\n/"
},
{
"path": "src/Spice/Core/Grid.cs",
"chars": 3475,
"preview": "using System.Collections.ObjectModel;\n\nnamespace Spice;\n\n/// <summary>\n/// A layout container that arranges child views "
},
{
"path": "src/Spice/Core/GridLength.cs",
"chars": 3065,
"preview": "namespace Spice;\n\n/// <summary>\n/// Represents the length of elements that support GridUnitType-based units (like rows a"
},
{
"path": "src/Spice/Core/GridUnitType.cs",
"chars": 461,
"preview": "namespace Spice;\n\n/// <summary>\n/// Describes the kind of value that a GridLength object is holding.\n/// </summary>\npubl"
},
{
"path": "src/Spice/Core/Image.cs",
"chars": 468,
"preview": "namespace Spice;\n\n/// <summary>\n/// Represents an image on screen. Set the Source property such as \"spice\".\n/// Android"
},
{
"path": "src/Spice/Core/ImageButton.cs",
"chars": 615,
"preview": "namespace Spice;\n\n/// <summary>\n/// A button that displays an image instead of text. Use the Clicked event.\n/// Android "
},
{
"path": "src/Spice/Core/Label.cs",
"chars": 704,
"preview": "namespace Spice;\n\n/// <summary>\n/// Represents text on screen. Set the Text property to a string value.\n/// Android -> A"
},
{
"path": "src/Spice/Core/LayoutAlignment.cs",
"chars": 1065,
"preview": "namespace Spice;\n\n/// <summary>\n/// Values that represent layout alignment.\n/// Maps to UIKit/Android alignment options."
},
{
"path": "src/Spice/Core/LayoutExpandFlag.cs",
"chars": 73,
"preview": "namespace Spice;\n\n[Flags]\ninternal enum LayoutExpandFlag\n{\n\tExpand = 4\n}\n"
},
{
"path": "src/Spice/Core/LayoutOptions.cs",
"chars": 4370,
"preview": "using System;\n\nnamespace Spice;\n\n/// <summary>\n/// A struct whose static members define various alignment and expansion "
},
{
"path": "src/Spice/Core/NavigationView.cs",
"chars": 3036,
"preview": "namespace Spice;\n\n/// <summary>\n/// A view that provides push/pop navigation with a navigation bar.\n/// Platform impleme"
},
{
"path": "src/Spice/Core/Orientation.cs",
"chars": 279,
"preview": "namespace Spice;\n\n/// <summary>\n/// General Orientation enum.\n/// Currently only used by StackLayout.\n/// </summary>\npu"
},
{
"path": "src/Spice/Core/Picker.cs",
"chars": 1511,
"preview": "using System.Collections.ObjectModel;\n\nnamespace Spice;\n\n/// <summary>\n/// Picker control for selecting an item from a l"
},
{
"path": "src/Spice/Core/PlatformAppearance.cs",
"chars": 701,
"preview": "namespace Spice;\n\n/// <summary>\n/// Provides cross-platform access to the system's appearance (light/dark mode).\n/// Pla"
},
{
"path": "src/Spice/Core/ProgressBar.cs",
"chars": 742,
"preview": "namespace Spice;\n\n/// <summary>\n/// Displays a progress indicator showing the completion percentage of a task.\n/// Andro"
},
{
"path": "src/Spice/Core/RadioButton.cs",
"chars": 3204,
"preview": "namespace Spice;\n\n/// <summary>\n/// A radio button control for single selection from a group of options.\n/// Android -> "
},
{
"path": "src/Spice/Core/RefreshView.cs",
"chars": 1648,
"preview": "namespace Spice;\n\n/// <summary>\n/// A container view that provides pull-to-refresh functionality for scrollable content."
},
{
"path": "src/Spice/Core/RootComponent.cs",
"chars": 2451,
"preview": "// From: https://github.com/dotnet/maui/blob/c8a6093ee805388732af8d75b437b099a301db22/src/BlazorWebView/src/Maui/RootCo"
},
{
"path": "src/Spice/Core/RowDefinition.cs",
"chars": 616,
"preview": "namespace Spice;\n\n/// <summary>\n/// Defines row-specific properties that apply to Grid elements.\n/// </summary>\npublic p"
},
{
"path": "src/Spice/Core/ScrollView.cs",
"chars": 717,
"preview": "namespace Spice;\n\n/// <summary>\n/// A scrollable container view that can hold a single child view.\n/// Android -> Androi"
},
{
"path": "src/Spice/Core/SearchBar.cs",
"chars": 1470,
"preview": "namespace Spice;\n\n/// <summary>\n/// Control for search input with a search button.\n/// Android -> Android.Widget.Search"
},
{
"path": "src/Spice/Core/SelectionMode.cs",
"chars": 361,
"preview": "namespace Spice;\n\n/// <summary>\n/// Defines the selection mode for a CollectionView.\n/// </summary>\npublic enum Selectio"
},
{
"path": "src/Spice/Core/Slider.cs",
"chars": 974,
"preview": "namespace Spice;\n\n/// <summary>\n/// A slider control for selecting a numeric value from a range.\n/// Android -> Android."
},
{
"path": "src/Spice/Core/StackLayout.cs",
"chars": 805,
"preview": "namespace Spice;\n\n/// <summary>\n/// A parent view for laying out child controls in a row. Defaults to Orientation=Verti"
},
{
"path": "src/Spice/Core/SwipeBehaviorOnInvoked.cs",
"chars": 490,
"preview": "namespace Spice;\n\n/// <summary>\n/// Defines the behavior of a SwipeView after a swipe item is invoked.\n/// </summary>\npu"
},
{
"path": "src/Spice/Core/SwipeDirection.cs",
"chars": 401,
"preview": "namespace Spice;\n\n/// <summary>\n/// Defines the direction of a swipe gesture.\n/// </summary>\npublic enum SwipeDirection\n"
},
{
"path": "src/Spice/Core/SwipeItem.cs",
"chars": 809,
"preview": "namespace Spice;\n\n/// <summary>\n/// Represents an individual swipe action item that can be invoked.\n/// Each SwipeItem c"
},
{
"path": "src/Spice/Core/SwipeItems.cs",
"chars": 1363,
"preview": "using System.Collections.ObjectModel;\n\nnamespace Spice;\n\n/// <summary>\n/// Represents a collection of SwipeItem objects "
},
{
"path": "src/Spice/Core/SwipeMode.cs",
"chars": 359,
"preview": "namespace Spice;\n\n/// <summary>\n/// Defines the effect of a swipe interaction on SwipeItems.\n/// </summary>\npublic enum "
},
{
"path": "src/Spice/Core/SwipeView.cs",
"chars": 3201,
"preview": "namespace Spice;\n\n/// <summary>\n/// A container control that wraps around an item of content and provides context menu i"
},
{
"path": "src/Spice/Core/Switch.cs",
"chars": 459,
"preview": "namespace Spice;\n\n/// <summary>\n/// A toggle switch control for boolean on/off input.\n/// Android -> AndroidX.AppCompat."
},
{
"path": "src/Spice/Core/TabView.cs",
"chars": 3280,
"preview": "namespace Spice;\n\n/// <summary>\n/// A view that displays bottom tabs for navigation between different content views.\n///"
},
{
"path": "src/Spice/Core/Theme.cs",
"chars": 2005,
"preview": "namespace Spice;\n\n/// <summary>\n/// Defines a set of semantic colors that are auto-applied to views.\n/// Extends Observa"
},
{
"path": "src/Spice/Core/Thickness.cs",
"chars": 3871,
"preview": "namespace Spice;\n\n/// <summary>\n/// Represents the thickness of a frame around a rectangle. Four double values describe "
},
{
"path": "src/Spice/Core/TimePicker.cs",
"chars": 416,
"preview": "namespace Spice;\n\n/// <summary>\n/// Represents a control that allows the user to select a time value.\n/// Android -> And"
},
{
"path": "src/Spice/Core/TwoWayBindingExtensions.cs",
"chars": 4201,
"preview": "using System.ComponentModel;\n\nnamespace Spice;\n\n/// <summary>\n/// Extension methods for two-way data-binding support in "
},
{
"path": "src/Spice/Core/View.cs",
"chars": 9673,
"preview": "using System.Collections;\nusing System.Collections.ObjectModel;\nusing System.Collections.Specialized;\n\nnamespace Spice;\n"
},
{
"path": "src/Spice/Core/WebView.cs",
"chars": 471,
"preview": "namespace Spice;\n\n/// <summary>\n/// A \"web view\" for rendering HTML content on each platform.\n/// Android -> Android.We"
},
{
"path": "src/Spice/GlobalUsings.cs",
"chars": 182,
"preview": "global using CommunityToolkit.Mvvm.ComponentModel;\nglobal using Color = Microsoft.Maui.Graphics.Color;\n\n[assembly: Syst"
},
{
"path": "src/Spice/MSBuild/Spice.Blazor.targets",
"chars": 6362,
"preview": "<!-- From: https://github.com/dotnet/maui/blob/2ccac2d3835d77a6548a7bb70773b5cf22b0f730/src/BlazorWebView/src/Maui/build"
},
{
"path": "src/Spice/MSBuild/Spice.props",
"chars": 686,
"preview": "<Project>\n\t<PropertyGroup>\n\t\t<!-- To attempt XAML hot reload features one day -->\n\t\t<!--<IgnoreMauiXamlHotReloadCompati"
},
{
"path": "src/Spice/MSBuild/Spice.targets",
"chars": 5643,
"preview": "<Project>\n\t<!--\n\t\tInlined from Microsoft.Maui.Controls SingleProject MSBuild logic (previously in Microsoft.Maui.Sdk.ne"
},
{
"path": "src/Spice/MSBuild/spice-blazor.aotprofile.txt",
"chars": 440588,
"preview": "Methods:\n\tAndroid.App.Activity Java.Lang.Object:_GetObject (intptr,Android.Runtime.JniHandleOwnership)\n\tAndroid.App.Acti"
},
{
"path": "src/Spice/MSBuild/spice.aotprofile.txt",
"chars": 68143,
"preview": "Methods:\n\tAndroid.App.Activity Java.Lang.Object:_GetObject (intptr,Android.Runtime.JniHandleOwnership)\n\tAndroid.App.Acti"
},
{
"path": "src/Spice/Platforms/Android/ActivityIndicator.cs",
"chars": 2234,
"preview": "using Android.Content;\nusing AndroidProgressBar = Android.Widget.ProgressBar;\n\nnamespace Spice;\n\npublic partial class Ac"
},
{
"path": "src/Spice/Platforms/Android/Application.cs",
"chars": 851,
"preview": "using Android.Content;\n\nnamespace Spice;\n\npublic partial class Application\n{\n\t/// <summary>\n\t/// The root \"view\" of a Sp"
},
{
"path": "src/Spice/Platforms/Android/Blazor/AndroidAssetFileProvider.cs",
"chars": 3366,
"preview": "// From: https://github.com/dotnet/maui/blob/260fa08b0f75fbbb945375592896dd9eb374f22f/src/BlazorWebView/src/Maui/Androi"
},
{
"path": "src/Spice/Platforms/Android/Blazor/AndroidWebViewManager.cs",
"chars": 4499,
"preview": "// From: https://github.com/dotnet/maui/blob/260fa08b0f75fbbb945375592896dd9eb374f22f/src/BlazorWebView/src/Maui/Androi"
},
{
"path": "src/Spice/Platforms/Android/Blazor/BlazorWebView.cs",
"chars": 2426,
"preview": "using System.Runtime.Versioning;\n\nusing Android.Content;\n\nusing Microsoft.AspNetCore.Components.WebView.Maui;\n\nnamespac"
},
{
"path": "src/Spice/Platforms/Android/Blazor/SpiceBlazorWebViewClient.cs",
"chars": 6137,
"preview": "// From: https://github.com/dotnet/maui/blob/260fa08b0f75fbbb945375592896dd9eb374f22f/src/BlazorWebView/src/Maui/Androi"
},
{
"path": "src/Spice/Platforms/Android/Blazor/SpiceDispatcher.cs",
"chars": 1614,
"preview": "using Android.OS;\n\nusing Microsoft.AspNetCore.Components;\n\nnamespace Spice;\n\ninternal partial class SpiceDispatcher : D"
},
{
"path": "src/Spice/Platforms/Android/Border.cs",
"chars": 3989,
"preview": "using Android.Content;\nusing Android.Content.Res;\nusing Android.Graphics.Drawables;\n\nnamespace Spice;\n\npublic partial cl"
},
{
"path": "src/Spice/Platforms/Android/BoxView.cs",
"chars": 1561,
"preview": "using Android.Content;\n\nnamespace Spice;\n\npublic partial class BoxView\n{\n\t/// <summary>\n\t/// Returns boxView.NativeView\n"
},
{
"path": "src/Spice/Platforms/Android/Button.cs",
"chars": 2015,
"preview": "using Android.Content;\n\nnamespace Spice;\n\npublic partial class Button\n{\n\t/// <summary>\n\t/// Returns button.NativeView\n\t/"
},
{
"path": "src/Spice/Platforms/Android/CheckBox.cs",
"chars": 2195,
"preview": "using Android.Content;\nusing Android.Widget;\nusing AndroidCheckBox = Android.Widget.CheckBox;\n\nnamespace Spice;\n\npublic "
},
{
"path": "src/Spice/Platforms/Android/CollectionView.cs",
"chars": 7304,
"preview": "using Android.Content;\nusing Android.Views;\nusing AndroidX.RecyclerView.Widget;\nusing System.Collections;\nusing System.C"
},
{
"path": "src/Spice/Platforms/Android/ContentView.cs",
"chars": 2029,
"preview": "using Android.Content;\n\nnamespace Spice;\n\npublic partial class ContentView\n{\n\t/// <summary>\n\t/// Returns contentView.Nat"
},
{
"path": "src/Spice/Platforms/Android/DatePicker.cs",
"chars": 2676,
"preview": "using Android.App;\nusing Android.Content;\nusing Android.Widget;\n\nnamespace Spice;\n\npublic partial class DatePicker\n{\n\t//"
},
{
"path": "src/Spice/Platforms/Android/Editor.cs",
"chars": 3213,
"preview": "using Android.Content;\nusing Android.Text;\n\nnamespace Spice;\n\npublic partial class Editor\n{\n\t/// <summary>\n\t/// Returns "
},
{
"path": "src/Spice/Platforms/Android/Entry.cs",
"chars": 1848,
"preview": "using Android.Content;\nusing Android.Text;\n\nnamespace Spice;\n\npublic partial class Entry\n{\n\t/// <summary>\n\t/// Returns "
},
{
"path": "src/Spice/Platforms/Android/Grid.cs",
"chars": 7359,
"preview": "using System.Collections.Specialized;\nusing Android.Content;\nusing Android.Widget;\n\nnamespace Spice;\n\npublic partial cla"
},
{
"path": "src/Spice/Platforms/Android/Image.cs",
"chars": 1511,
"preview": "using Android.Content;\n\nnamespace Spice;\n\npublic partial class Image\n{\n\t/// <summary>\n\t/// Returns image.NativeView\n\t//"
},
{
"path": "src/Spice/Platforms/Android/ImageButton.cs",
"chars": 2180,
"preview": "using Android.Content;\n\nnamespace Spice;\n\npublic partial class ImageButton\n{\n\t/// <summary>\n\t/// Returns imageButton.Nat"
}
]
// ... and 158 more files (download for full content)
About this extraction
This page contains the full source code of the jonathanpeppers/spice GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 358 files (1.4 MB), approximately 368.2k tokens, and a symbol index with 1812 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.