diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..726249e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,332 @@
+## 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/master/VisualStudio.gitignore
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# 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
+
+# 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/
+**/Properties/launchSettings.json
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.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
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# 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
+# 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
+
+# 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
+
+# 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 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/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# 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/
+/clean-all-bin-obj-directories.bat
+.DS_Store
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/FreakyDeoPlayer.csproj b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/FreakyDeoPlayer.csproj
new file mode 100644
index 0000000..1e8610b
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/FreakyDeoPlayer.csproj
@@ -0,0 +1,73 @@
+
+
+
+ net8.0-android;net8.0-ios;
+ true
+ true
+ enable
+ 14.2
+ 21.0
+ Maui.FreakyControls
+ FreakyDeoPlayer
+ 0.0.1
+ 0.0.1
+ 0.0.1
+ en
+ FreakyControls.FreakyDeoPlayer
+ latest
+ FreakyAli
+ MIT
+ Maui.FreakyControls is a free OSS UI Kit for .NET MAUI which provides a set of controls and utilities to build modern mobile apps.
+ maui_toolkit.png
+ https://github.com/FreakyAli/Maui.FreakyControls.FreakyDeoPlayer
+ https://github.com/FreakyAli/Maui.FreakyControls.FreakyDeoPlayer
+ Maui dotnet .net Maui FreakyControls Video VideoPlayer
+ Basic implementation for Freaky Video Player Control
+ Copyright 2024
+ true
+ false
+ 1701;1702;IL2121;CS1573;CS1591;CS1570;CS8632
+ Release;Debug
+
+
+ false
+
+
+ latest
+ true
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/FreakyDeoPlayerHandler.android.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/FreakyDeoPlayerHandler.android.cs
new file mode 100644
index 0000000..a5cf229
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/FreakyDeoPlayerHandler.android.cs
@@ -0,0 +1,121 @@
+using System;
+using AndroidX.Fragment.App;
+using Com.Google.Android.Exoplayer2;
+using Com.Google.Android.Exoplayer2.Source;
+using Com.Google.Android.Exoplayer2.UI;
+using Com.Google.Android.Exoplayer2.Upstream;
+using Microsoft.Maui.Controls.PlatformConfiguration;
+using LayoutParams = Android.Views.ViewGroup.LayoutParams;
+namespace Maui.FreakyControls;
+
+public partial class FreakyDeoPlayerHandler
+{
+ private readonly PlayerListener listener = new PlayerListener();
+
+ protected override FreakyNativeAndroidPlayer CreatePlatformView()
+ {
+ var HttpDataSourceFactory = new DefaultHttpDataSource.Factory().SetAllowCrossProtocolRedirects(true);
+ var MainDataSource = new ProgressiveMediaSource.Factory(HttpDataSourceFactory);
+ var exoplayer = new IExoPlayer.Builder(this.Context).
+ SetSeekBackIncrementMs(10000).
+ SetSeekForwardIncrementMs(10000).
+ SetMediaSourceFactory(MainDataSource).
+ Build();
+
+ var exoPlayerView = new FreakyNativeAndroidPlayer(this.Context)
+ {
+ Player = exoplayer,
+ ControllerShowTimeoutMs=4000,
+
+ ControllerHideOnTouch = true,
+ LayoutParameters = new LayoutParams(LayoutParams.MatchParent, LayoutParams.WrapContent),
+ };
+ exoPlayerView.Player.AddListener(listener);
+ exoPlayerView.Player.Prepare();
+ exoPlayerView.Player.PlayWhenReady = true;
+ exoPlayerView.FullscreenButtonClick += ExoPlayerView_FullscreenButtonClick;
+ return exoPlayerView;
+ }
+
+ private void ExoPlayerView_FullscreenButtonClick(object sender, StyledPlayerView.FullscreenButtonClickEventArgs e)
+ {
+
+ }
+
+ private void UpdateVolume()
+ {
+ PlatformView.Player.Volume = (float)VirtualView.Volume;
+ }
+
+ private void UpdateAutoPlay()
+ {
+ PlatformView.Player.PlayWhenReady = VirtualView.AutoPlay;
+ }
+
+ private void UpdateSource()
+ {
+ var hasSetSource = false;
+
+ if (PlatformView.Player is null)
+ {
+ return;
+ }
+
+ if (VirtualView.Source is null)
+ {
+ PlatformView.Player.ClearMediaItems();
+ //MediaElement.Duration = TimeSpan.Zero;
+ //MediaElement.CurrentStateChanged(MediaElementState.None);
+
+ return;
+ }
+
+ //MediaElement.CurrentStateChanged(MediaElementState.Opening);
+
+ PlatformView.Player.PlayWhenReady = VirtualView.AutoPlay;
+
+ if (VirtualView.Source is UriVideoSource uriSource)
+ {
+ var uri = uriSource.Uri;
+ if (!string.IsNullOrWhiteSpace(uri?.AbsoluteUri))
+ {
+ PlatformView.Player.SetMediaItem(MediaItem.FromUri(uri.AbsoluteUri));
+ PlatformView.Player.Prepare();
+
+ hasSetSource = true;
+ }
+ }
+ else if (VirtualView.Source is FileVideoSource fileSource)
+ {
+ var filePath = fileSource.Path;
+ if (!string.IsNullOrWhiteSpace(filePath))
+ {
+ PlatformView.Player.SetMediaItem(MediaItem.FromUri(filePath));
+ PlatformView.Player.Prepare();
+
+ hasSetSource = true;
+ }
+ }
+ else if (VirtualView.Source is ResourceVideoSource resourceSource)
+ {
+ var package = PlatformView?.Context?.PackageName ?? "";
+ var path = resourceSource.Path;
+ if (!string.IsNullOrWhiteSpace(path))
+ {
+ string assetFilePath = "asset://" + package + "/" + path;
+
+ PlatformView.Player.SetMediaItem(MediaItem.FromUri(assetFilePath));
+ PlatformView.Player.Prepare();
+
+ hasSetSource = true;
+ }
+ }
+
+ if (hasSetSource && PlatformView.Player.PlayerError is null)
+ {
+ //VirtualView.MediaOpened();
+ }
+
+ PlatformView.Player.Play();
+ }
+}
\ No newline at end of file
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/NativeControls/FreakyNativeAndroidPlayer.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/NativeControls/FreakyNativeAndroidPlayer.cs
new file mode 100644
index 0000000..d3b7159
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/NativeControls/FreakyNativeAndroidPlayer.cs
@@ -0,0 +1,29 @@
+using System;
+using Android.Content;
+using Android.Runtime;
+using Android.Util;
+using Android.Widget;
+using Com.Google.Android.Exoplayer2;
+using Com.Google.Android.Exoplayer2.UI;
+
+namespace Maui.FreakyControls;
+
+public class FreakyNativeAndroidPlayer : StyledPlayerView
+{
+ public FreakyNativeAndroidPlayer(Context context) :
+ base(context)
+ {
+ }
+
+ public FreakyNativeAndroidPlayer(Context context, IAttributeSet attrs) :
+ base(context, attrs)
+ {
+ }
+
+ public FreakyNativeAndroidPlayer(Context context, IAttributeSet attrs, int defStyleAttr) :
+ base(context, attrs, defStyleAttr)
+ {
+ }
+}
+
+
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/PlayerListener.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/PlayerListener.cs
new file mode 100644
index 0000000..ac59310
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/PlayerListener.cs
@@ -0,0 +1,191 @@
+using System;
+using Com.Google.Android.Exoplayer2;
+using Com.Google.Android.Exoplayer2.Audio;
+using Com.Google.Android.Exoplayer2.Metadata;
+using Com.Google.Android.Exoplayer2.Text;
+using Com.Google.Android.Exoplayer2.Trackselection;
+using Com.Google.Android.Exoplayer2.Video;
+
+namespace Maui.FreakyControls;
+
+public class PlayerListener : Java.Lang.Object, IPlayer.IListener
+{
+ public void OnAudioAttributesChanged(AudioAttributes audioAttributes)
+ {
+ }
+
+ public void OnAudioSessionIdChanged(int audioSessionId)
+ {
+ }
+
+ public void OnAvailableCommandsChanged(IPlayer.Commands availableCommands)
+ {
+
+ }
+
+ public void OnCues(CueGroup cueGroup)
+ {
+
+ }
+
+ public void OnDeviceInfoChanged(Com.Google.Android.Exoplayer2.DeviceInfo deviceInfo)
+ {
+
+ }
+
+ public void OnDeviceVolumeChanged(int volume, bool muted)
+ {
+
+ }
+
+ public void OnEvents(IPlayer player, IPlayer.Events events)
+ {
+
+ }
+
+ public void OnIsLoadingChanged(bool isLoading)
+ {
+
+ }
+
+ public void OnIsPlayingChanged(bool isPlaying)
+ {
+
+ }
+
+ public void OnLoadingChanged(bool isLoading)
+ {
+
+ }
+
+ public void OnMaxSeekToPreviousPositionChanged(long maxSeekToPreviousPositionMs)
+ {
+
+ }
+
+ public void OnMediaItemTransition(MediaItem mediaItem, int reason)
+ {
+
+ }
+
+ public void OnMediaMetadataChanged(MediaMetadata mediaMetadata)
+ {
+
+ }
+
+ public void OnMetadata(Metadata metadata)
+ {
+
+ }
+
+ public void OnPlaybackParametersChanged(PlaybackParameters playbackParameters)
+ {
+
+ }
+
+ public void OnPlaybackStateChanged(int playbackState)
+ {
+
+ }
+
+ public void OnPlaybackSuppressionReasonChanged(int playbackSuppressionReason)
+ {
+
+ }
+
+ public void OnPlayerError(PlaybackException error)
+ {
+
+ }
+
+ public void OnPlayerErrorChanged(PlaybackException error)
+ {
+
+ }
+
+ public void OnPlayerStateChanged(bool playWhenReady, int playbackState)
+ {
+
+ }
+
+ public void OnPlaylistMetadataChanged(MediaMetadata mediaMetadata)
+ {
+
+ }
+
+ public void OnPlayWhenReadyChanged(bool playWhenReady, int reason)
+ {
+
+ }
+
+ public void OnPositionDiscontinuity(int reason)
+ {
+
+ }
+
+ public void OnRenderedFirstFrame()
+ {
+
+ }
+
+ public void OnRepeatModeChanged(int repeatMode)
+ {
+
+ }
+
+ public void OnSeekBackIncrementChanged(long seekBackIncrementMs)
+ {
+
+ }
+
+ public void OnSeekForwardIncrementChanged(long seekForwardIncrementMs)
+ {
+
+ }
+
+ public void OnSeekProcessed()
+ {
+
+ }
+
+ public void OnShuffleModeEnabledChanged(bool shuffleModeEnabled)
+ {
+
+ }
+
+ public void OnSkipSilenceEnabledChanged(bool skipSilenceEnabled)
+ {
+
+ }
+
+ public void OnSurfaceSizeChanged(int width, int height)
+ {
+
+ }
+
+ public void OnTimelineChanged(Timeline timeline, int reason)
+ {
+
+ }
+
+ public void OnTracksChanged(Tracks tracks)
+ {
+
+ }
+
+ public void OnTrackSelectionParametersChanged(TrackSelectionParameters parameters)
+ {
+
+ }
+
+ public void OnVideoSizeChanged(VideoSize videoSize)
+ {
+
+ }
+
+ public void OnVolumeChanged(float volume)
+ {
+
+ }
+}
+
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/Resources/values/styles.xml b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/Resources/values/styles.xml
new file mode 100644
index 0000000..2397f1c
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/Android/Resources/values/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/MacCatalyst/FreakyDeoPlayerHandler.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/MacCatalyst/FreakyDeoPlayerHandler.cs
new file mode 100644
index 0000000..248fea9
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/MacCatalyst/FreakyDeoPlayerHandler.cs
@@ -0,0 +1,18 @@
+using System;
+using Microsoft.Maui.Handlers;
+using UIKit;
+
+namespace Maui.FreakyControls;
+
+public partial class FreakyDeoPlayerHandler : ViewHandler
+{
+ public FreakyDeoPlayerHandler(IPropertyMapper mapper, CommandMapper commandMapper = null) : base(mapper, commandMapper)
+ {
+ }
+
+ protected override UIView CreatePlatformView()
+ {
+ return new UIView();
+ }
+}
+
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/iOS/FreakyDeoPlayerHandler.ios.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/iOS/FreakyDeoPlayerHandler.ios.cs
new file mode 100644
index 0000000..afa18ed
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/iOS/FreakyDeoPlayerHandler.ios.cs
@@ -0,0 +1,24 @@
+using System;
+namespace Maui.FreakyControls;
+
+public partial class FreakyDeoPlayerHandler
+{
+ protected override FreakyNativeiOSPlayer CreatePlatformView()
+ {
+ return new FreakyNativeiOSPlayer();
+ }
+
+ private void UpdateSource()
+ {
+
+ }
+
+ private void UpdateAutoPlay()
+ {
+
+ }
+
+ private void UpdateVolume() { }
+
+}
+
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/iOS/FreakyNativeiOSPlayer.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/iOS/FreakyNativeiOSPlayer.cs
new file mode 100644
index 0000000..8fc182c
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Platforms/iOS/FreakyNativeiOSPlayer.cs
@@ -0,0 +1,7 @@
+using System;
+namespace Maui.FreakyControls;
+
+public class FreakyNativeiOSPlayer : UIKit.UIView
+{
+}
+
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Converters/FileVideoSourceConverter.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Converters/FileVideoSourceConverter.cs
new file mode 100644
index 0000000..0cf6d68
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Converters/FileVideoSourceConverter.cs
@@ -0,0 +1,22 @@
+using System.ComponentModel;
+using System.Globalization;
+
+namespace Maui.FreakyControls;
+
+///
+/// A specific to converting a string value to a .
+///
+[TypeConverter(typeof(FileVideoSource))]
+public sealed class FileVideoSourceConverter : TypeConverter
+{
+ ///
+ /// Thrown when is or empty.
+ public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
+ {
+ var filePath = value?.ToString() ?? string.Empty;
+
+ return string.IsNullOrWhiteSpace(filePath)
+ ? (FileVideoSource)VideoSource.FromFile(filePath)
+ : throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(FileVideoSource)}");
+ }
+}
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Converters/ResourceVideoSource.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Converters/ResourceVideoSource.cs
new file mode 100644
index 0000000..cf62393
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Converters/ResourceVideoSource.cs
@@ -0,0 +1,48 @@
+using System.ComponentModel;
+
+namespace Maui.FreakyControls;
+
+///
+/// Represents a source, loaded from the application's resources, that can be played by .
+///
+[TypeConverter(typeof(FileVideoSourceConverter))]
+public sealed class ResourceVideoSource : VideoSource
+{
+ ///
+ /// Backing store for the property.
+ ///
+ public static readonly BindableProperty PathProperty
+ = BindableProperty.Create(nameof(Path), typeof(string), typeof(ResourceVideoSource), propertyChanged: OnResourceVideoSourceVideoSourceChanged);
+
+ ///
+ /// Gets or sets the full path to the resource file to use as a media source.
+ /// This is a bindable property.
+ ///
+ ///
+ /// Path is relative to the application's resources folder.
+ /// It can only be just a filename if the resource file is in the root of the resources folder.
+ ///
+ public string? Path
+ {
+ get => (string?)GetValue(PathProperty);
+ set => SetValue(PathProperty, value);
+ }
+
+ ///
+ public override string ToString() => $"Resource: {Path}";
+
+ ///
+ /// An implicit operator to convert a string value into a .
+ ///
+ /// Full path to the resource file, relative to the application's resources folder.
+ public static implicit operator ResourceVideoSource(string path) => (ResourceVideoSource)FromFile(path);
+
+ ///
+ /// An implicit operator to convert a into a string value.
+ ///
+ /// A instance to convert to a string value.
+ public static implicit operator string?(ResourceVideoSource? resourceVideoSource) => resourceVideoSource?.Path;
+
+ static void OnResourceVideoSourceVideoSourceChanged(BindableObject bindable, object oldValue, object newValue) =>
+ ((ResourceVideoSource)bindable).OnSourceChanged();
+}
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Extensions.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Extensions.cs
new file mode 100644
index 0000000..a723a59
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Extensions.cs
@@ -0,0 +1,25 @@
+using System.Windows.Input;
+
+namespace Maui.FreakyControls;
+
+public static class Extensions
+{
+ public static void ExecuteCommandIfAvailable(this ICommand command, object parameter = null)
+ {
+ if (command?.CanExecute(parameter) == true)
+ {
+ command.Execute(parameter);
+ }
+ }
+
+ public static MauiAppBuilder InitializeFreakyDeoPlayer(this MauiAppBuilder builder, bool useSkiaSharp = true)
+ {
+ builder.ConfigureMauiHandlers(builders => builders.AddHandlers());
+ return builder;
+ }
+
+ public static void AddHandlers(this IMauiHandlersCollection handlers)
+ {
+ handlers.AddHandler(typeof(FreakyDeoPlayer),typeof(FreakyDeoPlayerHandler));
+ }
+}
\ No newline at end of file
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/FreakyDeoPlayer.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/FreakyDeoPlayer.cs
new file mode 100644
index 0000000..ee01428
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/FreakyDeoPlayer.cs
@@ -0,0 +1,49 @@
+namespace Maui.FreakyControls;
+
+public class FreakyDeoPlayer : View
+{
+ public static readonly BindableProperty SourceProperty = BindableProperty.Create(
+ nameof(Source),
+ typeof(VideoSource),
+ typeof(FreakyDeoPlayer),
+ default(VideoSource));
+
+ public VideoSource Source
+ {
+ get => (VideoSource)GetValue(SourceProperty);
+ set => SetValue(SourceProperty, value);
+ }
+
+ public static readonly BindableProperty AutoPlayProperty = BindableProperty.Create(
+ nameof(AutoPlay),
+ typeof(bool),
+ typeof(FreakyDeoPlayer),
+ default(bool));
+
+ public bool AutoPlay
+ {
+ get => (bool)GetValue(AutoPlayProperty);
+ set => SetValue(AutoPlayProperty, value);
+ }
+
+ public static readonly BindableProperty VolumeProperty = BindableProperty.Create(
+ nameof(Volume),
+ typeof(double),
+ typeof(FreakyDeoPlayer),
+ 1.0,
+ BindingMode.TwoWay,
+ new BindableProperty.ValidateValueDelegate(ValidateVolume));
+
+ private static bool ValidateVolume(BindableObject bindable, object value)
+ {
+ var volume = (double)value;
+ return volume >= 0.0 && volume <= 1.0;
+ }
+
+ public double Volume
+ {
+ get => (double)GetValue(VolumeProperty);
+ set => SetValue(VolumeProperty, value);
+ }
+}
+
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/FreakyDeoPlayerHandler.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/FreakyDeoPlayerHandler.cs
new file mode 100644
index 0000000..00d13d5
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/FreakyDeoPlayerHandler.cs
@@ -0,0 +1,57 @@
+using System;
+using Microsoft.Maui.Handlers;
+#if ANDROID
+using NativeVideoPlayer = Maui.FreakyControls.FreakyNativeAndroidPlayer;
+#elif IOS
+using NativeVideoPlayer = Maui.FreakyControls.FreakyNativeiOSPlayer;
+#endif
+namespace Maui.FreakyControls;
+
+#if ANDROID || IOS
+public partial class FreakyDeoPlayerHandler : ViewHandler
+{
+
+ public static PropertyMapper Mapper =
+ new(ViewHandler.ViewMapper)
+ {
+ [nameof(FreakyDeoPlayer.Source)] = MapSource,
+ [nameof(FreakyDeoPlayer.AutoPlay)]= MapAutoPlay,
+ [nameof(FreakyDeoPlayer.Volume)] = MapVolume,
+ };
+
+ private static void MapVolume(FreakyDeoPlayerHandler handler, FreakyDeoPlayer view)
+ {
+ handler.UpdateVolume();
+ }
+
+ private static void MapAutoPlay(FreakyDeoPlayerHandler handler, FreakyDeoPlayer view)
+ {
+ handler.UpdateAutoPlay();
+ }
+
+ private static void MapSource(FreakyDeoPlayerHandler handler, FreakyDeoPlayer view)
+ {
+ handler.UpdateSource();
+ }
+
+ public static CommandMapper CommandMapper =
+ new(ViewHandler.ViewCommandMapper)
+ {
+ };
+
+ public FreakyDeoPlayerHandler() : base(Mapper)
+ {
+ }
+
+ public FreakyDeoPlayerHandler(IPropertyMapper? mapper)
+ : base(mapper ?? Mapper, CommandMapper)
+ {
+ }
+
+ public FreakyDeoPlayerHandler(IPropertyMapper? mapper, CommandMapper? commandMapper)
+ : base(mapper ?? Mapper, commandMapper ?? CommandMapper)
+ {
+ }
+
+}
+#endif
\ No newline at end of file
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/FileVideoSource.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/FileVideoSource.cs
new file mode 100644
index 0000000..9007c1d
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/FileVideoSource.cs
@@ -0,0 +1,44 @@
+using System.ComponentModel;
+
+namespace Maui.FreakyControls;
+
+///
+/// Represents a source, loaded from local filesystem, that can be played by .
+///
+[TypeConverter(typeof(FileVideoSourceConverter))]
+public sealed class FileVideoSource : VideoSource
+{
+ ///
+ /// Backing store for the property.
+ ///
+ public static readonly BindableProperty PathProperty
+ = BindableProperty.Create(nameof(Path), typeof(string), typeof(FileVideoSource), propertyChanged: OnFileVideoSourceChanged);
+
+ ///
+ /// Gets or sets the full path to the local file to use as a media source.
+ /// This is a bindable property.
+ ///
+ public string? Path
+ {
+ get => (string?)GetValue(PathProperty);
+ set => SetValue(PathProperty, value);
+ }
+
+ ///
+ /// An implicit operator to convert a string value into a .
+ ///
+ /// Full path to the local file. Can be a relative or absolute path.
+ public static implicit operator FileVideoSource(string path) => (FileVideoSource)FromFile(path);
+
+ ///
+ /// An implicit operator to convert a into a string value.
+ ///
+ /// A instance to convert to a string value.
+ public static implicit operator string?(FileVideoSource? fileVideoSource) => fileVideoSource?.Path;
+
+ ///
+ public override string ToString() => $"File: {Path}";
+
+ static void OnFileVideoSourceChanged(BindableObject bindable, object oldValue, object newValue) =>
+ ((FileVideoSource)bindable).OnSourceChanged();
+}
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/UriVideoSource.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/UriVideoSource.cs
new file mode 100644
index 0000000..d9bbbbd
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/UriVideoSource.cs
@@ -0,0 +1,48 @@
+using System.ComponentModel;
+
+namespace Maui.FreakyControls;
+
+///
+/// Represents a source, loaded from a remote URI, that can be played by .
+///
+public sealed class UriVideoSource : VideoSource
+{
+ ///
+ /// Backing store for the property.
+ ///
+ public static readonly BindableProperty UriProperty =
+ BindableProperty.Create(nameof(Uri), typeof(Uri), typeof(UriVideoSource), propertyChanged: OnUriSourceChanged, validateValue: UriValueValidator);
+
+ ///
+ /// Gets or sets the URI to use as a media source.
+ /// This is a bindable property.
+ ///
+ /// The URI has to be absolute.
+ [TypeConverter(typeof(Microsoft.Maui.Controls.UriTypeConverter))]
+ public Uri? Uri
+ {
+ get => (Uri?)GetValue(UriProperty);
+ set => SetValue(UriProperty, value);
+ }
+
+ ///
+ public override string ToString() => $"Uri: {Uri}";
+
+ ///
+ /// An implicit operator to convert a string value into a .
+ ///
+ /// Full path to the resource file, relative to the application's resources folder.
+ public static implicit operator UriVideoSource?(string uri) => (UriVideoSource?)FromUri(uri);
+
+ ///
+ /// An implicit operator to convert a into a string value.
+ ///
+ /// A instance to convert to a string value.
+ public static implicit operator string?(UriVideoSource? uriVideoSource) => uriVideoSource?.Uri?.ToString();
+
+ static bool UriValueValidator(BindableObject bindable, object value) =>
+ value is null || ((Uri)value).IsAbsoluteUri;
+
+ static void OnUriSourceChanged(BindableObject bindable, object oldValue, object newValue) =>
+ ((UriVideoSource)bindable).OnSourceChanged();
+}
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/VideoSource.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/VideoSource.cs
new file mode 100644
index 0000000..633d191
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/VideoSource.cs
@@ -0,0 +1,83 @@
+using System;
+using System.ComponentModel;
+using System.Globalization;
+
+namespace Maui.FreakyControls;
+
+///
+/// Represents a source that can be played by .
+///
+[TypeConverter(typeof(VideoSourceConverter))]
+public abstract class VideoSource : Element
+{
+ readonly WeakEventManager weakEventManager = new();
+
+ internal event EventHandler SourceChanged
+ {
+ add => weakEventManager.AddEventHandler(value);
+ remove => weakEventManager.RemoveEventHandler(value);
+ }
+
+ ///
+ /// An implicit operator to convert a string value into a .
+ ///
+ /// Full path to a local file (starting with file://) or an absolute URI.
+ public static implicit operator VideoSource?(string? source) =>
+ Uri.TryCreate(source, UriKind.Absolute, out var uri) && uri.Scheme != "file"
+ ? FromUri(uri)
+ : FromFile(source);
+
+ ///
+ /// An implicit operator to convert a object into a .
+ ///
+ /// Absolute URI to load.
+ public static implicit operator VideoSource?(Uri? uri) => FromUri(uri);
+
+ ///
+ /// Creates a from an absolute URI.
+ ///
+ /// Full path to the resource file, relative to the application's resources folder.
+ /// A instance.
+ public static VideoSource FromResource(string? path) => new ResourceVideoSource { Path = path };
+
+ ///
+ /// Creates a from an string that contains an absolute URI.
+ ///
+ /// String representation or an absolute URI to load.
+ /// A instance.
+ /// Thrown if is not an absolute URI.
+ public static VideoSource? FromUri(string uri) => FromUri(new Uri(uri));
+
+ ///
+ /// Creates a from a local path.
+ ///
+ /// Full path to the file to load.
+ /// A instance.
+ public static VideoSource FromFile(string? path) => new FileVideoSource { Path = path };
+
+ ///
+ /// Creates a from an absolute URI.
+ ///
+ /// Absolute URI to load.
+ /// A instance.
+ /// Thrown if is not an absolute URI.
+ public static VideoSource? FromUri(Uri? uri)
+ {
+ if (uri is null)
+ {
+ return null;
+ }
+
+ if (!uri.IsAbsoluteUri)
+ {
+ throw new ArgumentException("Uri must be absolute", nameof(uri));
+ }
+
+ return new UriVideoSource { Uri = uri };
+ }
+
+ ///
+ /// Triggers the event.
+ ///
+ protected void OnSourceChanged() => weakEventManager.HandleEvent(this, EventArgs.Empty, nameof(SourceChanged));
+}
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/VideoSourceConverter.cs b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/VideoSourceConverter.cs
new file mode 100644
index 0000000..d5f6588
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/Shared/Source/VideoSourceConverter.cs
@@ -0,0 +1,58 @@
+using System.ComponentModel;
+using System.Globalization;
+
+namespace Maui.FreakyControls;
+
+///
+/// A specific to converting a string value to a .
+///
+public sealed class VideoSourceConverter : TypeConverter
+{
+ const string embeddedResourcePrefix = "embed://";
+ const string fileSystemPrefix = "filesystem://";
+
+ ///
+ public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
+ => sourceType == typeof(string);
+
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
+ => destinationType == typeof(string);
+
+ ///
+ public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
+ {
+ var valueAsString = value?.ToString() ?? string.Empty;
+
+ if (string.IsNullOrWhiteSpace(valueAsString))
+ {
+ return null;
+ }
+
+ var valueAsStringLowercase = valueAsString.ToLowerInvariant();
+
+ if (valueAsStringLowercase.StartsWith(embeddedResourcePrefix))
+ {
+ return VideoSource.FromResource(
+ valueAsString[embeddedResourcePrefix.Length..]);
+ }
+ else if (valueAsStringLowercase.StartsWith(fileSystemPrefix))
+ {
+ return VideoSource.FromFile(valueAsString[fileSystemPrefix.Length..]);
+ }
+
+ return Uri.TryCreate(valueAsString, UriKind.Absolute, out var uri) && uri.Scheme != "file"
+ ? VideoSource.FromUri(uri)
+ : VideoSource.FromFile(valueAsString);
+ }
+
+ ///
+ public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) => value switch
+ {
+ UriVideoSource uriVideoSource => uriVideoSource.ToString(),
+ FileVideoSource fileVideoSource => fileVideoSource.ToString(),
+ ResourceVideoSource resourceVideoSource => resourceVideoSource.ToString(),
+ VideoSource => string.Empty,
+ _ => throw new ArgumentException($"Invalid Media Source", nameof(value))
+ };
+}
\ No newline at end of file
diff --git a/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/maui_toolkit.png b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/maui_toolkit.png
new file mode 100644
index 0000000..5883dc8
Binary files /dev/null and b/Maui.FreakyControls/Maui.FreakyControls.FreakyDeoPlayer/maui_toolkit.png differ
diff --git a/Maui.FreakyControls/Maui.FreakyControls.sln b/Maui.FreakyControls/Maui.FreakyControls.sln
new file mode 100644
index 0000000..78d8d49
--- /dev/null
+++ b/Maui.FreakyControls/Maui.FreakyControls.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 25.0.1704.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreakyDeoPlayer", "Maui.FreakyControls.FreakyDeoPlayer\FreakyDeoPlayer.csproj", "{9A8E6659-EE0A-4CB2-BDEC-3681C1DD86BB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples", "Samples\Samples.csproj", "{E4397609-79B1-4F3F-AD6B-73AF93624A2F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9A8E6659-EE0A-4CB2-BDEC-3681C1DD86BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9A8E6659-EE0A-4CB2-BDEC-3681C1DD86BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9A8E6659-EE0A-4CB2-BDEC-3681C1DD86BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9A8E6659-EE0A-4CB2-BDEC-3681C1DD86BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E4397609-79B1-4F3F-AD6B-73AF93624A2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E4397609-79B1-4F3F-AD6B-73AF93624A2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E4397609-79B1-4F3F-AD6B-73AF93624A2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E4397609-79B1-4F3F-AD6B-73AF93624A2F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B64B74B2-595A-480B-9B6D-0759A0C12564}
+ EndGlobalSection
+EndGlobal
diff --git a/Maui.FreakyControls/Samples/App.xaml b/Maui.FreakyControls/Samples/App.xaml
new file mode 100644
index 0000000..58ffc95
--- /dev/null
+++ b/Maui.FreakyControls/Samples/App.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Maui.FreakyControls/Samples/App.xaml.cs b/Maui.FreakyControls/Samples/App.xaml.cs
new file mode 100644
index 0000000..923ddbc
--- /dev/null
+++ b/Maui.FreakyControls/Samples/App.xaml.cs
@@ -0,0 +1,12 @@
+namespace Samples;
+
+public partial class App : Application
+{
+ public App()
+ {
+ InitializeComponent();
+
+ MainPage = new AppShell();
+ }
+}
+
diff --git a/Maui.FreakyControls/Samples/AppShell.xaml b/Maui.FreakyControls/Samples/AppShell.xaml
new file mode 100644
index 0000000..8ece334
--- /dev/null
+++ b/Maui.FreakyControls/Samples/AppShell.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/Maui.FreakyControls/Samples/AppShell.xaml.cs b/Maui.FreakyControls/Samples/AppShell.xaml.cs
new file mode 100644
index 0000000..1609efb
--- /dev/null
+++ b/Maui.FreakyControls/Samples/AppShell.xaml.cs
@@ -0,0 +1,10 @@
+namespace Samples;
+
+public partial class AppShell : Shell
+{
+ public AppShell()
+ {
+ InitializeComponent();
+ }
+}
+
diff --git a/Maui.FreakyControls/Samples/MainPage.xaml b/Maui.FreakyControls/Samples/MainPage.xaml
new file mode 100644
index 0000000..ef4aeb7
--- /dev/null
+++ b/Maui.FreakyControls/Samples/MainPage.xaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/Maui.FreakyControls/Samples/MainPage.xaml.cs b/Maui.FreakyControls/Samples/MainPage.xaml.cs
new file mode 100644
index 0000000..23c9848
--- /dev/null
+++ b/Maui.FreakyControls/Samples/MainPage.xaml.cs
@@ -0,0 +1,11 @@
+namespace Samples;
+
+public partial class MainPage : ContentPage
+{
+ public MainPage()
+ {
+ InitializeComponent();
+ }
+
+ public string VideoUrl => "https://dsqqu7oxq6o1v.cloudfront.net/preview-9650dW8x3YLoZ8.mp4";
+}
\ No newline at end of file
diff --git a/Maui.FreakyControls/Samples/MauiProgram.cs b/Maui.FreakyControls/Samples/MauiProgram.cs
new file mode 100644
index 0000000..a39a9e6
--- /dev/null
+++ b/Maui.FreakyControls/Samples/MauiProgram.cs
@@ -0,0 +1,21 @@
+using Maui.FreakyControls;
+
+namespace Samples;
+
+public static class MauiProgram
+{
+ public static MauiApp CreateMauiApp()
+ {
+ var builder = MauiApp.CreateBuilder();
+ builder
+ .UseMauiApp()
+ .ConfigureFonts(fonts =>
+ {
+ fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ });
+
+ builder.InitializeFreakyDeoPlayer();
+ return builder.Build();
+ }
+}
\ No newline at end of file
diff --git a/Maui.FreakyControls/Samples/Platforms/Android/AndroidManifest.xml b/Maui.FreakyControls/Samples/Platforms/Android/AndroidManifest.xml
new file mode 100644
index 0000000..e41bece
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Platforms/Android/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Maui.FreakyControls/Samples/Platforms/Android/MainActivity.cs b/Maui.FreakyControls/Samples/Platforms/Android/MainActivity.cs
new file mode 100644
index 0000000..c95e72e
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Platforms/Android/MainActivity.cs
@@ -0,0 +1,11 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+
+namespace Samples;
+
+[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
+public class MainActivity : MauiAppCompatActivity
+{
+}
+
diff --git a/Maui.FreakyControls/Samples/Platforms/Android/MainApplication.cs b/Maui.FreakyControls/Samples/Platforms/Android/MainApplication.cs
new file mode 100644
index 0000000..a105249
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Platforms/Android/MainApplication.cs
@@ -0,0 +1,16 @@
+using Android.App;
+using Android.Runtime;
+
+namespace Samples;
+
+[Application]
+public class MainApplication : MauiApplication
+{
+ public MainApplication(IntPtr handle, JniHandleOwnership ownership)
+ : base(handle, ownership)
+ {
+ }
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
+
diff --git a/Maui.FreakyControls/Samples/Platforms/Android/Resources/values/colors.xml b/Maui.FreakyControls/Samples/Platforms/Android/Resources/values/colors.xml
new file mode 100644
index 0000000..c2794f7
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Platforms/Android/Resources/values/colors.xml
@@ -0,0 +1,7 @@
+
+
+ #512BD4
+ #2B0B98
+ #2B0B98
+
+
diff --git a/Maui.FreakyControls/Samples/Platforms/iOS/AppDelegate.cs b/Maui.FreakyControls/Samples/Platforms/iOS/AppDelegate.cs
new file mode 100644
index 0000000..69ca4af
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Platforms/iOS/AppDelegate.cs
@@ -0,0 +1,10 @@
+using Foundation;
+
+namespace Samples;
+
+[Register("AppDelegate")]
+public class AppDelegate : MauiUIApplicationDelegate
+{
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
+
diff --git a/Maui.FreakyControls/Samples/Platforms/iOS/Info.plist b/Maui.FreakyControls/Samples/Platforms/iOS/Info.plist
new file mode 100644
index 0000000..358337b
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Platforms/iOS/Info.plist
@@ -0,0 +1,32 @@
+
+
+
+
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+
+
diff --git a/Maui.FreakyControls/Samples/Platforms/iOS/Program.cs b/Maui.FreakyControls/Samples/Platforms/iOS/Program.cs
new file mode 100644
index 0000000..3908ab1
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Platforms/iOS/Program.cs
@@ -0,0 +1,16 @@
+using ObjCRuntime;
+using UIKit;
+
+namespace Samples;
+
+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));
+ }
+}
+
diff --git a/Maui.FreakyControls/Samples/Resources/AppIcon/appicon.svg b/Maui.FreakyControls/Samples/Resources/AppIcon/appicon.svg
new file mode 100644
index 0000000..49f9800
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Resources/AppIcon/appicon.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/Maui.FreakyControls/Samples/Resources/AppIcon/appiconfg.svg b/Maui.FreakyControls/Samples/Resources/AppIcon/appiconfg.svg
new file mode 100644
index 0000000..e9b7139
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Resources/AppIcon/appiconfg.svg
@@ -0,0 +1,8 @@
+
+
+
diff --git a/Maui.FreakyControls/Samples/Resources/Fonts/OpenSans-Regular.ttf b/Maui.FreakyControls/Samples/Resources/Fonts/OpenSans-Regular.ttf
new file mode 100644
index 0000000..8dc12bb
Binary files /dev/null and b/Maui.FreakyControls/Samples/Resources/Fonts/OpenSans-Regular.ttf differ
diff --git a/Maui.FreakyControls/Samples/Resources/Fonts/OpenSans-Semibold.ttf b/Maui.FreakyControls/Samples/Resources/Fonts/OpenSans-Semibold.ttf
new file mode 100644
index 0000000..7a6e9fb
Binary files /dev/null and b/Maui.FreakyControls/Samples/Resources/Fonts/OpenSans-Semibold.ttf differ
diff --git a/Maui.FreakyControls/Samples/Resources/Images/dotnet_bot.svg b/Maui.FreakyControls/Samples/Resources/Images/dotnet_bot.svg
new file mode 100644
index 0000000..e19b012
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Resources/Images/dotnet_bot.svg
@@ -0,0 +1,95 @@
+
+
+
diff --git a/Maui.FreakyControls/Samples/Resources/Raw/AboutAssets.txt b/Maui.FreakyControls/Samples/Resources/Raw/AboutAssets.txt
new file mode 100644
index 0000000..808d6d3
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Resources/Raw/AboutAssets.txt
@@ -0,0 +1,17 @@
+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`.
+
+
+
+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();
+ }
+
+
diff --git a/Maui.FreakyControls/Samples/Resources/Splash/splash.svg b/Maui.FreakyControls/Samples/Resources/Splash/splash.svg
new file mode 100644
index 0000000..4b71383
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Resources/Splash/splash.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/Maui.FreakyControls/Samples/Resources/Styles/Colors.xaml b/Maui.FreakyControls/Samples/Resources/Styles/Colors.xaml
new file mode 100644
index 0000000..e4a7a43
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Resources/Styles/Colors.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+ #512BD4
+ #DFD8F7
+ #2B0B98
+ White
+ Black
+ #E1E1E1
+ #C8C8C8
+ #ACACAC
+ #919191
+ #6E6E6E
+ #404040
+ #212121
+ #141414
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #F7B548
+ #FFD590
+ #FFE5B9
+ #28C2D1
+ #7BDDEF
+ #C3F2F4
+ #3E8EED
+ #72ACF1
+ #A7CBF6
+
+
diff --git a/Maui.FreakyControls/Samples/Resources/Styles/Styles.xaml b/Maui.FreakyControls/Samples/Resources/Styles/Styles.xaml
new file mode 100644
index 0000000..d23a11d
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Resources/Styles/Styles.xaml
@@ -0,0 +1,406 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Maui.FreakyControls/Samples/Samples.csproj b/Maui.FreakyControls/Samples/Samples.csproj
new file mode 100644
index 0000000..000e997
--- /dev/null
+++ b/Maui.FreakyControls/Samples/Samples.csproj
@@ -0,0 +1,56 @@
+
+
+
+ net8.0-android;net8.0-ios
+ Exe
+ Samples
+ true
+ true
+ enable
+
+
+ Samples
+
+
+ com.companyname.samples
+ c2072737-65fc-458e-8427-dd3b01d75634
+
+
+ 1.0
+ 1
+
+ 11.0
+ 21.0
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index bfe803d..9f69de6 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-# Maui.FreakyControls.FreakyDeoPlayer
\ No newline at end of file
+# FreakyDeoPlayer