File: Compatibility\Handlers\TableView\iOS\TableViewModelRenderer.cs
Web Access
Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls)
#nullable disable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Foundation;
using ObjCRuntime;
using UIKit;
 
namespace Microsoft.Maui.Controls.Handlers.Compatibility
{
	public class TableViewModelRenderer : UITableViewSource
	{
		readonly Dictionary<nint, Cell> _headerCells = new Dictionary<nint, Cell>();
 
		protected bool HasBoundGestures;
 
		[Obsolete("Unused due to memory leak. Will be removed in a future version.")]
		[UnconditionalSuppressMessage("Memory", "MEM0002", Justification = "Unused")]
		protected UITableView Table;
 
		[Obsolete("Unused due to memory leak. Will be removed in a future version.")]
		[UnconditionalSuppressMessage("Memory", "MEM0002", Justification = "Unused")]
		protected TableView View;
 
		WeakReference<UITableView> _platformView;
		WeakReference<TableView> _tableView;
 
		UITableView PlatformView
		{
			get => _platformView is not null && _platformView.TryGetTarget(out var t) ? t : null;
			set => _platformView = value is not null ? new(value) : null;
		}
 
		internal TableView TableView
		{
			get => _tableView is not null && _tableView.TryGetTarget(out var t) ? t : null;
			set => _tableView = value is not null ? new(value) : null;
		}
 
		public TableViewModelRenderer(TableView model)
		{
			TableView = model;
			model.ModelChanged += (s, e) => PlatformView?.ReloadData();
			AutomaticallyDeselect = true;
		}
 
		public bool AutomaticallyDeselect { get; set; }
 
		public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
		{
			if (TableView is not TableView table)
				return null;
			var cell = table.Model.GetCell(indexPath.Section, indexPath.Row);
			var nativeCell = CellTableViewCell.GetPlatformCell(tableView, cell);
 
			return nativeCell;
		}
 
		public override nfloat GetHeightForHeader(UITableView tableView, nint section)
		{
			if (TableView is not TableView table)
				return 0;
			if (!_headerCells.ContainsKey((int)section))
				_headerCells[section] = table.Model.GetHeaderCell((int)section);
 
			var result = _headerCells[section];
 
			return result == null ? UITableView.AutomaticDimension : (nfloat)result.Height;
		}
 
		public override UIView GetViewForHeader(UITableView tableView, nint section)
		{
			if (TableView is not TableView table)
				return null;
			if (!_headerCells.ContainsKey((int)section))
				_headerCells[section] = table.Model.GetHeaderCell((int)section);
 
			var result = _headerCells[section];
 
			if (result != null)
			{
				var reusable = tableView.DequeueReusableCell(result.GetType().FullName);
 
				result.Handler?.DisconnectHandler();
				result.ReusableCell = reusable;
				result.TableView = tableView;
 
				var cellRenderer = result.ToHandler(table.FindMauiContext());
				return (UIView)cellRenderer.PlatformView;
			}
			return null;
		}
 
		public override void WillDisplayHeaderView(UITableView tableView, UIView headerView, nint section)
		{
			if (headerView is UITableViewHeaderFooterView header && TableView is TableView table)
			{
				var sectionHeaderTextColor = table.Model.GetSectionTextColor((int)section);
				if (sectionHeaderTextColor is not null)
				{
#pragma warning disable CA1416, CA1422 // TODO:  'UITableViewHeaderFooterView.TextLabel' is unsupported on: 'ios' 14.0 and later
					if (header.TextLabel is not null)
					{
						header.TextLabel.TextColor = sectionHeaderTextColor.ToPlatform();
					}
#pragma warning restore CA1416, CA1422
				}
			}
		}
 
		public void LongPress(UILongPressGestureRecognizer gesture)
		{
			if (PlatformView is not UITableView tableView)
				return;
 
			var point = gesture.LocationInView(tableView);
			var indexPath = tableView.IndexPathForRowAtPoint(point);
			if (indexPath == null)
				return;
 
			TableView?.Model.RowLongPressed(indexPath.Section, indexPath.Row);
		}
 
		public override nint NumberOfSections(UITableView tableView)
		{
			BindGestures(tableView);
			return TableView?.Model.GetSectionCount() ?? 0;
		}
 
		public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
		{
			TableView?.Model.RowSelected(indexPath.Section, indexPath.Row);
			if (AutomaticallyDeselect)
				tableView.DeselectRow(indexPath, true);
		}
 
		public override nint RowsInSection(UITableView tableview, nint section)
		{
			return TableView?.Model.GetRowCount((int)section) ?? 0;
		}
 
		public override string[] SectionIndexTitles(UITableView tableView)
		{
			return TableView?.Model.GetSectionIndexTitles();
		}
 
		public override string TitleForHeader(UITableView tableView, nint section)
		{
			return TableView?.Model.GetSectionTitle((int)section);
		}
 
		void BindGestures(UITableView tableview)
		{
			if (HasBoundGestures)
				return;
 
			HasBoundGestures = true;
 
			var gesture = new UILongPressGestureRecognizer(LongPress);
			gesture.MinimumPressDuration = 2;
			tableview.AddGestureRecognizer(gesture);
 
			var dismissGesture = new UITapGestureRecognizer(Tap);
			dismissGesture.CancelsTouchesInView = false;
			tableview.AddGestureRecognizer(dismissGesture);
 
			PlatformView = tableview;
		}
 
		void Tap(UITapGestureRecognizer gesture)
		{
			gesture.View.EndEditing(true);
		}
	}
 
	public class UnEvenTableViewModelRenderer : TableViewModelRenderer
	{
		public UnEvenTableViewModelRenderer(TableView model) : base(model)
		{
		}
 
		public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
		{
			if (TableView is not TableView table)
				return 0;
 
			var cell = table.Model.GetCell(indexPath.Section, indexPath.Row);
			var h = cell.Height;
 
			if (table.RowHeight == -1 && h == -1 && cell is ViewCell)
			{
				return UITableView.AutomaticDimension;
			}
			else if (h == -1)
				return tableView.RowHeight;
			return (nfloat)h;
		}
	}
}