Plugin.Maui.BottomSheet 10.0.6

dotnet add package Plugin.Maui.BottomSheet --version 10.0.6
                    
NuGet\Install-Package Plugin.Maui.BottomSheet -Version 10.0.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Plugin.Maui.BottomSheet" Version="10.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Plugin.Maui.BottomSheet" Version="10.0.6" />
                    
Directory.Packages.props
<PackageReference Include="Plugin.Maui.BottomSheet" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Plugin.Maui.BottomSheet --version 10.0.6
                    
#r "nuget: Plugin.Maui.BottomSheet, 10.0.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Plugin.Maui.BottomSheet@10.0.6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Plugin.Maui.BottomSheet&version=10.0.6
                    
Install as a Cake Addin
#tool nuget:?package=Plugin.Maui.BottomSheet&version=10.0.6
                    
Install as a Cake Tool

πŸ“± Plugin.Maui.BottomSheet

πŸš€ Show native BottomSheets with .NET MAUI!

NuGet License Platform Support

✨ Features

  • 🧭 Built-in NavigationService - Seamless navigation between bottom sheets
  • πŸ“„ Flexible Content - Open any ContentPage or View as BottomSheet
  • 🎨 Customizable Layout - Create BottomSheets in any layout
  • πŸ“‹ Configurable Header - Full header customization support
  • πŸ—οΈ MVVM Support - Complete MVVM pattern integration
  • 🎯 Native Performance - Platform-specific implementations for optimal UX

🎯 Quick Demo

Check out the sample project to see the API in action!

🌍 Platform Support

Mobile

<table> <tr> <td>

πŸ“± Apple iOS 15+

<figure> <figcaption>iPhone</figcaption> <img src="screenshots/iOS/Showcase.gif" width="150" height="250" alt="iOS Demo"/> </figure>

<figure> <figcaption>iPad</figcaption> <img src="screenshots/iPad/Showcase.gif" width="200" height="200" alt="iPad Demo"/> </figure>

</td> <td>

πŸ€– Android API 21+

<figure> <figcaption>Phone</figcaption> <img src="screenshots/Android/Showcase.gif" width="150" height="250" alt="Android Demo"/> </figure>

<figure> <figcaption>Tablet</figcaption> <img src="screenshots/Android/Tablet/Showcase.gif" width="200" height="200" alt="Android Tablet Demo"/> </figure>

</td> </tr> </table>

Desktop

<table> <tr> <td>

πŸ’» MacCatalyst 15+

<img src="screenshots/MacCatalyst/Showcase.gif" height="200" width="500" alt="MacCatalyst Demo"/> </td> <td>

πŸͺŸ Windows

<img src="screenshots/MacCatalyst/Showcase.gif" height="200" width="500" alt="Windows Demo"/>

</td> </tr> </table>

πŸš€ Quick Start

1️⃣ Installation

Install the NuGet package:

dotnet add package Plugin.Maui.BottomSheet

2️⃣ Setup

Enable the plugin in your MauiProgram.cs:

using Plugin.Maui.BottomSheet.Hosting;

var builder = MauiApp.CreateBuilder();
builder
    .UseMauiApp<App>()
    .UseBottomSheet() // πŸ‘ˆ Add this line
    .ConfigureFonts(fonts =>
    {
        fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
        fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
    });

#if DEBUG
builder.Logging.AddDebug();
#endif

return builder.Build();

3️⃣ Basic Usage

Add the XAML namespace:

xmlns:bottomsheet="http://pluginmauibottomsheet.com"

Create a simple bottom sheet:

<bottomsheet:BottomSheet x:Name="MyBottomSheet" IsOpen="{Binding IsSheetOpen}">
    <bottomsheet:BottomSheetContent>
        <Label Text="Hello from Bottom Sheet!" />
    </bottomsheet:BottomSheetContent>
</bottomsheet:BottomSheet>

Set peek height to view height (peek height changes dynamically as view height changes)

<mauibottomsheet:BottomSheet
    PeekHeight="{mauibottomsheet:PeekView View={x:Reference ContentBox}}"
    States="Peek">
    <mauibottomsheet:BottomSheetContent>
        <mauibottomsheet:BottomSheetContent.Content>
            <Grid RowDefinitions="300">
                <BoxView x:Name="ContentBox" Color="Orange" />
            </Grid>
        </mauibottomsheet:BottomSheetContent.Content>
    </mauibottomsheet:BottomSheetContent>
</mauibottomsheet:BottomSheet>

or

<mauibottomsheet:BottomSheet
    PeekHeight="{mauibottomsheet:PeekView ContentBox}"
    States="Peek">
    <mauibottomsheet:BottomSheetContent>
        <mauibottomsheet:BottomSheetContent.ContentTemplate>
            <DataTemplate>
                <Grid RowDefinitions="300">
                    <BoxView x:Name="ContentBox" Color="Orange" />
                </Grid>
            </DataTemplate>
        </mauibottomsheet:BottomSheetContent.ContentTemplate>
    </mauibottomsheet:BottomSheetContent>
</mauibottomsheet:BottomSheet>

The peek height is calculated using MAUI's measurement behavior. Different platforms may return different heights for the same layout. This is especially true when using ScrollView, VerticalStackLayout, or Grid with Star rows. To observe the differences, launch the Plugin.BottomSheet.Tests.Maui.Ui.Application test project and open the various peek BottomSheets

πŸ“– API Reference

πŸ”§ Core Properties

Property Type Description
IsModal bool Enable/disable interaction with content under BottomSheet
IsCancelable bool Allow user to close via gestures or background click
HasHandle bool Show/hide the drag handle
ShowHeader bool Show/hide the header section
IsOpen bool Control open/close state
IsDraggable bool Enable/disable drag gestures (useful for drawing)
States List<BottomSheetState> Allowed states (Peek, Medium, Large)
CurrentState BottomSheetState Current display state
PeekHeight double Height when in peek state (iOS 16+)
Padding double Internal padding
BackgroundColor Color Background color
CornerRadius float Top corner radius
WindowBackgroundColor Color Window background (modal only)
SizeMode BottomSheetSizeMode Represents a size mode for the bottom sheet where the height is adjusted dynamically to fit the content displayed within it or a fixed value based on the number of states it can display.

Size Modes

State Description
States Represents a size mode for the bottom sheet where the height is set to a fixed value based on the number of states it can display. This mode ensures the bottom sheet is fully expanded rather than dynamically adjusting its size to-fit content.
FitToContent A size mode indicating that the bottom sheet dynamically adjusts its height to precisely fit the content it displays. In this mode, the bottom sheet wraps around its contents and does not occupy any more vertical space than necessary.

Mode FitToContent is not compatible with the States and CurrentState property. Do not mix these two properties. Requires iOS 16+. On prior versions of iOS, the medium state will be used instead.

🎭 BottomSheet States

State Description
Peek Fractional height (customizable)
Medium Half screen height
Large Full screen height

🎨 Header Configuration

Property Type Description
TitleText string Title text displayed in header
TopLeftButton Button Custom button for top-left position
TopRightButton Button Custom button for top-right position
HeaderDataTemplate DataTemplate Custom view template (overrides other header properties)
Content View Direct view content
HeaderAppearance BottomSheetHeaderButtonAppearanceMode Controls which buttons are displayed
ShowCloseButton bool Show built-in close button
CloseButtonPosition CloseButtonPosition Position of close button (Left/Right)

Be careful when using Content because the Content will be created even if the BottomSheet isn't open and this may have a negative performance impact. Content should only be used with navigation and not in BottomSheets added directly to a Layout.

πŸ“± Content Configuration

Property Type Description
Content View Direct view content
ContentTemplate DataTemplate Template for lazy loading

Be careful when using Content because the Content will be created even if the BottomSheet isn't open and this may have a negative performance impact. Content should only be used with navigation and not in BottomSheets added directly to a Layout.

🎨 Styling Options

BottomSheet Style Properties
Property Type Description
HeaderStyle BottomSheetHeaderStyle Styling configuration for header elements
BottomSheet Header Style Properties
Property Type Description
TitleTextColor Color Color of the title text
TitleTextFontSize double Font size of the title text
TitleTextFontAttributes FontAttributes Font attributes (Bold, Italic, None)
TitleTextFontFamily string Font family name for title text
TitleTextFontAutoScalingEnabled bool Enable automatic font scaling
CloseButtonHeightRequest double Requested height for close button
CloseButtonWidthRequest double Requested width for close button
CloseButtonTintColor Color Tint color for close button icon

πŸŽͺ Advanced Examples

πŸ“‹ Complete XAML Example

<bottomsheet:BottomSheet
    x:Name="AdvancedBottomSheet"
    Padding="20"
    CornerRadius="20"
    HasHandle="True"
    IsCancelable="True"
    IsDraggable="True"
    IsModal="True"
    IsOpen="{Binding IsOpen}"
    ShowHeader="True"
    States="Peek,Medium,Large"
    CurrentState="Medium"
    WindowBackgroundColor="Black">
    
    
    <bottomsheet:BottomSheet.Header>
        <bottomsheet:BottomSheetHeader
            CloseButtonPosition="Right"
            HeaderAppearance="LeftAndRightButton"
            ShowCloseButton="True"
            TitleText="My Awesome Sheet">
            <bottomsheet:BottomSheetHeader.TopLeftButton>
                <Button Command="{Binding LeftButtonCommand}" Text="Cancel" />
            </bottomsheet:BottomSheetHeader.TopLeftButton>
            <bottomsheet:BottomSheetHeader.TopRightButton>
                <Button Command="{Binding RightButtonCommand}" Text="Save" />
            </bottomsheet:BottomSheetHeader.TopRightButton>
        </bottomsheet:BottomSheetHeader>
    </bottomsheet:BottomSheet.Header>
    
    
    <bottomsheet:BottomSheetContent>
        <bottomsheet:BottomSheetContent.ContentTemplate>
            <DataTemplate>
                <VerticalStackLayout>
                    
                    <ContentView>
                        <ContentView.Behaviors>
                            <bottomsheet:BottomSheetPeekBehavior />
                        </ContentView.Behaviors>
                        <Label Text="This content is visible in peek mode" />
                    </ContentView>
                        
                    
                    <Grid>
                        <Label Text="This content appears when expanded" />
                        
                    </Grid>
                </VerticalStackLayout>
            </DataTemplate>
        </bottomsheet:BottomSheetContent.ContentTemplate>
    </bottomsheet:BottomSheetContent>
    
    
    <bottomsheet:BottomSheet.BottomSheetStyle>
        <bottomsheet:BottomSheetStyle>
            <bottomsheet:BottomSheetStyle.HeaderStyle>
                <bottomsheet:BottomSheetHeaderStyle 
                    TitleTextColor="Blue" 
                    TitleTextFontSize="18"
                    TitleTextFontAttributes="Bold"
                    CloseButtonTintColor="Red"/>
            </bottomsheet:BottomSheetStyle.HeaderStyle>
        </bottomsheet:BottomSheetStyle>
    </bottomsheet:BottomSheet.BottomSheetStyle>
</bottomsheet:BottomSheet>

πŸ“‹ Easy and fast popups with content based size

<mauibottomsheet:BottomSheet
    SizeMode="FitToContent">
    <mauibottomsheet:BottomSheetContent>
        <mauibottomsheet:BottomSheetContent.Content>
            <Grid RowDefinitions="300">
                <BoxView x:Name="ContentBox" Color="Orange" />
            </Grid>
        </mauibottomsheet:BottomSheetContent.Content>
    </mauibottomsheet:BottomSheetContent>
</mauibottomsheet:BottomSheet>

🎨 Global Styling

<Style TargetType="bottomsheet:BottomSheet">
    <Setter Property="BottomSheetStyle">
        <Setter.Value>
            <bottomsheet:BottomSheetStyle>
                <bottomsheet:BottomSheetStyle.HeaderStyle>
                    <bottomsheet:BottomSheetHeaderStyle
                        CloseButtonHeightRequest="40"
                        CloseButtonTintColor="LightBlue"
                        CloseButtonWidthRequest="40"
                        TitleTextColor="Blue"
                        TitleTextFontAttributes="Bold"
                        TitleTextFontAutoScalingEnabled="True"
                        TitleTextFontFamily="OpenSansRegular"
                        TitleTextFontSize="20" />
                </bottomsheet:BottomSheetStyle.HeaderStyle>
            </bottomsheet:BottomSheetStyle>
        </Setter.Value>
    </Setter>
</Style>

🧭 Navigation System

πŸš€ Setup Navigation

Register your bottom sheets for navigation:

// Basic registration
builder.Services.AddBottomSheet<UserProfilePage>("UserProfile");

// With ViewModel binding
builder.Services.AddBottomSheet<UserProfileSheet, UserProfileViewModel>("UserProfile");

// With default configuration
builder.Services.AddBottomSheet<UserProfilePage>("UserProfile", (sheet, page) =>
{
    sheet.States = [BottomSheetState.Medium, BottomSheetState.Large];
    sheet.CurrentState = BottomSheetState.Large;
    sheet.ShowHeader = true;
    sheet.Header = new BottomSheetHeader()
    {
        TitleText = page.Title,
    };
});

🎯 Using Navigation Service

public class MainViewModel
{
    private readonly IBottomSheetNavigationService _navigationService;

    public MainViewModel(IBottomSheetNavigationService navigationService)
    {
        _navigationService = navigationService;
    }

    // Navigate to a bottom sheet
    public async Task ShowUserProfile()
    {
        await _navigationService.NavigateToAsync("UserProfile");
    }

    // Navigate with parameters
    public async Task ShowUserProfile(int userId)
    {
        var parameters = new BottomSheetNavigationParameters
        {
            { "UserId", userId },
            { "Mode", "Edit" },
            { "ShowActions", true }
        };
        
        await _navigationService.NavigateToAsync("UserProfile", parameters);
    }

    // Navigate with parameters and custom configuration
    public async Task ShowProductDetails(Product product)
    {
        var parameters = new BottomSheetNavigationParameters
        {
            { "Product", product },
            { "Category", product.CategoryId },
            { "ReadOnly", false }
        };

        await _navigationService.NavigateToAsync("ProductDetails", parameters, configure: sheet =>
        {
            sheet.Header.TitleText = product.Name;
            sheet.CurrentState = BottomSheetState.Large;
            sheet.HasHandle = true;
        });
    }

    // Navigate with ViewModel and parameters
    public async Task ShowEditForm<T>(T model, string formType)
    {
        var parameters = new BottomSheetNavigationParameters
        {
            { "Model", model },
            { "FormType", formType },
            { "Timestamp", DateTime.Now }
        };

        await _navigationService.NavigateToAsync<EditFormViewModel>("EditForm", parameters);
    }

    // Navigate with complex object parameters
    public async Task ShowOrderSummary(Order order, List<OrderItem> items, decimal total)
    {
        var parameters = new BottomSheetNavigationParameters
        {
            { "Order", order },
            { "OrderItems", items },
            { "Total", total },
            { "Currency", "USD" },
            { "CanEdit", order.Status == OrderStatus.Draft }
        };

        await _navigationService.NavigateToAsync("OrderSummary", parameters);
    }

    // Go back with result parameters
    public async Task CloseWithResult()
    {
        var resultParameters = new BottomSheetNavigationParameters
        {
            { "Result", "Success" },
            { "ModifiedData", GetModifiedData() },
            { "HasChanges", true }
        };

        await _navigationService.GoBackAsync(resultParameters);
    }

    // Clear all sheets with notification parameters
    public async Task ClearBottomSheetStackAsync()
    {
        var parameters = new BottomSheetNavigationParameters
        {
            { "CloseReason", "ForceClose" },
            { "SaveState", true }
        };

        await _navigationService.ClearBottomSheetStack(parameters);
    }
}

πŸ”„ Navigation Lifecycle

Implement INavigationAware for lifecycle events:

public class UserProfileViewModel : INavigationAware
{
    public void OnNavigatedTo(IBottomSheetNavigationParameters parameters)
    {
        // Sheet opened
        var userId = parameters.GetValue<string>("UserId");
        LoadUserData(userId);
    }

    public void OnNavigatedFrom(IBottomSheetNavigationParameters parameters)
    {
        // Sheet closed or another sheet opened
        SaveChanges();
    }
}

Not only can the BottomSheet’s ViewModel implement INavigationAware, but so can the ViewModel of the parent view that launched the BottomSheet. This allows the parent to respond when:

  • The first BottomSheet is opened (OnNavigatedFrom)
  • The last BottomSheet is closed (OnNavigatedTo)

This is especially useful for suspending or restoring state in the parent view while modals are active.

πŸ›‘οΈ Navigation Confirmation

Implement confirmation dialogs:

public class EditUserViewModel : IConfirmNavigationAsync
{
    public async Task<bool> CanNavigateAsync(IBottomSheetNavigationParameters? parameters)
    {
        if (HasUnsavedChanges)
        {
            return await Shell.Current.CurrentPage.DisplayAlert(
                "Unsaved Changes",
                "You have unsaved changes. Do you want to discard them?",
                "Discard",
                "Cancel");
        }
        return true;
    }
}

When using the IsOpen to manage the visibility of a BottomSheet, the parent ViewModel can implement INavigationAware to respond to the lifecycle of the BottomSheet. This allows the parent ViewModel to handle actions when:

Scenario INavigationAware on Parent Triggered?
BottomSheet opened via navigation ❌ No
BottomSheet opened without navigation (IsOpen) βœ… Yes

🎯 Event Handling

πŸ“± Commands

public class MyViewModel
{
    public ICommand TopLeftButtonCommand { get; }
    public ICommand TopRightButtonCommand { get; }
    public ICommand OpeningCommand { get; }
    public ICommand OpenedCommand { get; }
    public ICommand ClosingCommand { get; }
    public ICommand ClosedCommand { get; }
}

🎭 Events

MyBottomSheet.Opening += OnOpening;
MyBottomSheet.Opened += OnOpened;
MyBottomSheet.Closing += OnClosing;
MyBottomSheet.Closed += OnClosed;

πŸ”§ Platform-Specific Features

πŸ€– Android

🎨 Custom Themes
// Set custom theme before opening
MyBottomSheet.On<Android>().SetTheme(Resource.Style.My_Awesome_BottomSheetDialog);
πŸ“ Size Constraints
// Code approach
MyBottomSheet.On<Android>().SetMaxHeight(800);
MyBottomSheet.On<Android>().SetMaxWidth(600);
MyBottomSheet.On<Android>().SetMargin(new Thickness(10, 0, 10, 0));
MyBottomSheet.On<Android>().SetHalfExpanedRatio = 0.8f;
MyBottomSheet.On<Android>().SetShouldRemoveExpandedCorners = false;

xmlns:androidBottomsheet="http://pluginmauibottomsheet.com/platformconfiguration/android"

<bottomsheet:BottomSheet
    androidBottomsheet:BottomSheet.MaxWidth="300"
    androidBottomsheet:BottomSheet.Margin="10,0,10,0"
    androidBottomsheet:BottomSheet.HalfExpandedRatio="0.8"
    androidBottomsheet:BottomSheet.ShouldRemoveExpandedCorners="false">
    
</bottomsheet:BottomSheet>
🎨 Edge-to-Edge Support

EdgeToEdge support is built-in and enabled by default. If you create your own theme make sure to derive from ThemeOverlay.MaterialComponents.BottomSheetDialog and that navigationBarColor is translucent.

To disable:

<item name="enableEdgeToEdge">false</item>

πŸ’» MacCatalyst

By design, sheets are always modal on macOS.

πŸͺŸ Windows

To ensure the same user experience (UX) across desktop applications, Windows sheets are always modal too. The sheet implementation mimics Microsoft.UI.Xaml.Controls.ContentDialog therefore some default properties are set.

Property ResourceKey Value
BorderThickness ContentDialogBorderWidth 1
MinWidth ContentDialogMinWidth 320
MinHeight ContentDialogMinHeight 184
MaxWidth ContentDialogMaxWidth 548
MaxHeight ContentDialogMaxHeight 756
πŸ“ Size Constraints
// Code approach
MyBottomSheet.On<Windows>().SetMaxHeight(800);
MyBottomSheet.On<Windows>().SetMaxWidth(600);
MyBottomSheet.On<Windows>().SetMinHeight(800);
MyBottomSheet.On<Windows>().SetMinWidth(600);

xmlns:windowsBottomsheet="http://pluginmauibottomsheet.com/platformconfiguration/windows"

<bottomsheet:BottomSheet
    androidBottomsheet:BottomSheet.MinWidth="300"
    androidBottomsheet:BottomSheet.MinHeight="300"
    androidBottomsheet:BottomSheet.MaxWidth="300"
    androidBottomsheet:BottomSheet.MaxHeight="300">
    
</bottomsheet:BottomSheet>

πŸ“± Platform Considerations

Feature iOS Android MacCatalyst Windows
Edge-to-Edge βœ… βœ… ❌ ❌
PeekHeight iOS 16+ βœ… ❌ ❌
Custom Themes ❌ βœ… ❌ ❌
Modal Only ❌ ❌ βœ… βœ…

πŸ”„ Lifecycle Events

πŸ“± Platform Lifecycle Integration

using Microsoft.Maui.LifecycleEvents;
using Plugin.Maui.BottomSheet.LifecycleEvents;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .UseBottomSheet();
        
        #if ANDROID
        builder.ConfigureLifecycleEvents(events =>
        {
            events.AddAndroid(android =>
            {
                android.OnBottomSheetBackPressed(activity =>
                {
                    // Handle back button press
                    Debug.WriteLine("BottomSheet back button pressed");
                });
            });
        });
        #endif

        return builder.Build();
    }
}

🚨 Important Notes & Best Practices

🎯 Performance Tips

  • Use ContentTemplate instead of Content for better performance
  • Implement lazy loading for complex content
  • Consider using INavigationAware for proper lifecycle management

πŸ”„ Navigation Best Practices

  • Don't mix IsOpen with navigation methods
  • Always implement IConfirmNavigation for forms with user input

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ†˜ Support


<div> <b>Made with ❀️ for the .NET MAUI community</b> </div>

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-android35.0 is compatible.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-ios18.0 is compatible.  net9.0-maccatalyst was computed.  net9.0-maccatalyst18.0 is compatible.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net9.0-windows10.0.19041 is compatible.  net10.0 is compatible.  net10.0-android was computed.  net10.0-android36.0 is compatible.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-ios26.0 is compatible.  net10.0-maccatalyst was computed.  net10.0-maccatalyst26.0 is compatible.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed.  net10.0-windows10.0.19041 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on Plugin.Maui.BottomSheet:

Repository Stars
securefolderfs-community/SecureFolderFS
Powerful, secure, modern way to keep your files protected.
Version Downloads Last Updated
10.0.6 5,370 1/29/2026
10.0.5 242 1/27/2026
10.0.4 3,277 12/12/2025
10.0.2 971 12/3/2025
10.0.0 225 11/28/2025
9.1.9 16,867 7/13/2025
9.1.8 1,832 6/19/2025
9.1.7 698 6/9/2025
9.1.6 3,671 5/25/2025
9.1.5 1,796 4/19/2025
9.1.4 8,608 4/2/2025
9.1.3 561 3/15/2025
9.1.2 1,637 2/21/2025
9.1.1 302 2/20/2025
9.1.0 2,598 2/9/2025
9.0.0 302 2/2/2025
Loading failed