Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
e443cf4
Added Stream as a media source for all platforms except Tizen
matt-goldman Nov 25, 2025
d578bb4
Added media element sample page and fixed small bug on Android
matt-goldman Nov 25, 2025
b86fbb7
Code cleanup and fix for Windows
matt-goldman Nov 25, 2025
a1f72a4
Resolve content type identification on macios
matt-goldman Nov 25, 2025
500bff8
Add Stream source test and remove temp file
matt-goldman Apr 3, 2026
4eebe6d
Merge branch 'main' into add-stream-media-source
matt-goldman Apr 3, 2026
dce4b60
Remove default cancellation token from CreateMediaItemFromStream
matt-goldman Apr 3, 2026
ab38062
Update StreamAssetResourceLoader to chunk reads with a max buffer siz…
matt-goldman Apr 3, 2026
e978e15
Fix test for MediaSource.FromStream
matt-goldman Apr 3, 2026
94966fe
Remove hard-coded CRLF from sample app csproj file
matt-goldman Apr 3, 2026
72e1b74
Fixed disposal pattern in MediaElementFromStreamPage.xaml.cs, also cl…
matt-goldman Apr 5, 2026
c0bcdce
Fix stream position logic in StreamDataSource.android.cs and formatti…
matt-goldman Apr 5, 2026
8cefc98
Remove static keyword from HttpClient declaration in MediaManager.and…
matt-goldman Apr 5, 2026
6846f44
Added a static dictionary to avoid re-instantiation of response heade…
matt-goldman Apr 5, 2026
d2ba541
Update samples/CommunityToolkit.Maui.Sample/ViewModels/Views/ViewsGal…
matt-goldman Apr 5, 2026
3ee0570
Update samples/CommunityToolkit.Maui.Sample/MauiProgram.cs
matt-goldman Apr 5, 2026
5b10d29
Fix ILogger type in constructor of MediaElementFromStreamPage.xaml.cs
matt-goldman Apr 5, 2026
e64124b
Removed static from artwork metadata method in MediaManager.android.cs
matt-goldman Apr 5, 2026
b459302
Update src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.maci…
matt-goldman Apr 5, 2026
9429dbf
Merge branch 'CommunityToolkit:main' into add-stream-media-source
matt-goldman Apr 5, 2026
5d9c2f9
Restore macios StreamAssetResourceLoader.macios.cs to working version
matt-goldman Apr 5, 2026
d6b22fe
Merge branch 'main' into add-stream-media-source
matt-goldman Apr 5, 2026
a28307e
Added updated permisisons for sample app
matt-goldman Apr 6, 2026
a6f715f
Fix race condition in LazyView test
matt-goldman Apr 6, 2026
4dafc54
Remove ConfigureAwait(false) from OnValidationPropertyChanged
matt-goldman Apr 6, 2026
4599b2f
Catch exceptions in OnValidationPropertychanged
matt-goldman Apr 6, 2026
d10b027
Merge branch 'main' into add-stream-media-source
matt-goldman Apr 6, 2026
8579f57
Merge branch 'main' into add-stream-media-source
matt-goldman Apr 10, 2026
a9c8c92
Merge branch 'main' into add-stream-media-source
ne0rrmatrix Apr 13, 2026
dcf4409
Revert unintentional solution and project file changes
matt-goldman Apr 13, 2026
dd305df
Move GetMimeType extension to primitives
matt-goldman Apr 13, 2026
2699fc7
Move GetMimeType extension to Extensions folder and namespace
matt-goldman Apr 14, 2026
6c02604
Merge branch 'main' into add-stream-media-source
matt-goldman Apr 16, 2026
b0bc6d9
Merge branch 'main' into add-stream-media-source
matt-goldman May 4, 2026
64c4bb6
Merge branch 'main' into add-stream-media-source
TheCodeTraveler May 6, 2026
dc90cb6
Potential fix for pull request finding
TheCodeTraveler May 6, 2026
8643cae
Implement CoPilot suggestions
TheCodeTraveler May 6, 2026
22a8655
Remove static cached dictionary for empty headers and add property in…
matt-goldman May 8, 2026
96c36c3
Add validation for stream length in StreamDataSource to prevent Argum…
matt-goldman May 8, 2026
3571483
Change File.Open to File.OpenRead for improved stream handling
matt-goldman May 8, 2026
1697efe
Dispose current stream data source factory before initializing a new one
matt-goldman May 8, 2026
e9e9dcd
Merge branch 'main' into add-stream-media-source
matt-goldman May 8, 2026
81c0771
Merge branch 'main' into add-stream-media-source
matt-goldman May 9, 2026
d75be1d
Update Sample App to play video OnAppearing
TheCodeTraveler May 11, 2026
f9a6561
Merge branch 'main' into add-stream-media-source
TheCodeTraveler May 11, 2026
62533bb
Merge branch 'add-stream-media-source' of https://github.com/matt-gol…
TheCodeTraveler May 11, 2026
ed443a0
Update `GetMimeType`, Add Unit Tests
TheCodeTraveler May 11, 2026
5354e4f
Add `ArgumentNullException.ThrowIfNull`
TheCodeTraveler May 11, 2026
64f686c
Nest `StreamDataSource` inside `StreamDataSourceFactory`, Move File L…
TheCodeTraveler May 11, 2026
fbd7b08
Update formatting
TheCodeTraveler May 11, 2026
a9cfbcf
Update formatting
TheCodeTraveler May 11, 2026
69c97e6
Update formatting
TheCodeTraveler May 11, 2026
bc3af00
`dotnet format`
TheCodeTraveler May 11, 2026
78f261f
Use `StreamAssetResourceLoader.DefaultContentType`
TheCodeTraveler May 11, 2026
ff5e7ed
Update formatting
TheCodeTraveler May 11, 2026
1e8d2e2
Rename `StreamDataSourceFactory`
TheCodeTraveler May 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion .github/instructions/codestyle.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,28 @@ This guide provides a set of best practices and coding standards for writing C#
}
```

## Argument Validation:

- Prefer `ArgumentNullException.ThrowIfNull` over manual null checks:
```csharp
// Good: Concise null validation
public void Write(byte[] buffer)
{
ArgumentNullException.ThrowIfNull(buffer);
// Use buffer safely here
}

// Avoid: Verbose manual null check
public void Write(byte[] buffer)
{
if (buffer is null)
{
throw new ArgumentNullException(nameof(buffer));
}
// Use buffer safely here
}
```

## Safe Operations:

- Use Try methods for safer operations:
Expand Down Expand Up @@ -578,4 +600,4 @@ Here Key Components of the Try Pattern:
4. Null Analysis Attribute: [NotNullWhen(true)] (or [MaybeNullWhen(false)]) informs the compiler that if the method returns true, the out parameter is guaranteed to be non-null.

This pattern allows for high-performance retrieval or parsing without throwing exceptions for expected failures. It also allows cleaner call sites by eliminating the need for null-checking the output variable within the if block, as seen in Dictionary<TKey, TValue>.TryGetValue.
```

1 change: 1 addition & 0 deletions samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ public partial class AppShell : Shell
CreateViewModelMapping<LazyViewPage, LazyViewViewModel, ViewsGalleryPage, ViewsGalleryViewModel>(),
CreateViewModelMapping<MapsPinsPage, MapsPinsViewModel, ViewsGalleryPage, ViewsGalleryViewModel>(),
CreateViewModelMapping<MediaElementPage, MediaElementViewModel, ViewsGalleryPage, ViewsGalleryViewModel>(),
CreateViewModelMapping<MediaElementFromStreamPage, MediaElementFromStreamViewModel, ViewsGalleryPage, ViewsGalleryViewModel>(),
CreateViewModelMapping<MediaElementCarouselViewPage, MediaElementCarouselViewViewModel, ViewsGalleryPage, ViewsGalleryViewModel>(),
CreateViewModelMapping<MediaElementCollectionViewPage, MediaElementCollectionViewViewModel, ViewsGalleryPage, ViewsGalleryViewModel>(),
CreateViewModelMapping<MediaElementMultipleWindowsPage, MediaElementMultipleWindowsViewModel, ViewsGalleryPage, ViewsGalleryViewModel>(),
Expand Down
4 changes: 4 additions & 0 deletions samples/CommunityToolkit.Maui.Sample/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ public static MauiApp CreateMauiApp()
builder.Services.AddHttpClient<ByteArrayToImageSourceConverterViewModel>()
.AddStandardResilienceHandler(static options => options.Retry = new MobileHttpRetryStrategyOptions());

builder.Services.AddHttpClient<MediaElementFromStreamPage>()
.AddStandardResilienceHandler(static options => options.Retry = new MobileHttpRetryStrategyOptions());

builder.Services.AddSingleton<AppShell>();

RegisterViewsAndViewModels(builder.Services);
Expand Down Expand Up @@ -252,6 +255,7 @@ static void RegisterViewsAndViewModels(in IServiceCollection services)
services.AddTransientWithShellRoute<LazyViewPage, LazyViewViewModel>();
services.AddTransientWithShellRoute<MapsPinsPage, MapsPinsViewModel>();
services.AddTransientWithShellRoute<MediaElementPage, MediaElementViewModel>();
services.AddTransientWithShellRoute<MediaElementFromStreamPage, MediaElementFromStreamViewModel>();
services.AddTransientWithShellRoute<MediaElementCarouselViewPage, MediaElementCarouselViewViewModel>();
services.AddTransientWithShellRoute<MediaElementCollectionViewPage, MediaElementCollectionViewViewModel>();
services.AddTransientWithShellRoute<MediaElementMultipleWindowsPage, MediaElementMultipleWindowsViewModel>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:CommunityToolkit.Maui.Sample.Pages"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:constants="clr-namespace:CommunityToolkit.Maui.Sample.Constants"
xmlns:viewModels="clr-namespace:CommunityToolkit.Maui.Sample.ViewModels.Views"
xmlns:converters="clr-namespace:CommunityToolkit.Maui.Sample.Converters"
x:TypeArguments="viewModels:MediaElementFromStreamViewModel"
x:DataType="viewModels:MediaElementFromStreamViewModel"
x:Class="CommunityToolkit.Maui.Sample.Pages.Views.MediaElementFromStreamPage"
Title="MediaElement">
<pages:BasePage.Resources>
<converters:SecondsToStringConverter x:Key="SecondsToStringConverter" />
</pages:BasePage.Resources>

<ScrollView>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="220" />
<RowDefinition Height="50" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<toolkit:MediaElement
x:Name="MediaElement"
ShouldAutoPlay="True"
MediaEnded="OnMediaEnded"
MediaFailed="OnMediaFailed"
MediaOpened="OnMediaOpened"
PositionChanged="OnPositionChanged"
StateChanged="OnStateChanged"
SeekCompleted="OnSeekCompleted"/>
<HorizontalStackLayout Grid.Row="1" Padding="0,0,0,15">
<Label HorizontalOptions="Center" x:DataType="toolkit:MediaElement">
<Label.Text>
<MultiBinding StringFormat="{}Current State: {0} - Dimensions: {1}x{2}">
<Binding Path="CurrentState" Source="{x:Reference MediaElement}" />
<Binding Path="MediaWidth" Source="{x:Reference MediaElement}" />
<Binding Path="MediaHeight" Source="{x:Reference MediaElement}" />
</MultiBinding>
</Label.Text>
</Label>

</HorizontalStackLayout>

<Grid Grid.Row="2" Padding="0,10,0,10" ColumnDefinitions="*,*,*,*" ColumnSpacing="5">
<Button Grid.Column="0" Text="Play" Clicked="OnPlayClicked" />
<Button Grid.Column="1" Text="Pause" Clicked="OnPauseClicked" />
<Button Grid.Column="2" Text="Stop" Clicked="OnStopClicked" />
<Button Grid.Column="3" Text="Mute" Clicked="OnMuteClicked">
<Button.Triggers>
<DataTrigger TargetType="Button"
x:DataType="toolkit:MediaElement"
Binding="{Binding ShouldMute, Source={x:Reference MediaElement}}"
Value="True">
<Setter Property="Text" Value="Unmute" />
</DataTrigger>
<DataTrigger TargetType="Button"
x:DataType="toolkit:MediaElement"
Binding="{Binding ShouldMute, Source={x:Reference MediaElement}}"
Value="False">
<Setter Property="Text" Value="Mute" />
</DataTrigger>
</Button.Triggers>
</Button>
</Grid>

<Slider
x:Name="PositionSlider"
Grid.Row="3"
MinimumTrackColor="Gray"
DragStarted="Slider_DragStarted"
DragCompleted="Slider_DragCompleted"/>

<Grid Grid.Row="4" HorizontalOptions="Fill">
<Label HorizontalOptions="Start" x:DataType="toolkit:MediaElement" Text="{Binding Position, Source={x:Reference MediaElement}, Converter={StaticResource SecondsToStringConverter}}" />
<Label HorizontalOptions="End" HorizontalTextAlignment="End" x:DataType="toolkit:MediaElement" Text="{Binding Duration, Source={x:Reference MediaElement}, Converter={StaticResource SecondsToStringConverter}}" />
</Grid>

<VerticalStackLayout Padding="0,20,0,0" Grid.Row="5" Spacing="5">
<HorizontalStackLayout Spacing="5" HorizontalOptions="Center">
<Button Text="Open Video" Clicked="OnOpenVideoClicked" HorizontalOptions="Fill" />

<Button Text="Record Video" Clicked="OnRecordVideoClicked" HorizontalOptions="Fill" />
</HorizontalStackLayout>
<Button Text="Change Aspect" Clicked="ChangeAspectClicked" />
</VerticalStackLayout>

<HorizontalStackLayout Grid.Row="6" Padding="0,10,0,10" Spacing="5">
<Label Margin="20,10" x:DataType="toolkit:MediaElement">
<Label.FormattedText>
<FormattedString>
<Span Text="Speed:" />
<Span Text="{Binding Source={x:Reference MediaElement}, Path=Speed}" />
</FormattedString>
</Label.FormattedText>
</Label>

<Button Text="-" Clicked="OnSpeedMinusClicked" />
<Button Text="+" Clicked="OnSpeedPlusClicked" />
</HorizontalStackLayout>

<HorizontalStackLayout Grid.Row="7" Padding="0,10,0,10" Spacing="5">
<Label Margin="20,10" x:DataType="toolkit:MediaElement">
<Label.FormattedText>
<FormattedString>
<Span Text="Volume:" />
<Span Text="{Binding Source={x:Reference MediaElement}, Path=Volume, StringFormat='{}{0:P0}'}" />
</FormattedString>
</Label.FormattedText>
</Label>

<Button Text="-" Clicked="OnVolumeMinusClicked" />
<Button Text="+" Clicked="OnVolumePlusClicked" />
</HorizontalStackLayout>

<VerticalStackLayout Grid.Row="8">
<HorizontalStackLayout Padding="0,0,0,10">
<Switch
Margin="0,0,5,0"
ThumbColor="White"
OnColor="LimeGreen"
x:DataType="toolkit:MediaElement"
IsToggled="{Binding Source={x:Reference MediaElement}, Path=ShouldShowPlaybackControls}" />
<Label
VerticalOptions="Center"
Text="Show playback controls" />
</HorizontalStackLayout>
<HorizontalStackLayout Padding="0,0,0,10">
<Switch
Margin="0,0,5,0"
ThumbColor="White"
OnColor="LimeGreen"
x:DataType="toolkit:MediaElement"
IsToggled="{Binding Source={x:Reference MediaElement}, Path=ShouldLoopPlayback}" />
<Label
VerticalOptions="Center"
Text="Loop media" />
</HorizontalStackLayout>
<HorizontalStackLayout>
<Switch
Margin="0,0,5,0"
ThumbColor="White"
OnColor="LimeGreen"
x:DataType="toolkit:MediaElement"
IsToggled="{Binding Source={x:Reference MediaElement}, Path=ShouldKeepScreenOn}" />
<Label
VerticalOptions="Center"
Text="Keep screen on" />
</HorizontalStackLayout>
</VerticalStackLayout>
</Grid>
</ScrollView>
</pages:BasePage>
Loading
Loading