Skip to content

Instantly share code, notes, and snippets.

@wcoder
Created March 26, 2019 15:54
Show Gist options
  • Save wcoder/ac87cfb7b5627ab9121a7c4adb937902 to your computer and use it in GitHub Desktop.
Save wcoder/ac87cfb7b5627ab9121a7c4adb937902 to your computer and use it in GitHub Desktop.
Texture PoC Dispose
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Threading;
using AsyncDisplayKitBindings;
using Foundation;
using UIKit;
using Softeq.XToolkit.Common.Collections;
using Softeq.XToolkit.Common.WeakSubscription;
namespace Softeq.XToolkit.WhiteLabel.iOS.Shared
{
public class ObservableASTableDataSource<T> : ASTableDataSource
{
private readonly Func<int, IList<T>, ASCellNode> _createCellFunc;
private readonly Thread _mainThread;
private readonly UITableView _tableView;
private ObservableRangeCollection<T> _dataSource;
private INotifyCollectionChanged _notifier;
private NotifyCollectionChangedEventSubscription _subscription;
public ObservableASTableDataSource(
ObservableRangeCollection<T> items,
UITableView tableView,
Func<int, IList<T>, ASCellNode> createCellFunc)
{
_tableView = tableView;
DataSource = items;
_mainThread = Thread.CurrentThread;
_createCellFunc = createCellFunc;
}
public ObservableRangeCollection<T> DataSource
{
get => _dataSource;
private set
{
if (Equals(_dataSource, value))
{
return;
}
_dataSource = value;
_notifier = value;
if (_notifier != null)
{
_subscription = new NotifyCollectionChangedEventSubscription(DataSource, HandleCollectionChanged);
}
if (_tableView != null)
{
_tableView.ReloadData();
}
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_subscription?.Dispose();
}
base.Dispose(disposing);
}
public event EventHandler DataReloaded;
public override nint NumberOfSectionsInTableNode(ASTableNode tableNode)
{
return 1;
}
public override nint NumberOfRowsInSection(ASTableNode tableNode, nint section)
{
return _dataSource.Count;
}
public override ASCellNodeBlock NodeBlockForRowAtIndexPath(ASTableNode tableNode, NSIndexPath indexPath)
{
return () => _createCellFunc(indexPath.Row, DataSource);
}
private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (_tableView == null)
{
return;
}
void act()
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
{
var count = e.NewItems.Count;
var paths = new NSIndexPath[count];
for (var i = 0; i < count; i++)
{
paths[i] = NSIndexPath.FromRowSection(e.NewStartingIndex + i, 0);
}
_tableView.InsertRows(paths, UITableViewRowAnimation.None);
}
break;
case NotifyCollectionChangedAction.Remove:
{
var count = e.OldItems.Count;
var paths = new NSIndexPath[count];
for (var i = 0; i < count; i++)
{
var index = NSIndexPath.FromRowSection(e.OldStartingIndex + i, 0);
paths[i] = index;
}
_tableView.DeleteRows(paths, UITableViewRowAnimation.Automatic);
}
break;
default:
_tableView.ReloadData();
DataReloaded?.Invoke(this, EventArgs.Empty);
break;
}
}
var isMainThread = Thread.CurrentThread == _mainThread;
if (isMainThread)
{
act();
}
else
{
NSOperationQueue.MainQueue.AddOperation(act);
NSOperationQueue.MainQueue.WaitUntilAllOperationsAreFinished();
}
}
}
}
using System.Collections.Generic;
using AsyncDisplayKitBindings;
using Foundation;
using FQ.DEEMA.Mobile.Demo.iOS.Styles;
using FQ.DEEMA.Mobile.Demo.ViewModels.MoreApps;
using Softeq.XToolkit.Common.iOS.Helpers;
using UIKit;
namespace FQ.DEEMA.Mobile.Demo.iOS.ViewControllers.MoreApps.Cells
{
internal class DocumentCell : ASCellNode
{
private const string DocumentTypeImagePrefix = "ContentSearch_";
private readonly ASTextNode _titleNode = new ASTextNode();
private readonly ASTextNode _descriptionNode = new ASTextNode();
private readonly ASImageNode _imageNode = new ASImageNode
{
ContentMode = UIViewContentMode.ScaleAspectFill
};
private DocumentViewModel _documentViewModel;
public DocumentCell()
{
BackgroundColor = StyleHelper.Style.ContentColor;
}
public void BindCell(DocumentViewModel documentViewModel)
{
_documentViewModel = documentViewModel;
_imageNode.Image = UIImage.FromBundle(DocumentTypeImagePrefix + _documentViewModel.Document.Type);
if (!string.IsNullOrEmpty(_documentViewModel.Document.Title))
{
_titleNode.AttributedText = documentViewModel.Document.Title
.BuildAttributedString()
.Font(StyleHelper.Style.BigSemiboldFont)
.Foreground(StyleHelper.Style.AccentColor);
_titleNode.AddTarget(this, new ObjCRuntime.Selector(nameof(OnOpenDocumentPressed)),
ASControlNodeEvent.TouchUpInside);
}
if (!string.IsNullOrEmpty(_documentViewModel.Document.Description))
{
_descriptionNode.AttributedText = documentViewModel.Document.Description
.BuildAttributedString()
.Font(StyleHelper.Style.BigFont)
.Foreground(StyleHelper.Style.TextNormalColor);
}
SelectionStyle = UITableViewCellSelectionStyle.None;
AutomaticallyManagesSubnodes = true;
SetNeedsLayout();
}
public override ASLayoutSpec LayoutSpecThatFits(ASSizeRange constrainedSize)
{
var items = new List<ASDisplayNode>();
if (_titleNode.AttributedText != null)
{
_titleNode.MaximumNumberOfLines = 1;
_titleNode.TruncationMode = UILineBreakMode.TailTruncation;
_titleNode.Style.SpacingBefore = 4;
items.Add(_titleNode);
}
if (_descriptionNode.AttributedText != null)
{
_descriptionNode.MaximumNumberOfLines = 2;
_descriptionNode.TruncationMode = UILineBreakMode.TailTruncation;
_descriptionNode.Style.SpacingAfter = 8;
items.Add(_descriptionNode);
}
_imageNode.Style.Height = new ASDimension { unit = ASDimensionUnit.Points, value = 28 };
_imageNode.Style.Width = new ASDimension { unit = ASDimensionUnit.Points, value = 22 };
var stack = new ASStackLayoutSpec
{
Direction = ASStackLayoutDirection.Vertical,
Children = items.ToArray()
};
stack.Style.FlexShrink = 1;
stack.Style.SpacingBefore = 12;
var cell = new ASStackLayoutSpec
{
Direction = ASStackLayoutDirection.Horizontal,
Children = new IASLayoutElement[] { _imageNode, stack }
};
return ASInsetLayoutSpec.InsetLayoutSpecWithInsets(new UIEdgeInsets(4, 12, 4, 12), cell);
}
[Export(nameof(OnOpenDocumentPressed))]
private void OnOpenDocumentPressed()
{
_documentViewModel?.OpenDocumentCommand.Execute(null);
}
}
}
private void InitTableView()
{
_tableNode = new ASTableNode(UITableViewStyle.Plain);
_tableNode.BackgroundColor = UIColor.Clear;
_tableNode.View.AddAsSubviewWithParentSize(TableContainer);
_tableNode.View.SeparatorStyle = UITableViewCellSeparatorStyle.SingleLine;
_tableNode.View.TableFooterView = new UIView();
_tableNode.View.KeyboardDismissMode = UIScrollViewKeyboardDismissMode.Interactive;
var ds = new ObservableASTableDataSource<DocumentViewModel>(
ViewModel.SearchViewModel.Items,
_tableNode.View,
(index, dataSource) =>
{
var cell = new DocumentCell();
var viewModel = dataSource[index];
cell.BindCell(viewModel);
return cell;
});
_tableNode.DataSource = ds;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment