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