Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/PJ.ContextActions.Maui/AppBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace PJ.ContextActions.Maui;
public static class AppBuilderExtensions
{
public static MauiAppBuilder UseContextActions(this MauiAppBuilder builder)
{
builder.ConfigureMauiHandlers(h =>
{
h.AddHandler(typeof(CollectionView), typeof(PJCollectionViewHandler));
});

return builder;
}
}
142 changes: 142 additions & 0 deletions src/PJ.ContextActions.Maui/PJCollectionViewHandler.android.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using Android.Content;
using Android.Views;
using AndroidX.RecyclerView.Widget;
using Microsoft.Maui.Controls.Handlers.Items;

namespace PJ.ContextActions.Maui;

sealed class PJCollectionViewHandler : CollectionViewHandler
{
protected override ReorderableItemsViewAdapter<ReorderableItemsView, IGroupableItemsViewSource> CreateAdapter()
{
return new PJViewAdapter(VirtualView);
}
}


sealed class PJViewAdapter : ReorderableItemsViewAdapter<ReorderableItemsView, IGroupableItemsViewSource>
{
IGroupableItemsViewSource itemsSource = default!;
ReorderableItemsView collectionView;

internal static MenuItem[]? MenuItems;
public PJViewAdapter(ReorderableItemsView reorderableItemsView, Func<Microsoft.Maui.Controls.View, Context, ItemContentView>? createView = null) : base(reorderableItemsView, createView)
{
collectionView = reorderableItemsView;
}

protected override IGroupableItemsViewSource CreateItemsSource()
{
return ItemsSource = base.CreateItemsSource();
}

public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
base.OnBindViewHolder(holder, position);

if (collectionView is not CollectionView cv)
{
return;
}

var contextActions = ContextActions.GetContextActions(cv);

if (contextActions.Count is 0)
{
return;
}

if (MenuItems is null)
{
MenuItems = new MenuItem[contextActions.Count];

foreach (var (index, item) in contextActions.Index())
{
item.BindingContext = cv.BindingContext;
MenuItems[index] = item;
}
}

position -= itemsSource.HasHeader ? 1 : 0;

var size = itemsSource.Count - (itemsSource.HasHeader ? 1 : 0) - (itemsSource.HasHeader ? 1 : 0);

if (position >= 0 && position < size)
{
var element = itemsSource.GetItem(position + 1);

}
}

public override void OnViewRecycled(Java.Lang.Object holder)
{
base.OnViewRecycled(holder);

if (holder is RecyclerView.ViewHolder viewHolder)
{
viewHolder.ItemView.SetOnCreateContextMenuListener(null);
}
}
}

sealed class ItemContextMenuListener : Java.Lang.Object, global::Android.Views.View.IOnCreateContextMenuListener
{
readonly object element;

public ItemContextMenuListener(object element)
{
this.element = element;
}

public void OnCreateContextMenu(IContextMenu? menu, Android.Views.View? v, IContextMenuContextMenuInfo? menuInfo)
{
if (menu is null || v is null)
{
return;
}

if (PJViewAdapter.MenuItems is null)
{
return;
}

var menuItems = PJViewAdapter.MenuItems;

foreach (var (index, item) in menuItems.Index())
{
var mItem = menu.Add(0, index + 1, index, item.Text);
Assert(mItem is not null);
mItem.SetOnMenuItemClickListener(new MenuItemClickListener(new(element, item)));
}
}
}

sealed class MenuItemClickListener : Java.Lang.Object, IMenuItemOnMenuItemClickListener
{
readonly CommandBag bag;

public MenuItemClickListener(CommandBag bag)
{
this.bag = bag;
}

public bool OnMenuItemClick(IMenuItem item)
{
if (item is null)
{
return false;
}

var menuItem = bag.item;
var element = bag.cvItem;

menuItem.FireClicked(element);

if (menuItem.Command?.CanExecute(element) is true)
{
menuItem.Command.Execute(element);
}

return true;
}
}
Loading