Skip to content

Commit

Permalink
MaterialCalendarView
Browse files Browse the repository at this point in the history
  • Loading branch information
VladislavAntonyuk committed Dec 24, 2023
1 parent e8d1272 commit 3b1c583
Show file tree
Hide file tree
Showing 12 changed files with 270 additions and 6 deletions.
10 changes: 10 additions & 0 deletions AndroidBindableLibraries/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Project>
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Additions allow you to add arbitrary C# to the generated classes
before they are compiled. This can be helpful for providing convenience
methods or adding pure C# classes.

== Adding Methods to Generated Classes ==

Let's say the library being bound has a Rectangle class with a constructor
that takes an x and y position, and a width and length size. It will look like
this:

public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}

Imagine we want to add a constructor to this class that takes a Point and
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
with a partial class containing our new method:

public partial class Rectangle
{
public Rectangle (Point location, Size size) :
this (location.X, location.Y, size.Width, size.Height)
{
}
}

At compile time, the additions class will be added to the generated class
and the final assembly will a Rectangle class with both constructors.


== Adding C# Classes ==

Another thing that can be done is adding fully C# managed classes to the
generated library. In the above example, let's assume that there isn't a
Point class available in Java or our library. The one we create doesn't need
to interact with Java, so we'll create it like a normal class in C#.

By adding a Point.cs file with this class, it will end up in the binding library:

public class Point
{
public int X { get; set; }
public int Y { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<SupportedOSPlatformVersion>23</SupportedOSPlatformVersion>
<PackageId>VladislavAntonyuk.$(AssemblyName)</PackageId>
<Version>1.9.0</Version>
<PackageReadmeFile>ReadMe.md</PackageReadmeFile>
<PackageOutputPath>..\..\LocalPackages\</PackageOutputPath>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="XamPrototype.Android.MavenBinding.Tasks" Version="0.0.11" />
</ItemGroup>

<ItemGroup>
<!-- Include format is {GroupId}:{ArtifactId} -->
<AndroidMavenLibrary Include="org.jetbrains.kotlin:kotlin-android-extensions-runtime" Version="1.6.10" Bind="false" />
<AndroidMavenLibrary Include="com.annimon:stream" Version="1.2.2" Bind="false" />
<AndroidMavenLibrary Include="com.applandeo:material-calendar-view" Version="1.9.0" />
<PackageReference Include="Xamarin.AndroidX.AppCompat">
<Version>1.6.1.6</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.ConstraintLayout">
<Version>2.1.4.9</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Core.Core.Ktx">
<Version>1.12.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Kotlin.StdLib">
<Version>1.9.21.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Kotlin.StdLib.Jdk8">
<Version>1.9.21.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.AndroidX.Collection" Version="1.3.0.2" />
<PackageReference Include="Xamarin.AndroidX.Collection.Jvm" Version="1.3.0.2" />
<PackageReference Include="Xamarin.AndroidX.Collection.Ktx" Version="1.3.0.2" />

<PackageReference Include="Xamarin.AndroidX.Fragment.Ktx ">
<Version>1.6.2.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Update="ReadMe.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions AndroidBindableLibraries/MaterialCalendarView/ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Android Material Calendar View

Android Java Library Binding for [Material Calendar View](https://github.com/Applandeo/Material-Calendar-View)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<enum-field-mappings>
<!--
This example converts the constants Fragment_id, Fragment_name,
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
to an enum called Android.Support.V4.App.FragmentTagType with values
Id, Name, and Tag.
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
<field jni-name="Fragment_name" clr-name="Name" value="0" />
<field jni-name="Fragment_id" clr-name="Id" value="1" />
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
</mapping>
-->
</enum-field-mappings>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<enum-method-mappings>
<!--
This example changes the Java method:
android.support.v4.app.Fragment.SavedState.writeToParcel (int flags)
to be:
android.support.v4.app.Fragment.SavedState.writeToParcel (Android.OS.ParcelableWriteFlags flags)
when bound in C#.
<mapping jni-class="android/support/v4/app/Fragment.SavedState">
<method jni-name="writeToParcel" parameter="flags" clr-enum-type="Android.OS.ParcelableWriteFlags" />
</mapping>
-->
</enum-method-mappings>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<metadata>
<!--
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
-->
</metadata>
7 changes: 6 additions & 1 deletion MauiBells/MauiBells.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@

<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Plugin.Maui.Audio" Version="3.0.0-preview2" />
<PackageReference Include="Plugin.Maui.Audio" Version="3.0.0-preview2" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == '$(NetVersion)-android'">
<PackageReference Include="VladislavAntonyuk.MaterialCalendarView" Version="1.9.0" />
</ItemGroup>
</Project>
6 changes: 5 additions & 1 deletion MauiBells/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ public static MauiApp CreateMauiApp()
builder.UseMauiApp<App>()
.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler<CalendarView, CalendarHandler>();
#if ANDROID
handlers.AddHandler<ICalendarView, CalendarMaterialHandler>();
#else
handlers.AddHandler<CalendarView, CalendarHandler>();
#endif
});

return builder.Build();
Expand Down
99 changes: 99 additions & 0 deletions MauiBells/Platforms/Android/CalendarMaterialHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
namespace MauiBells.Calendar;

using System.ComponentModel;
using Android;
using Com.Applandeo.Materialcalendarview;
using Com.Applandeo.Materialcalendarview.Listeners;
using Java.Lang;
using Microsoft.Maui.Handlers;
using Calendar = Com.Applandeo.Materialcalendarview.CalendarView;

public class CalendarMaterialHandler(IPropertyMapper mapper, CommandMapper? commandMapper = null) : ViewHandler<ICalendarView, Calendar>(mapper, commandMapper)
{
public static IPropertyMapper<ICalendarView, CalendarMaterialHandler> PropertyMapper = new PropertyMapper<ICalendarView, CalendarMaterialHandler>(ViewMapper)
{
[nameof(ICalendarView.FirstDayOfWeek)] = MapFirstDayOfWeek,
[nameof(ICalendarView.MinDate)] = MapMinDate,
[nameof(ICalendarView.MaxDate)] = MapMaxDate,
[nameof(ICalendarView.SelectedDate)] = MapSelectedDate,
};

public static CommandMapper<ICalendarView, CalendarMaterialHandler> CommandMapper = new(ViewCommandMapper);

public CalendarMaterialHandler() : this(PropertyMapper, CommandMapper)
{
}

protected override Calendar CreatePlatformView()
{
return new Calendar(Context);
}

protected override void ConnectHandler(Calendar platformView)
{
base.ConnectHandler(platformView);
platformView.CalendarDayClick += PlatformView_SelectedDatesChanged;
}

private void PlatformView_SelectedDatesChanged(object? sender, CalendarDayClickEventArgs e)
{
var calendar = e.CalendarDay.Calendar;
var time = TimeSpan.FromMilliseconds(calendar.TimeInMillis);
var result = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
VirtualView.SelectedDate = new DateTimeOffset(result.Add(time).Add(TimeSpan.FromMilliseconds(calendar.TimeZone.RawOffset)));
VirtualView.OnSelectedDateChanged(VirtualView.SelectedDate);
}

protected override void DisconnectHandler(Calendar platformView)
{
platformView.CalendarDayClick -= PlatformView_SelectedDatesChanged;
base.DisconnectHandler(platformView);
}

private static void MapFirstDayOfWeek(CalendarMaterialHandler handler, ICalendarView virtualView)
{
var calendarWeekDate = virtualView.FirstDayOfWeek switch
{
DayOfWeek.Sunday => CalendarWeekDay.Sunday,
DayOfWeek.Monday => CalendarWeekDay.Monday,
DayOfWeek.Tuesday => CalendarWeekDay.Tuesday,
DayOfWeek.Wednesday => CalendarWeekDay.Wednesday,
DayOfWeek.Thursday => CalendarWeekDay.Thursday,
DayOfWeek.Friday => CalendarWeekDay.Friday,
DayOfWeek.Saturday => CalendarWeekDay.Saturday,
_ => throw new InvalidEnumArgumentException(),
};
ArgumentNullException.ThrowIfNull(calendarWeekDate);
handler.PlatformView.SetFirstDayOfWeek(calendarWeekDate);
}

private static void MapMinDate(CalendarMaterialHandler handler, ICalendarView virtualView)
{
var calendar = Java.Util.Calendar.Instance;
calendar.Set(virtualView.MinDate.Year, virtualView.MinDate.Month - 1, virtualView.MinDate.Day);
handler.PlatformView.SetMinimumDate(calendar);
}

private static void MapMaxDate(CalendarMaterialHandler handler, ICalendarView virtualView)
{
var calendar = Java.Util.Calendar.Instance;
calendar.Set(virtualView.MaxDate.Year, virtualView.MaxDate.Month - 1, virtualView.MaxDate.Day);
handler.PlatformView.SetMaximumDate(calendar);
}

private static void MapSelectedDate(CalendarMaterialHandler handler, ICalendarView virtualView)
{
if (virtualView.SelectedDate is null)
{
return;
}

var calendar = Java.Util.Calendar.Instance;
calendar.Set(virtualView.SelectedDate.Value.Year, virtualView.SelectedDate.Value.Month - 1, virtualView.SelectedDate.Value.Day);
List<CalendarDay> events = new();
var day = new CalendarDay(calendar);
day.BackgroundResource = Integer.ValueOf(Resource.Color.HoloRedDark);
events.Add(day);
handler.PlatformView.SetCalendarDays(events);
}
}
15 changes: 12 additions & 3 deletions MauiSamples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BottomSheet", "BottomSheet\BottomSheet.csproj", "{29FEFF3E-62BD-4156-993A-7264EC281AA9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "iOSExtensions", "iOSExtensions", "{F215B6A7-4C79-4415-95D2-6F561143C9AC}"
ProjectSection(SolutionItems) = preProject
iOSExtensions\Directory.Build.props = iOSExtensions\Directory.Build.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppContainer", "iOSExtensions\ShareExtension\AppContainer\AppContainer.csproj", "{E3B8C927-987B-410C-9B8F-9C683B2F494A}"
EndProject
Expand Down Expand Up @@ -126,6 +123,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Database", "Database", "{D3
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiTaskListApp", "Database\MauiTaskListApp\MauiTaskListApp.csproj", "{08096F4C-2BB3-4860-B0CA-9EC6A09EC377}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AndroidBindableLibraries", "AndroidBindableLibraries", "{E08722A6-C1B6-4C83-983C-809BF721D6F1}"
ProjectSection(SolutionItems) = preProject
AndroidBindableLibraries\Directory.Build.props = AndroidBindableLibraries\Directory.Build.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialCalendarView", "AndroidBindableLibraries\MaterialCalendarView\MaterialCalendarView.csproj", "{42DD8662-FBD2-47B8-8740-17807E17EF5A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -372,6 +376,10 @@ Global
{08096F4C-2BB3-4860-B0CA-9EC6A09EC377}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08096F4C-2BB3-4860-B0CA-9EC6A09EC377}.Release|Any CPU.Build.0 = Release|Any CPU
{08096F4C-2BB3-4860-B0CA-9EC6A09EC377}.Release|Any CPU.Deploy.0 = Release|Any CPU
{42DD8662-FBD2-47B8-8740-17807E17EF5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42DD8662-FBD2-47B8-8740-17807E17EF5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42DD8662-FBD2-47B8-8740-17807E17EF5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42DD8662-FBD2-47B8-8740-17807E17EF5A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -392,6 +400,7 @@ Global
{8CE62F62-CE5D-48F4-8754-3F07FF72C3C2} = {D7258BEF-416D-4F3E-A359-87BD545A84A9}
{4C3F6E69-0FB4-41D5-8D8F-2E48B033A3EF} = {CE4ABC8D-3F54-49AA-BA5A-DD47E7CEB56B}
{08096F4C-2BB3-4860-B0CA-9EC6A09EC377} = {D3C704D0-FB95-42BA-BBF1-E7360491551F}
{42DD8662-FBD2-47B8-8740-17807E17EF5A} = {E08722A6-C1B6-4C83-983C-809BF721D6F1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572}
Expand Down
2 changes: 1 addition & 1 deletion NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<!-- <add key="LocalPackages" value="LocalPackages"/> -->
<add key="LocalPackages" value="LocalPackages"/>
</packageSources>
<packageRestore>
<add key="enabled" value="True" />
Expand Down

0 comments on commit 3b1c583

Please sign in to comment.