mirror of
https://github.com/bitwarden/mobile
synced 2025-12-15 07:43:37 +00:00
remove boxedview
This commit is contained in:
@@ -126,16 +126,8 @@
|
|||||||
<Compile Include="Renderers\HybridWebViewRenderer.cs" />
|
<Compile Include="Renderers\HybridWebViewRenderer.cs" />
|
||||||
<Compile Include="Services\AndroidPushNotificationService.cs" />
|
<Compile Include="Services\AndroidPushNotificationService.cs" />
|
||||||
<Compile Include="SplashActivity.cs" />
|
<Compile Include="SplashActivity.cs" />
|
||||||
<Compile Include="Renderers\BoxedView\BoxedViewRecyclerAdapter.cs" />
|
|
||||||
<Compile Include="Renderers\BoxedView\BoxedViewRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\BoxedView\BoxedViewSimpleCallback.cs" />
|
|
||||||
<Compile Include="Renderers\BoxedView\Cells\BaseCellRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\BoxedView\Cells\BaseCellView.cs" />
|
|
||||||
<Compile Include="Renderers\BoxedView\Cells\EntryCellRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\BoxedView\Cells\LabelCellRenderer.cs" />
|
|
||||||
<Compile Include="MainApplication.cs" />
|
<Compile Include="MainApplication.cs" />
|
||||||
<Compile Include="MainActivity.cs" />
|
<Compile Include="MainActivity.cs" />
|
||||||
<Compile Include="Renderers\RendererUtils.cs" />
|
|
||||||
<Compile Include="Resources\Resource.designer.cs" />
|
<Compile Include="Resources\Resource.designer.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||||
|
|||||||
@@ -1,526 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Support.V7.Widget;
|
|
||||||
using Android.Text;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Widget;
|
|
||||||
using Bit.App.Controls.BoxedView;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
using AView = Android.Views.View;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Renderers.BoxedView
|
|
||||||
{
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
public class BoxedViewRecyclerAdapter : RecyclerView.Adapter, AView.IOnClickListener
|
|
||||||
{
|
|
||||||
private const int ViewTypeHeader = 0;
|
|
||||||
private const int ViewTypeFooter = 1;
|
|
||||||
|
|
||||||
private Dictionary<Type, int> _viewTypes;
|
|
||||||
private List<CellCache> _cellCaches;
|
|
||||||
|
|
||||||
internal List<CellCache> CellCaches
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if(_cellCaches == null)
|
|
||||||
{
|
|
||||||
FillCache();
|
|
||||||
}
|
|
||||||
return _cellCaches;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Item click. correspond to AdapterView.IOnItemClickListener
|
|
||||||
private int _selectedIndex = -1;
|
|
||||||
private AView _preSelectedCell = null;
|
|
||||||
|
|
||||||
Context _context;
|
|
||||||
App.Controls.BoxedView.BoxedView _boxedView;
|
|
||||||
RecyclerView _recyclerView;
|
|
||||||
|
|
||||||
List<ViewHolder> _viewHolders = new List<ViewHolder>();
|
|
||||||
|
|
||||||
public BoxedViewRecyclerAdapter(Context context, App.Controls.BoxedView.BoxedView boxedView,
|
|
||||||
RecyclerView recyclerView)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
_boxedView = boxedView;
|
|
||||||
_recyclerView = recyclerView;
|
|
||||||
_boxedView.ModelChanged += BoxedView_ModelChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float MinRowHeight => _context.ToPixels(44);
|
|
||||||
|
|
||||||
public override int ItemCount => CellCaches.Count;
|
|
||||||
|
|
||||||
public override long GetItemId(int position)
|
|
||||||
{
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
|
|
||||||
{
|
|
||||||
ViewHolder viewHolder;
|
|
||||||
switch(viewType)
|
|
||||||
{
|
|
||||||
case ViewTypeHeader:
|
|
||||||
viewHolder = new HeaderViewHolder(
|
|
||||||
LayoutInflater.FromContext(_context).Inflate(Resource.Layout.HeaderCell, parent, false),
|
|
||||||
_boxedView);
|
|
||||||
break;
|
|
||||||
case ViewTypeFooter:
|
|
||||||
viewHolder = new FooterViewHolder(
|
|
||||||
LayoutInflater.FromContext(_context).Inflate(Resource.Layout.FooterCell, parent, false),
|
|
||||||
_boxedView);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
viewHolder = new ContentViewHolder(
|
|
||||||
LayoutInflater.FromContext(_context).Inflate(Resource.Layout.ContentCell, parent, false));
|
|
||||||
viewHolder.ItemView.SetOnClickListener(this);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_viewHolders.Add(viewHolder);
|
|
||||||
return viewHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnClick(AView view)
|
|
||||||
{
|
|
||||||
var position = _recyclerView.GetChildAdapterPosition(view);
|
|
||||||
|
|
||||||
// TODO: It is desirable that the forms side has Selected property and reflects it.
|
|
||||||
// But do it at a later as iOS side doesn't have that process.
|
|
||||||
DeselectRow();
|
|
||||||
|
|
||||||
var cell = view.FindViewById<LinearLayout>(Resource.Id.ContentCellBody).GetChildAt(0) as BaseCellView;
|
|
||||||
if(cell == null || !CellCaches[position].Cell.IsEnabled)
|
|
||||||
{
|
|
||||||
// If FormsCell IsEnable is false, does nothing.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_boxedView.Model.RowSelected(CellCaches[position].Cell);
|
|
||||||
cell.RowSelected(this, position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
|
|
||||||
{
|
|
||||||
var cellInfo = CellCaches[position];
|
|
||||||
switch(holder.ItemViewType)
|
|
||||||
{
|
|
||||||
case ViewTypeHeader:
|
|
||||||
BindHeaderView((HeaderViewHolder)holder, (TextCell)cellInfo.Cell);
|
|
||||||
break;
|
|
||||||
case ViewTypeFooter:
|
|
||||||
BindFooterView((FooterViewHolder)holder, (TextCell)cellInfo.Cell);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BindContentView((ContentViewHolder)holder, cellInfo.Cell, position);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetItemViewType(int position)
|
|
||||||
{
|
|
||||||
var cellInfo = CellCaches[position];
|
|
||||||
if(cellInfo.IsHeader)
|
|
||||||
{
|
|
||||||
return ViewTypeHeader;
|
|
||||||
}
|
|
||||||
else if(cellInfo.IsFooter)
|
|
||||||
{
|
|
||||||
return ViewTypeFooter;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return _viewTypes[cellInfo.Cell.GetType()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeselectRow()
|
|
||||||
{
|
|
||||||
if(_preSelectedCell != null)
|
|
||||||
{
|
|
||||||
_preSelectedCell.Selected = false;
|
|
||||||
_preSelectedCell = null;
|
|
||||||
}
|
|
||||||
_selectedIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SelectedRow(AView cell, int position)
|
|
||||||
{
|
|
||||||
_preSelectedCell = cell;
|
|
||||||
_selectedIndex = position;
|
|
||||||
cell.Selected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
_boxedView.ModelChanged -= BoxedView_ModelChanged;
|
|
||||||
_cellCaches?.Clear();
|
|
||||||
_cellCaches = null;
|
|
||||||
_boxedView = null;
|
|
||||||
_viewTypes = null;
|
|
||||||
foreach(var holder in _viewHolders)
|
|
||||||
{
|
|
||||||
holder.Dispose();
|
|
||||||
}
|
|
||||||
_viewHolders.Clear();
|
|
||||||
_viewHolders = null;
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BoxedView_ModelChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if(_recyclerView != null)
|
|
||||||
{
|
|
||||||
_cellCaches = null;
|
|
||||||
NotifyDataSetChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BindHeaderView(HeaderViewHolder holder, TextCell formsCell)
|
|
||||||
{
|
|
||||||
var view = holder.ItemView;
|
|
||||||
|
|
||||||
// Judging cell height
|
|
||||||
int cellHeight = (int)_context.ToPixels(44);
|
|
||||||
var individualHeight = formsCell.Height;
|
|
||||||
|
|
||||||
if(individualHeight > 0d)
|
|
||||||
{
|
|
||||||
cellHeight = (int)_context.ToPixels(individualHeight);
|
|
||||||
}
|
|
||||||
else if(_boxedView.HeaderHeight > -1)
|
|
||||||
{
|
|
||||||
cellHeight = (int)_context.ToPixels(_boxedView.HeaderHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
view.SetMinimumHeight(cellHeight);
|
|
||||||
view.LayoutParameters.Height = cellHeight;
|
|
||||||
|
|
||||||
holder.TextView.SetPadding(
|
|
||||||
(int)view.Context.ToPixels(_boxedView.HeaderPadding.Left),
|
|
||||||
(int)view.Context.ToPixels(_boxedView.HeaderPadding.Top),
|
|
||||||
(int)view.Context.ToPixels(_boxedView.HeaderPadding.Right),
|
|
||||||
(int)view.Context.ToPixels(_boxedView.HeaderPadding.Bottom));
|
|
||||||
|
|
||||||
holder.TextView.Gravity = _boxedView.HeaderTextVerticalAlign.ToAndroidVertical() | GravityFlags.Left;
|
|
||||||
holder.TextView.TextAlignment = Android.Views.TextAlignment.Gravity;
|
|
||||||
holder.TextView.SetTextSize(Android.Util.ComplexUnitType.Sp, (float)_boxedView.HeaderFontSize);
|
|
||||||
holder.TextView.SetBackgroundColor(_boxedView.HeaderBackgroundColor.ToAndroid());
|
|
||||||
holder.TextView.SetMaxLines(1);
|
|
||||||
holder.TextView.SetMinLines(1);
|
|
||||||
holder.TextView.SetTypeface(null, Android.Graphics.TypefaceStyle.Bold);
|
|
||||||
holder.TextView.Ellipsize = TextUtils.TruncateAt.End;
|
|
||||||
|
|
||||||
if(_boxedView.HeaderTextColor != Color.Default)
|
|
||||||
{
|
|
||||||
holder.TextView.SetTextColor(_boxedView.HeaderTextColor.ToAndroid());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Border setting
|
|
||||||
if(_boxedView.ShowSectionTopBottomBorder)
|
|
||||||
{
|
|
||||||
holder.Border.SetBackgroundColor(_boxedView.SeparatorColor.ToAndroid());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
holder.Border.SetBackgroundColor(Android.Graphics.Color.Transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update text
|
|
||||||
holder.TextView.Text = formsCell.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BindFooterView(FooterViewHolder holder, TextCell formsCell)
|
|
||||||
{
|
|
||||||
var view = holder.ItemView;
|
|
||||||
|
|
||||||
// Footer visible setting
|
|
||||||
if(string.IsNullOrEmpty(formsCell.Text))
|
|
||||||
{
|
|
||||||
//if text is empty, hidden (height 0)
|
|
||||||
holder.TextView.Visibility = ViewStates.Gone;
|
|
||||||
view.Visibility = ViewStates.Gone;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
holder.TextView.Visibility = ViewStates.Visible;
|
|
||||||
view.Visibility = ViewStates.Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.TextView.SetPadding(
|
|
||||||
(int)view.Context.ToPixels(_boxedView.FooterPadding.Left),
|
|
||||||
(int)view.Context.ToPixels(_boxedView.FooterPadding.Top),
|
|
||||||
(int)view.Context.ToPixels(_boxedView.FooterPadding.Right),
|
|
||||||
(int)view.Context.ToPixels(_boxedView.FooterPadding.Bottom));
|
|
||||||
|
|
||||||
holder.TextView.SetTextSize(Android.Util.ComplexUnitType.Sp, (float)_boxedView.FooterFontSize);
|
|
||||||
holder.TextView.SetBackgroundColor(_boxedView.FooterBackgroundColor.ToAndroid());
|
|
||||||
if(_boxedView.FooterTextColor != Color.Default)
|
|
||||||
{
|
|
||||||
holder.TextView.SetTextColor(_boxedView.FooterTextColor.ToAndroid());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update text
|
|
||||||
holder.TextView.Text = formsCell.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BindContentView(ContentViewHolder holder, Cell formsCell, int position)
|
|
||||||
{
|
|
||||||
AView nativeCell = null;
|
|
||||||
AView layout = holder.ItemView;
|
|
||||||
|
|
||||||
holder.SectionIndex = CellCaches[position].SectionIndex;
|
|
||||||
holder.RowIndex = CellCaches[position].RowIndex;
|
|
||||||
|
|
||||||
nativeCell = holder.Body.GetChildAt(0);
|
|
||||||
if(nativeCell != null)
|
|
||||||
{
|
|
||||||
holder.Body.RemoveViewAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
nativeCell = CellFactory.GetCell(formsCell, nativeCell, _recyclerView, _context, _boxedView);
|
|
||||||
|
|
||||||
if(position == _selectedIndex)
|
|
||||||
{
|
|
||||||
DeselectRow();
|
|
||||||
nativeCell.Selected = true;
|
|
||||||
_preSelectedCell = nativeCell;
|
|
||||||
}
|
|
||||||
|
|
||||||
var minHeight = (int)Math.Max(_context.ToPixels(_boxedView.RowHeight), MinRowHeight);
|
|
||||||
|
|
||||||
// It is necessary to set both
|
|
||||||
layout.SetMinimumHeight(minHeight);
|
|
||||||
nativeCell.SetMinimumHeight(minHeight);
|
|
||||||
|
|
||||||
if(!_boxedView.HasUnevenRows)
|
|
||||||
{
|
|
||||||
// If not Uneven, set the larger one of RowHeight and MinRowHeight.
|
|
||||||
layout.LayoutParameters.Height = minHeight;
|
|
||||||
}
|
|
||||||
else if(formsCell.Height > -1)
|
|
||||||
{
|
|
||||||
// If the cell itself was specified height, set it.
|
|
||||||
layout.SetMinimumHeight((int)_context.ToPixels(formsCell.Height));
|
|
||||||
layout.LayoutParameters.Height = (int)_context.ToPixels(formsCell.Height);
|
|
||||||
}
|
|
||||||
else if(formsCell is ViewCell viewCell)
|
|
||||||
{
|
|
||||||
// If used a viewcell, calculate the size and layout it.
|
|
||||||
var size = viewCell.View.Measure(_boxedView.Width, double.PositiveInfinity);
|
|
||||||
viewCell.View.Layout(new Rectangle(0, 0, size.Request.Width, size.Request.Height));
|
|
||||||
layout.LayoutParameters.Height = (int)_context.ToPixels(size.Request.Height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
layout.LayoutParameters.Height = -2; // wrap_content
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!CellCaches[position].IsLastCell || _boxedView.ShowSectionTopBottomBorder)
|
|
||||||
{
|
|
||||||
holder.Border.SetBackgroundColor(_boxedView.SeparatorColor.ToAndroid());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
holder.Border.SetBackgroundColor(Android.Graphics.Color.Transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.Body.AddView(nativeCell, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FillCache()
|
|
||||||
{
|
|
||||||
var model = _boxedView.Model;
|
|
||||||
int sectionCount = model.GetSectionCount();
|
|
||||||
|
|
||||||
var newCellCaches = new List<CellCache>();
|
|
||||||
for(var sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++)
|
|
||||||
{
|
|
||||||
var sectionTitle = model.GetSectionTitle(sectionIndex);
|
|
||||||
var sectionRowCount = model.GetRowCount(sectionIndex);
|
|
||||||
|
|
||||||
Cell headerCell = new TextCell { Text = sectionTitle, Height = model.GetHeaderHeight(sectionIndex) };
|
|
||||||
headerCell.Parent = _boxedView;
|
|
||||||
|
|
||||||
newCellCaches.Add(new CellCache
|
|
||||||
{
|
|
||||||
Cell = headerCell,
|
|
||||||
IsHeader = true,
|
|
||||||
SectionIndex = sectionIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
for(int i = 0; i < sectionRowCount; i++)
|
|
||||||
{
|
|
||||||
newCellCaches.Add(new CellCache
|
|
||||||
{
|
|
||||||
Cell = model.GetCell(sectionIndex, i),
|
|
||||||
IsLastCell = i == sectionRowCount - 1,
|
|
||||||
SectionIndex = sectionIndex,
|
|
||||||
RowIndex = i
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var footerCell = new TextCell { Text = model.GetFooterText(sectionIndex) };
|
|
||||||
footerCell.Parent = _boxedView;
|
|
||||||
|
|
||||||
newCellCaches.Add(new CellCache
|
|
||||||
{
|
|
||||||
Cell = footerCell,
|
|
||||||
IsFooter = true,
|
|
||||||
SectionIndex = sectionIndex,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_cellCaches = newCellCaches;
|
|
||||||
|
|
||||||
if(_viewTypes == null)
|
|
||||||
{
|
|
||||||
_viewTypes = _cellCaches
|
|
||||||
.Select(x => x.Cell.GetType())
|
|
||||||
.Distinct()
|
|
||||||
.Select((x, idx) => new { x, index = idx })
|
|
||||||
.ToDictionary(key => key.x, val => val.index + 2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var idx = _viewTypes.Values.Max() + 1;
|
|
||||||
foreach(var t in _cellCaches.Select(x => x.Cell.GetType()).Distinct().Except(_viewTypes.Keys).ToList())
|
|
||||||
{
|
|
||||||
_viewTypes.Add(t, idx++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CellMoved(int fromPos, int toPos)
|
|
||||||
{
|
|
||||||
var tmp = CellCaches[fromPos];
|
|
||||||
CellCaches.RemoveAt(fromPos);
|
|
||||||
CellCaches.Insert(toPos, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
internal class CellCache
|
|
||||||
{
|
|
||||||
public Cell Cell { get; set; }
|
|
||||||
public bool IsHeader { get; set; } = false;
|
|
||||||
public bool IsFooter { get; set; } = false;
|
|
||||||
public bool IsLastCell { get; set; } = false;
|
|
||||||
public int SectionIndex { get; set; }
|
|
||||||
public int RowIndex { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
internal class ViewHolder : RecyclerView.ViewHolder
|
|
||||||
{
|
|
||||||
public ViewHolder(AView view)
|
|
||||||
: base(view) { }
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
ItemView?.Dispose();
|
|
||||||
ItemView = null;
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
internal class HeaderViewHolder : ViewHolder
|
|
||||||
{
|
|
||||||
public HeaderViewHolder(AView view, App.Controls.BoxedView.BoxedView boxedView)
|
|
||||||
: base(view)
|
|
||||||
{
|
|
||||||
TextView = view.FindViewById<TextView>(Resource.Id.HeaderCellText);
|
|
||||||
Border = view.FindViewById<LinearLayout>(Resource.Id.HeaderCellBorder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextView TextView { get; private set; }
|
|
||||||
public LinearLayout Border { get; private set; }
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
TextView?.Dispose();
|
|
||||||
TextView = null;
|
|
||||||
Border?.Dispose();
|
|
||||||
Border = null;
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
internal class FooterViewHolder : ViewHolder
|
|
||||||
{
|
|
||||||
public TextView TextView { get; private set; }
|
|
||||||
|
|
||||||
public FooterViewHolder(AView view, App.Controls.BoxedView.BoxedView boxedView)
|
|
||||||
: base(view)
|
|
||||||
{
|
|
||||||
TextView = view.FindViewById<TextView>(Resource.Id.FooterCellText);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
TextView?.Dispose();
|
|
||||||
TextView = null;
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
internal class ContentViewHolder : ViewHolder
|
|
||||||
{
|
|
||||||
public LinearLayout Body { get; private set; }
|
|
||||||
public AView Border { get; private set; }
|
|
||||||
public int SectionIndex { get; set; }
|
|
||||||
public int RowIndex { get; set; }
|
|
||||||
|
|
||||||
public ContentViewHolder(AView view)
|
|
||||||
: base(view)
|
|
||||||
{
|
|
||||||
Body = view.FindViewById<LinearLayout>(Resource.Id.ContentCellBody);
|
|
||||||
Border = view.FindViewById(Resource.Id.ContentCellBorder);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
var nativeCell = Body.GetChildAt(0);
|
|
||||||
if(nativeCell is INativeElementView nativeElementView)
|
|
||||||
{
|
|
||||||
// If a ViewCell is used, it stops the ViewCellContainer from executing the dispose method.
|
|
||||||
// Because if the AiForms.Effects is used and a ViewCellContainer is disposed, it crashes.
|
|
||||||
if(!(nativeElementView.Element is ViewCell))
|
|
||||||
{
|
|
||||||
nativeCell?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Border?.Dispose();
|
|
||||||
Border = null;
|
|
||||||
Body?.Dispose();
|
|
||||||
Body = null;
|
|
||||||
ItemView.SetOnClickListener(null);
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Support.V7.Widget;
|
|
||||||
using Android.Support.V7.Widget.Helper;
|
|
||||||
using Android.Views;
|
|
||||||
using Bit.App.Controls.BoxedView;
|
|
||||||
using Bit.Droid.Renderers.BoxedView;
|
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(BoxedView), typeof(BoxedViewRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers.BoxedView
|
|
||||||
{
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
public class BoxedViewRenderer : ViewRenderer<App.Controls.BoxedView.BoxedView, RecyclerView>
|
|
||||||
{
|
|
||||||
private Page _parentPage;
|
|
||||||
private LinearLayoutManager _layoutManager;
|
|
||||||
private ItemTouchHelper _itemTouchhelper;
|
|
||||||
private BoxedViewRecyclerAdapter _adapter;
|
|
||||||
private BoxedViewSimpleCallback _simpleCallback;
|
|
||||||
|
|
||||||
public BoxedViewRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{
|
|
||||||
AutoPackage = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<App.Controls.BoxedView.BoxedView> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
if(e.NewElement != null)
|
|
||||||
{
|
|
||||||
var recyclerView = new RecyclerView(Context);
|
|
||||||
_layoutManager = new LinearLayoutManager(Context);
|
|
||||||
recyclerView.SetLayoutManager(_layoutManager);
|
|
||||||
|
|
||||||
SetNativeControl(recyclerView);
|
|
||||||
|
|
||||||
Control.Focusable = false;
|
|
||||||
Control.DescendantFocusability = DescendantFocusability.AfterDescendants;
|
|
||||||
|
|
||||||
UpdateBackgroundColor();
|
|
||||||
UpdateRowHeight();
|
|
||||||
|
|
||||||
_adapter = new BoxedViewRecyclerAdapter(Context, e.NewElement, recyclerView);
|
|
||||||
Control.SetAdapter(_adapter);
|
|
||||||
|
|
||||||
_simpleCallback = new BoxedViewSimpleCallback(
|
|
||||||
e.NewElement, ItemTouchHelper.Up | ItemTouchHelper.Down, 0);
|
|
||||||
_itemTouchhelper = new ItemTouchHelper(_simpleCallback);
|
|
||||||
_itemTouchhelper.AttachToRecyclerView(Control);
|
|
||||||
|
|
||||||
Element elm = Element;
|
|
||||||
while(elm != null)
|
|
||||||
{
|
|
||||||
elm = elm.Parent;
|
|
||||||
if(elm is Page)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_parentPage = elm as Page;
|
|
||||||
_parentPage.Appearing += ParentPageAppearing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ParentPageAppearing(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
Device.BeginInvokeOnMainThread(() => _adapter.DeselectRow());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
|
|
||||||
{
|
|
||||||
base.OnLayout(changed, left, top, right, bottom);
|
|
||||||
if(!changed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var startPos = _layoutManager.FindFirstCompletelyVisibleItemPosition();
|
|
||||||
var endPos = _layoutManager.FindLastCompletelyVisibleItemPosition();
|
|
||||||
|
|
||||||
var totalH = 0;
|
|
||||||
for(var i = startPos; i <= endPos; i++)
|
|
||||||
{
|
|
||||||
var child = _layoutManager.GetChildAt(i);
|
|
||||||
if(child == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
totalH += _layoutManager.GetChildAt(i).Height;
|
|
||||||
}
|
|
||||||
Element.VisibleContentHeight = Context.FromPixels(Math.Min(totalH, Control.Height));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
if(e.PropertyName == App.Controls.BoxedView.BoxedView.SeparatorColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
_adapter.NotifyDataSetChanged();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.BackgroundColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBackgroundColor();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == TableView.RowHeightProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateRowHeight();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.SelectedColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
//_adapter.NotifyDataSetChanged();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.ShowSectionTopBottomBorderProperty.PropertyName)
|
|
||||||
{
|
|
||||||
_adapter.NotifyDataSetChanged();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == TableView.HasUnevenRowsProperty.PropertyName)
|
|
||||||
{
|
|
||||||
_adapter.NotifyDataSetChanged();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.ScrollToTopProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateScrollToTop();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.ScrollToBottomProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateScrollToBottom();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateRowHeight()
|
|
||||||
{
|
|
||||||
if(Element.RowHeight == -1)
|
|
||||||
{
|
|
||||||
Element.RowHeight = 60;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_adapter?.NotifyDataSetChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateScrollToTop()
|
|
||||||
{
|
|
||||||
if(Element.ScrollToTop)
|
|
||||||
{
|
|
||||||
_layoutManager.ScrollToPosition(0);
|
|
||||||
Element.ScrollToTop = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateScrollToBottom()
|
|
||||||
{
|
|
||||||
if(Element.ScrollToBottom)
|
|
||||||
{
|
|
||||||
if(_adapter != null)
|
|
||||||
{
|
|
||||||
_layoutManager.ScrollToPosition(_adapter.ItemCount - 1);
|
|
||||||
}
|
|
||||||
Element.ScrollToBottom = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected new void UpdateBackgroundColor()
|
|
||||||
{
|
|
||||||
if(Element.BackgroundColor != Color.Default)
|
|
||||||
{
|
|
||||||
Control.SetBackgroundColor(Element.BackgroundColor.ToAndroid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
_parentPage.Appearing -= ParentPageAppearing;
|
|
||||||
_adapter?.Dispose();
|
|
||||||
_adapter = null;
|
|
||||||
_layoutManager?.Dispose();
|
|
||||||
_layoutManager = null;
|
|
||||||
_simpleCallback?.Dispose();
|
|
||||||
_simpleCallback = null;
|
|
||||||
_itemTouchhelper?.Dispose();
|
|
||||||
_itemTouchhelper = null;
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
using Android.Runtime;
|
|
||||||
using Android.Support.V7.Widget;
|
|
||||||
using Android.Support.V7.Widget.Helper;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Renderers.BoxedView
|
|
||||||
{
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
public class BoxedViewSimpleCallback : ItemTouchHelper.SimpleCallback
|
|
||||||
{
|
|
||||||
private App.Controls.BoxedView.BoxedView _boxedView;
|
|
||||||
private int _offset = 0;
|
|
||||||
|
|
||||||
public BoxedViewSimpleCallback(App.Controls.BoxedView.BoxedView boxedView, int dragDirs, int swipeDirs)
|
|
||||||
: base(dragDirs, swipeDirs)
|
|
||||||
{
|
|
||||||
_boxedView = boxedView;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
|
|
||||||
RecyclerView.ViewHolder target)
|
|
||||||
{
|
|
||||||
if(!(viewHolder is ContentViewHolder fromContentHolder))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(!(target is ContentViewHolder toContentHolder))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(fromContentHolder.SectionIndex != toContentHolder.SectionIndex)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var section = _boxedView.Model.GetSection(fromContentHolder.SectionIndex);
|
|
||||||
if(section == null || !section.UseDragSort)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fromPos = viewHolder.AdapterPosition;
|
|
||||||
var toPos = target.AdapterPosition;
|
|
||||||
_offset += toPos - fromPos;
|
|
||||||
var settingsAdapter = recyclerView.GetAdapter() as BoxedViewRecyclerAdapter;
|
|
||||||
settingsAdapter.NotifyItemMoved(fromPos, toPos); // rows update
|
|
||||||
settingsAdapter.CellMoved(fromPos, toPos); // caches update
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ClearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
|
|
||||||
{
|
|
||||||
base.ClearView(recyclerView, viewHolder);
|
|
||||||
if(!(viewHolder is ContentViewHolder contentHolder))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var section = _boxedView.Model.GetSection(contentHolder.SectionIndex);
|
|
||||||
var pos = contentHolder.RowIndex;
|
|
||||||
if(section.ItemsSource == null)
|
|
||||||
{
|
|
||||||
var tmp = section[pos];
|
|
||||||
section.RemoveAt(pos);
|
|
||||||
section.Insert(pos + _offset, tmp);
|
|
||||||
}
|
|
||||||
else if(section.ItemsSource != null)
|
|
||||||
{
|
|
||||||
// must update DataSource at this timing.
|
|
||||||
var tmp = section.ItemsSource[pos];
|
|
||||||
section.ItemsSource.RemoveAt(pos);
|
|
||||||
section.ItemsSource.Insert(pos + _offset, tmp);
|
|
||||||
}
|
|
||||||
_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetDragDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
|
|
||||||
{
|
|
||||||
if(!(viewHolder is ContentViewHolder contentHolder))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
var section = _boxedView.Model.GetSection(contentHolder.SectionIndex);
|
|
||||||
if(section == null || !section.UseDragSort)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return base.GetDragDirs(recyclerView, viewHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnSwiped(RecyclerView.ViewHolder viewHolder, int direction)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
_boxedView = null;
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Views;
|
|
||||||
using Bit.App.Controls.BoxedView;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Renderers.BoxedView
|
|
||||||
{
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
public class BaseCellRenderer<TNativeCell> : CellRenderer where TNativeCell : BaseCellView
|
|
||||||
{
|
|
||||||
protected override View GetCellCore(Xamarin.Forms.Cell item, View convertView, ViewGroup parent,
|
|
||||||
Context context)
|
|
||||||
{
|
|
||||||
if(!(convertView is TNativeCell nativeCell))
|
|
||||||
{
|
|
||||||
nativeCell = InstanceCreator<Context, Xamarin.Forms.Cell, TNativeCell>.Create(context, item);
|
|
||||||
}
|
|
||||||
ClearPropertyChanged(nativeCell);
|
|
||||||
nativeCell.Cell = item;
|
|
||||||
SetUpPropertyChanged(nativeCell);
|
|
||||||
nativeCell.UpdateCell();
|
|
||||||
return nativeCell;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void SetUpPropertyChanged(BaseCellView nativeCell)
|
|
||||||
{
|
|
||||||
var formsCell = nativeCell.Cell as BaseCell;
|
|
||||||
formsCell.PropertyChanged += nativeCell.CellPropertyChanged;
|
|
||||||
if(formsCell.Parent is App.Controls.BoxedView.BoxedView parentElement)
|
|
||||||
{
|
|
||||||
parentElement.PropertyChanged += nativeCell.ParentPropertyChanged;
|
|
||||||
var section = parentElement.Model.GetSection(BoxedModel.GetPath(formsCell).Item1);
|
|
||||||
if(section != null)
|
|
||||||
{
|
|
||||||
formsCell.Section = section;
|
|
||||||
formsCell.Section.PropertyChanged += nativeCell.SectionPropertyChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearPropertyChanged(BaseCellView nativeCell)
|
|
||||||
{
|
|
||||||
var formsCell = nativeCell.Cell as BaseCell;
|
|
||||||
formsCell.PropertyChanged -= nativeCell.CellPropertyChanged;
|
|
||||||
if(formsCell.Parent is App.Controls.BoxedView.BoxedView parentElement)
|
|
||||||
{
|
|
||||||
parentElement.PropertyChanged -= nativeCell.ParentPropertyChanged;
|
|
||||||
if(formsCell.Section != null)
|
|
||||||
{
|
|
||||||
formsCell.Section.PropertyChanged -= nativeCell.SectionPropertyChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class InstanceCreator<T1, T2, TInstance>
|
|
||||||
{
|
|
||||||
public static Func<T1, T2, TInstance> Create { get; } = CreateInstance();
|
|
||||||
|
|
||||||
private static Func<T1, T2, TInstance> CreateInstance()
|
|
||||||
{
|
|
||||||
var argsTypes = new[] { typeof(T1), typeof(T2) };
|
|
||||||
var constructor = typeof(TInstance).GetConstructor(
|
|
||||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
|
|
||||||
Type.DefaultBinder, argsTypes, null);
|
|
||||||
var args = argsTypes.Select(Expression.Parameter).ToArray();
|
|
||||||
return Expression.Lambda<Func<T1, T2, TInstance>>(Expression.New(constructor, args), args).Compile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.Graphics.Drawables;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Util;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Widget;
|
|
||||||
using Bit.App.Controls.BoxedView;
|
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Threading;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
using ARelativeLayout = Android.Widget.RelativeLayout;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Renderers.BoxedView
|
|
||||||
{
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
public class BaseCellView : ARelativeLayout, INativeElementView
|
|
||||||
{
|
|
||||||
private bool _debugWithColors = false;
|
|
||||||
private CancellationTokenSource _iconTokenSource;
|
|
||||||
private Android.Graphics.Color _defaultTextColor;
|
|
||||||
private ColorDrawable _backgroundColor;
|
|
||||||
private ColorDrawable _selectedColor;
|
|
||||||
private RippleDrawable _ripple;
|
|
||||||
private float _defaultFontSize;
|
|
||||||
|
|
||||||
protected Context _Context;
|
|
||||||
|
|
||||||
public BaseCellView(Context context, Cell cell)
|
|
||||||
: base(context)
|
|
||||||
{
|
|
||||||
_Context = context;
|
|
||||||
Cell = cell;
|
|
||||||
CreateContentView();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cell Cell { get; set; }
|
|
||||||
public Element Element => Cell;
|
|
||||||
protected BaseCell CellBase => Cell as BaseCell;
|
|
||||||
public App.Controls.BoxedView.BoxedView CellParent => Cell.Parent as App.Controls.BoxedView.BoxedView;
|
|
||||||
public TextView CellTitle { get; set; }
|
|
||||||
public LinearLayout CellTitleContent { get; set; }
|
|
||||||
public LinearLayout CellContent { get; set; }
|
|
||||||
public LinearLayout CellButtonContent { get; set; }
|
|
||||||
public Android.Widget.ImageButton CellButton1 { get; set; }
|
|
||||||
public Android.Widget.ImageButton CellButton2 { get; set; }
|
|
||||||
public Android.Widget.ImageButton CellButton3 { get; set; }
|
|
||||||
public LinearLayout CellAccessory { get; set; }
|
|
||||||
|
|
||||||
private void CreateContentView()
|
|
||||||
{
|
|
||||||
var contentView = (_Context as FormsAppCompatActivity)
|
|
||||||
.LayoutInflater
|
|
||||||
.Inflate(Resource.Layout.CellBaseView, this, true);
|
|
||||||
|
|
||||||
contentView.LayoutParameters = new ViewGroup.LayoutParams(-1, -1);
|
|
||||||
|
|
||||||
CellTitle = contentView.FindViewById<TextView>(Resource.Id.CellTitle);
|
|
||||||
CellContent = contentView.FindViewById<LinearLayout>(Resource.Id.CellContent);
|
|
||||||
CellTitleContent = contentView.FindViewById<LinearLayout>(Resource.Id.CellTitleContent);
|
|
||||||
CellButtonContent = contentView.FindViewById<LinearLayout>(Resource.Id.CellButtonContent);
|
|
||||||
CellButton1 = contentView.FindViewById<Android.Widget.ImageButton>(Resource.Id.CellButton1);
|
|
||||||
CellButton1.Click += CellButton1_Click;
|
|
||||||
CellButton2 = contentView.FindViewById<Android.Widget.ImageButton>(Resource.Id.CellButton2);
|
|
||||||
CellButton2.Click += CellButton2_Click;
|
|
||||||
CellButton3 = contentView.FindViewById<Android.Widget.ImageButton>(Resource.Id.CellButton3);
|
|
||||||
CellButton3.Click += CellButton3_Click;
|
|
||||||
CellAccessory = contentView.FindViewById<LinearLayout>(Resource.Id.CellAccessory);
|
|
||||||
|
|
||||||
_backgroundColor = new ColorDrawable();
|
|
||||||
_selectedColor = new ColorDrawable(Android.Graphics.Color.Argb(125, 180, 180, 180));
|
|
||||||
|
|
||||||
var sel = new StateListDrawable();
|
|
||||||
|
|
||||||
sel.AddState(new int[] { Android.Resource.Attribute.StateSelected }, _selectedColor);
|
|
||||||
sel.AddState(new int[] { -Android.Resource.Attribute.StateSelected }, _backgroundColor);
|
|
||||||
sel.SetExitFadeDuration(250);
|
|
||||||
sel.SetEnterFadeDuration(250);
|
|
||||||
|
|
||||||
var rippleColor = Android.Graphics.Color.Rgb(180, 180, 180);
|
|
||||||
if(CellParent.SelectedColor != Color.Default)
|
|
||||||
{
|
|
||||||
rippleColor = CellParent.SelectedColor.ToAndroid();
|
|
||||||
}
|
|
||||||
_ripple = RendererUtils.CreateRipple(rippleColor, sel);
|
|
||||||
Background = _ripple;
|
|
||||||
|
|
||||||
_defaultTextColor = new Android.Graphics.Color(CellTitle.CurrentTextColor);
|
|
||||||
_defaultFontSize = CellTitle.TextSize;
|
|
||||||
|
|
||||||
if(_debugWithColors)
|
|
||||||
{
|
|
||||||
contentView.Background = _Context.GetDrawable(Android.Resource.Color.HoloGreenLight);
|
|
||||||
CellContent.Background = _Context.GetDrawable(Android.Resource.Color.HoloOrangeLight);
|
|
||||||
CellButtonContent.Background = _Context.GetDrawable(Android.Resource.Color.HoloOrangeDark);
|
|
||||||
CellTitle.Background = _Context.GetDrawable(Android.Resource.Color.HoloBlueLight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if(e.PropertyName == BaseCell.TitleProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateTitleText();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == BaseCell.TitleColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateTitleColor();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == BaseCell.TitleFontSizeProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateTitleFontSize();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == BaseCell.BackgroundColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBackgroundColor();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == Cell.IsEnabledProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateIsEnabled();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == BaseCell.Button1IconProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateButtonIcon(CellButton1, CellBase.Button1Icon);
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == BaseCell.Button2IconProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateButtonIcon(CellButton2, CellBase.Button2Icon);
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == BaseCell.Button3IconProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateButtonIcon(CellButton3, CellBase.Button3Icon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void ParentPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
// Avoid running the vain process when popping a page.
|
|
||||||
if((sender as BindableObject)?.BindingContext == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellTitleColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateTitleColor();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellTitleFontSizeProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateWithForceLayout(UpdateTitleFontSize);
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellBackgroundColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBackgroundColor();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.SelectedColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateWithForceLayout(UpdateSelectedColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void SectionPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public virtual void RowSelected(BoxedViewRecyclerAdapter adapter, int position)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected void UpdateWithForceLayout(Action updateAction)
|
|
||||||
{
|
|
||||||
updateAction();
|
|
||||||
Invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void UpdateCell()
|
|
||||||
{
|
|
||||||
UpdateButtonIcon(CellButton1, CellBase.Button1Icon);
|
|
||||||
UpdateButtonIcon(CellButton2, CellBase.Button2Icon);
|
|
||||||
UpdateButtonIcon(CellButton3, CellBase.Button3Icon);
|
|
||||||
UpdateBackgroundColor();
|
|
||||||
UpdateSelectedColor();
|
|
||||||
UpdateTitleText();
|
|
||||||
UpdateTitleColor();
|
|
||||||
UpdateTitleFontSize();
|
|
||||||
|
|
||||||
UpdateIsEnabled();
|
|
||||||
|
|
||||||
Invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateButtonIcon(Android.Widget.ImageButton cellButton, string icon)
|
|
||||||
{
|
|
||||||
if(string.IsNullOrWhiteSpace(icon))
|
|
||||||
{
|
|
||||||
cellButton.Visibility = ViewStates.Gone;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cellButton.SetImageDrawable(_Context.GetDrawable(icon));
|
|
||||||
cellButton.SetImageDrawable(_Context.GetDrawable(icon));
|
|
||||||
cellButton.Visibility = ViewStates.Visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CellButton1_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if(CellBase.Button1Command?.CanExecute(CellBase.Button1CommandParameter) ?? false)
|
|
||||||
{
|
|
||||||
CellBase.Button1Command.Execute(CellBase.Button1CommandParameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CellButton2_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if(CellBase.Button2Command?.CanExecute(CellBase.Button2CommandParameter) ?? false)
|
|
||||||
{
|
|
||||||
CellBase.Button2Command.Execute(CellBase.Button2CommandParameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CellButton3_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if(CellBase.Button3Command?.CanExecute(CellBase.Button3CommandParameter) ?? false)
|
|
||||||
{
|
|
||||||
CellBase.Button3Command.Execute(CellBase.Button3CommandParameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBackgroundColor()
|
|
||||||
{
|
|
||||||
Selected = false;
|
|
||||||
if(CellBase.BackgroundColor != Color.Default)
|
|
||||||
{
|
|
||||||
_backgroundColor.Color = CellBase.BackgroundColor.ToAndroid();
|
|
||||||
}
|
|
||||||
else if(CellParent != null && CellParent.CellBackgroundColor != Color.Default)
|
|
||||||
{
|
|
||||||
_backgroundColor.Color = CellParent.CellBackgroundColor.ToAndroid();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_backgroundColor.Color = Android.Graphics.Color.Transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateSelectedColor()
|
|
||||||
{
|
|
||||||
if(CellParent != null && CellParent.SelectedColor != Color.Default)
|
|
||||||
{
|
|
||||||
_selectedColor.Color = CellParent.SelectedColor.MultiplyAlpha(0.5).ToAndroid();
|
|
||||||
_ripple.SetColor(RendererUtils.GetPressedColorSelector(CellParent.SelectedColor.ToAndroid()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_selectedColor.Color = Android.Graphics.Color.Argb(125, 180, 180, 180);
|
|
||||||
_ripple.SetColor(RendererUtils.GetPressedColorSelector(Android.Graphics.Color.Rgb(180, 180, 180)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTitleText()
|
|
||||||
{
|
|
||||||
CellTitle.Text = CellBase.Title;
|
|
||||||
// Hide TextView right padding when TextView.Text empty.
|
|
||||||
CellTitle.Visibility = string.IsNullOrEmpty(CellTitle.Text) ? ViewStates.Gone : ViewStates.Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTitleColor()
|
|
||||||
{
|
|
||||||
if(CellBase.TitleColor != Color.Default)
|
|
||||||
{
|
|
||||||
CellTitle.SetTextColor(CellBase.TitleColor.ToAndroid());
|
|
||||||
}
|
|
||||||
else if(CellParent != null && CellParent.CellTitleColor != Color.Default)
|
|
||||||
{
|
|
||||||
CellTitle.SetTextColor(CellParent.CellTitleColor.ToAndroid());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CellTitle.SetTextColor(_defaultTextColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTitleFontSize()
|
|
||||||
{
|
|
||||||
if(CellBase.TitleFontSize > 0)
|
|
||||||
{
|
|
||||||
CellTitle.SetTextSize(ComplexUnitType.Sp, (float)CellBase.TitleFontSize);
|
|
||||||
}
|
|
||||||
else if(CellParent != null)
|
|
||||||
{
|
|
||||||
CellTitle.SetTextSize(ComplexUnitType.Sp, (float)CellParent.CellTitleFontSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CellTitle.SetTextSize(ComplexUnitType.Sp, _defaultFontSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void UpdateIsEnabled()
|
|
||||||
{
|
|
||||||
SetEnabledAppearance(CellBase.IsEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void SetEnabledAppearance(bool isEnabled)
|
|
||||||
{
|
|
||||||
if(isEnabled)
|
|
||||||
{
|
|
||||||
Focusable = false;
|
|
||||||
DescendantFocusability = DescendantFocusability.AfterDescendants;
|
|
||||||
CellTitle.Alpha = 1f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// not to invoke a ripple effect and not to selected
|
|
||||||
Focusable = true;
|
|
||||||
DescendantFocusability = DescendantFocusability.BlockDescendants;
|
|
||||||
// to turn like disabled
|
|
||||||
CellTitle.Alpha = 0.3f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
CellBase.PropertyChanged -= CellPropertyChanged;
|
|
||||||
CellParent.PropertyChanged -= ParentPropertyChanged;
|
|
||||||
CellButton1.Click -= CellButton1_Click;
|
|
||||||
CellButton2.Click -= CellButton2_Click;
|
|
||||||
CellButton3.Click -= CellButton3_Click;
|
|
||||||
|
|
||||||
if(CellBase.Section != null)
|
|
||||||
{
|
|
||||||
CellBase.Section.PropertyChanged -= SectionPropertyChanged;
|
|
||||||
CellBase.Section = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
CellTitle?.Dispose();
|
|
||||||
CellTitle = null;
|
|
||||||
CellTitleContent?.Dispose();
|
|
||||||
CellTitleContent = null;
|
|
||||||
CellAccessory?.Dispose();
|
|
||||||
CellAccessory = null;
|
|
||||||
CellButton1?.Dispose();
|
|
||||||
CellButton1 = null;
|
|
||||||
CellButton2?.Dispose();
|
|
||||||
CellButton2 = null;
|
|
||||||
CellButton3?.Dispose();
|
|
||||||
CellButton3 = null;
|
|
||||||
CellButtonContent?.Dispose();
|
|
||||||
CellButtonContent = null;
|
|
||||||
CellContent?.Dispose();
|
|
||||||
CellContent = null;
|
|
||||||
Cell = null;
|
|
||||||
|
|
||||||
_iconTokenSource?.Dispose();
|
|
||||||
_iconTokenSource = null;
|
|
||||||
_Context = null;
|
|
||||||
|
|
||||||
_backgroundColor?.Dispose();
|
|
||||||
_backgroundColor = null;
|
|
||||||
_selectedColor?.Dispose();
|
|
||||||
_selectedColor = null;
|
|
||||||
_ripple?.Dispose();
|
|
||||||
_ripple = null;
|
|
||||||
|
|
||||||
Background?.Dispose();
|
|
||||||
Background = null;
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.OS;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Text;
|
|
||||||
using Android.Text.Method;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Views.InputMethods;
|
|
||||||
using Android.Widget;
|
|
||||||
using Java.Lang;
|
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(Bit.App.Controls.BoxedView.EntryCell),
|
|
||||||
typeof(Bit.Droid.Renderers.BoxedView.EntryCellRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers.BoxedView
|
|
||||||
{
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
public class EntryCellRenderer : BaseCellRenderer<EntryCellView>
|
|
||||||
{ }
|
|
||||||
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
public class EntryCellView : BaseCellView, ITextWatcher, Android.Views.View.IOnFocusChangeListener,
|
|
||||||
TextView.IOnEditorActionListener
|
|
||||||
{
|
|
||||||
private bool _debugWithColors = false;
|
|
||||||
private CustomEditText _editText;
|
|
||||||
|
|
||||||
public EntryCellView(Context context, Cell cell)
|
|
||||||
: base(context, cell)
|
|
||||||
{
|
|
||||||
_editText = new CustomEditText(context)
|
|
||||||
{
|
|
||||||
Focusable = true,
|
|
||||||
ImeOptions = ImeAction.Done,
|
|
||||||
OnFocusChangeListener = this,
|
|
||||||
Ellipsize = TextUtils.TruncateAt.End,
|
|
||||||
ClearFocusAction = DoneEdit,
|
|
||||||
Background = _Context.GetDrawable(Android.Resource.Color.Transparent)
|
|
||||||
};
|
|
||||||
_editText.SetPadding(0, 0, 0, 0);
|
|
||||||
_editText.SetOnEditorActionListener(this);
|
|
||||||
_editText.SetSingleLine(true);
|
|
||||||
_editText.InputType |= InputTypes.TextFlagNoSuggestions; // Disabled spell check
|
|
||||||
|
|
||||||
Click += EntryCellView_Click;
|
|
||||||
|
|
||||||
using(var lParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent,
|
|
||||||
ViewGroup.LayoutParams.WrapContent))
|
|
||||||
{
|
|
||||||
CellContent.AddView(_editText, lParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_debugWithColors)
|
|
||||||
{
|
|
||||||
_editText.Background = _Context.GetDrawable(Android.Resource.Color.HoloRedLight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
App.Controls.BoxedView.EntryCell _EntryCell => Cell as App.Controls.BoxedView.EntryCell;
|
|
||||||
|
|
||||||
public override void UpdateCell()
|
|
||||||
{
|
|
||||||
UpdateValueText();
|
|
||||||
UpdateValueTextColor();
|
|
||||||
UpdateValueTextFontSize();
|
|
||||||
UpdateKeyboard();
|
|
||||||
UpdatePlaceholder();
|
|
||||||
UpdateTextAlignment();
|
|
||||||
UpdateIsPassword();
|
|
||||||
base.UpdateCell();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.CellPropertyChanged(sender, e);
|
|
||||||
if(e.PropertyName == App.Controls.BoxedView.EntryCell.ValueTextProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateValueText();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.ValueTextFontSizeProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateWithForceLayout(UpdateValueTextFontSize);
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.ValueTextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateWithForceLayout(UpdateValueTextColor);
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.KeyboardProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateKeyboard();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.PlaceholderProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdatePlaceholder();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.TextAlignmentProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateTextAlignment();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.EntryCell.IsPasswordProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateIsPassword();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParentPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.ParentPropertyChanged(sender, e);
|
|
||||||
if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellValueTextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateValueTextColor();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellValueTextFontSizeProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateWithForceLayout(UpdateValueTextFontSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
Click -= EntryCellView_Click;
|
|
||||||
_editText.RemoveFromParent();
|
|
||||||
_editText.SetOnEditorActionListener(null);
|
|
||||||
_editText.RemoveTextChangedListener(this);
|
|
||||||
_editText.OnFocusChangeListener = null;
|
|
||||||
_editText.ClearFocusAction = null;
|
|
||||||
_editText.Dispose();
|
|
||||||
_editText = null;
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EntryCellView_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
_editText.RequestFocus();
|
|
||||||
ShowKeyboard(_editText);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateValueText()
|
|
||||||
{
|
|
||||||
_editText.RemoveTextChangedListener(this);
|
|
||||||
if(_editText.Text != _EntryCell.ValueText)
|
|
||||||
{
|
|
||||||
_editText.Text = _EntryCell.ValueText;
|
|
||||||
}
|
|
||||||
_editText.AddTextChangedListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateValueTextFontSize()
|
|
||||||
{
|
|
||||||
if(_EntryCell.ValueTextFontSize > 0)
|
|
||||||
{
|
|
||||||
_editText.SetTextSize(Android.Util.ComplexUnitType.Sp, (float)_EntryCell.ValueTextFontSize);
|
|
||||||
}
|
|
||||||
else if(CellParent != null)
|
|
||||||
{
|
|
||||||
_editText.SetTextSize(Android.Util.ComplexUnitType.Sp, (float)CellParent.CellValueTextFontSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateValueTextColor()
|
|
||||||
{
|
|
||||||
if(_EntryCell.ValueTextColor != Color.Default)
|
|
||||||
{
|
|
||||||
_editText.SetTextColor(_EntryCell.ValueTextColor.ToAndroid());
|
|
||||||
}
|
|
||||||
else if(CellParent != null && CellParent.CellValueTextColor != Color.Default)
|
|
||||||
{
|
|
||||||
_editText.SetTextColor(CellParent.CellValueTextColor.ToAndroid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateKeyboard()
|
|
||||||
{
|
|
||||||
_editText.InputType = _EntryCell.Keyboard.ToInputType() | InputTypes.TextFlagNoSuggestions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateIsPassword()
|
|
||||||
{
|
|
||||||
_editText.TransformationMethod = _EntryCell.IsPassword ? new PasswordTransformationMethod() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdatePlaceholder()
|
|
||||||
{
|
|
||||||
_editText.Hint = _EntryCell.Placeholder;
|
|
||||||
_editText.SetHintTextColor(Android.Graphics.Color.Rgb(210, 210, 210));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTextAlignment()
|
|
||||||
{
|
|
||||||
_editText.Gravity = _EntryCell.TextAlignment.ToAndroidHorizontal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DoneEdit()
|
|
||||||
{
|
|
||||||
var entryCell = (IEntryCellController)Cell;
|
|
||||||
entryCell.SendCompleted();
|
|
||||||
_editText.ClearFocus();
|
|
||||||
ClearFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HideKeyboard(Android.Views.View inputView)
|
|
||||||
{
|
|
||||||
using(var inputMethodManager = (InputMethodManager)_Context.GetSystemService(Context.InputMethodService))
|
|
||||||
{
|
|
||||||
IBinder windowToken = inputView.WindowToken;
|
|
||||||
if(windowToken != null)
|
|
||||||
{
|
|
||||||
inputMethodManager.HideSoftInputFromWindow(windowToken, HideSoftInputFlags.None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowKeyboard(Android.Views.View inputView)
|
|
||||||
{
|
|
||||||
using(var inputMethodManager = (InputMethodManager)_Context.GetSystemService(Context.InputMethodService))
|
|
||||||
{
|
|
||||||
inputMethodManager.ShowSoftInput(inputView, ShowFlags.Forced);
|
|
||||||
inputMethodManager.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.ImplicitOnly);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextView.IOnEditorActionListener.OnEditorAction(TextView v, ImeAction actionId, KeyEvent e)
|
|
||||||
{
|
|
||||||
if(actionId == ImeAction.Done || (actionId == ImeAction.ImeNull && e.KeyCode == Keycode.Enter))
|
|
||||||
{
|
|
||||||
HideKeyboard(v);
|
|
||||||
DoneEdit();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ITextWatcher.AfterTextChanged(IEditable s)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void ITextWatcher.BeforeTextChanged(ICharSequence s, int start, int count, int after)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void ITextWatcher.OnTextChanged(ICharSequence s, int start, int before, int count)
|
|
||||||
{
|
|
||||||
_EntryCell.ValueText = s?.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOnFocusChangeListener.OnFocusChange(Android.Views.View v, bool hasFocus)
|
|
||||||
{
|
|
||||||
if(hasFocus)
|
|
||||||
{
|
|
||||||
// Show underline when on focus.
|
|
||||||
_editText.Background.Alpha = 100;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Hide underline
|
|
||||||
_editText.Background.Alpha = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
internal class CustomEditText : EditText
|
|
||||||
{
|
|
||||||
public CustomEditText(Context context)
|
|
||||||
: base(context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public Action ClearFocusAction { get; set; }
|
|
||||||
|
|
||||||
public override bool OnKeyPreIme(Keycode keyCode, KeyEvent e)
|
|
||||||
{
|
|
||||||
if(keyCode == Keycode.Back && e.Action == KeyEventActions.Up)
|
|
||||||
{
|
|
||||||
ClearFocus();
|
|
||||||
ClearFocusAction?.Invoke();
|
|
||||||
}
|
|
||||||
return base.OnKeyPreIme(keyCode, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Android.Text;
|
|
||||||
using Android.Views;
|
|
||||||
using Android.Widget;
|
|
||||||
using Bit.App.Controls.BoxedView;
|
|
||||||
using Bit.Droid.Renderers.BoxedView;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(LabelCell), typeof(LabelCellRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers.BoxedView
|
|
||||||
{
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
public class LabelCellRenderer : BaseCellRenderer<LabelCellView>
|
|
||||||
{ }
|
|
||||||
|
|
||||||
[Preserve(AllMembers = true)]
|
|
||||||
public class LabelCellView : BaseCellView
|
|
||||||
{
|
|
||||||
private bool _debugWithColors = false;
|
|
||||||
private TextView _valueLabel;
|
|
||||||
|
|
||||||
public LabelCellView(Context context, Cell cell)
|
|
||||||
: base(context, cell)
|
|
||||||
{
|
|
||||||
_valueLabel = new TextView(context)
|
|
||||||
{
|
|
||||||
Ellipsize = TextUtils.TruncateAt.End,
|
|
||||||
Gravity = GravityFlags.Left,
|
|
||||||
};
|
|
||||||
_valueLabel.SetSingleLine(true);
|
|
||||||
|
|
||||||
using(var lParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent,
|
|
||||||
ViewGroup.LayoutParams.WrapContent))
|
|
||||||
{
|
|
||||||
CellContent.AddView(_valueLabel, lParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_debugWithColors)
|
|
||||||
{
|
|
||||||
_valueLabel.Background = _Context.GetDrawable(Android.Resource.Color.HoloRedLight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LabelCell LabelCell => Cell as LabelCell;
|
|
||||||
|
|
||||||
public override void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.CellPropertyChanged(sender, e);
|
|
||||||
if(e.PropertyName == LabelCell.ValueTextProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateValueText();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == LabelCell.ValueTextFontSizeProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateValueTextFontSize();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == LabelCell.ValueTextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateValueTextColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParentPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.ParentPropertyChanged(sender, e);
|
|
||||||
if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellValueTextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateValueTextColor();
|
|
||||||
}
|
|
||||||
else if(e.PropertyName == App.Controls.BoxedView.BoxedView.CellValueTextFontSizeProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateValueTextFontSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateCell()
|
|
||||||
{
|
|
||||||
base.UpdateCell();
|
|
||||||
UpdateValueText();
|
|
||||||
UpdateValueTextColor();
|
|
||||||
UpdateValueTextFontSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void UpdateValueText()
|
|
||||||
{
|
|
||||||
_valueLabel.Text = LabelCell.ValueText;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateValueTextFontSize()
|
|
||||||
{
|
|
||||||
if(LabelCell.ValueTextFontSize > 0)
|
|
||||||
{
|
|
||||||
_valueLabel.SetTextSize(Android.Util.ComplexUnitType.Sp, (float)LabelCell.ValueTextFontSize);
|
|
||||||
}
|
|
||||||
else if(CellParent != null)
|
|
||||||
{
|
|
||||||
_valueLabel.SetTextSize(Android.Util.ComplexUnitType.Sp, (float)CellParent.CellValueTextFontSize);
|
|
||||||
}
|
|
||||||
Invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateValueTextColor()
|
|
||||||
{
|
|
||||||
if(LabelCell.ValueTextColor != Color.Default)
|
|
||||||
{
|
|
||||||
_valueLabel.SetTextColor(LabelCell.ValueTextColor.ToAndroid());
|
|
||||||
}
|
|
||||||
else if(CellParent != null && CellParent.CellValueTextColor != Color.Default)
|
|
||||||
{
|
|
||||||
_valueLabel.SetTextColor(CellParent.CellValueTextColor.ToAndroid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if(disposing)
|
|
||||||
{
|
|
||||||
_valueLabel?.Dispose();
|
|
||||||
_valueLabel = null;
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
using Android.Content.Res;
|
|
||||||
using Android.Graphics.Drawables;
|
|
||||||
using Android.Views;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
[Android.Runtime.Preserve(AllMembers = true)]
|
|
||||||
public static class RendererUtils
|
|
||||||
{
|
|
||||||
public static GravityFlags ToAndroidVertical(this LayoutAlignment formsAlignment)
|
|
||||||
{
|
|
||||||
switch(formsAlignment)
|
|
||||||
{
|
|
||||||
case LayoutAlignment.Start:
|
|
||||||
return GravityFlags.Top;
|
|
||||||
case LayoutAlignment.Center:
|
|
||||||
return GravityFlags.CenterVertical;
|
|
||||||
case LayoutAlignment.End:
|
|
||||||
return GravityFlags.Bottom;
|
|
||||||
default:
|
|
||||||
return GravityFlags.FillHorizontal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GravityFlags ToAndroidHorizontal(this LayoutAlignment formsAlignment)
|
|
||||||
{
|
|
||||||
switch(formsAlignment)
|
|
||||||
{
|
|
||||||
case LayoutAlignment.Start:
|
|
||||||
return GravityFlags.Start;
|
|
||||||
case LayoutAlignment.Center:
|
|
||||||
return GravityFlags.CenterHorizontal;
|
|
||||||
case LayoutAlignment.End:
|
|
||||||
return GravityFlags.End;
|
|
||||||
default:
|
|
||||||
return GravityFlags.FillVertical;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GravityFlags ToAndroidHorizontal(this Xamarin.Forms.TextAlignment formsAlignment)
|
|
||||||
{
|
|
||||||
switch(formsAlignment)
|
|
||||||
{
|
|
||||||
case Xamarin.Forms.TextAlignment.Start:
|
|
||||||
return GravityFlags.Left | GravityFlags.CenterVertical;
|
|
||||||
case Xamarin.Forms.TextAlignment.Center:
|
|
||||||
return GravityFlags.Center | GravityFlags.CenterVertical;
|
|
||||||
case Xamarin.Forms.TextAlignment.End:
|
|
||||||
return GravityFlags.Right | GravityFlags.CenterVertical;
|
|
||||||
default:
|
|
||||||
return GravityFlags.Left | GravityFlags.CenterVertical;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RippleDrawable CreateRipple(Android.Graphics.Color color, Drawable background = null)
|
|
||||||
{
|
|
||||||
if(background == null)
|
|
||||||
{
|
|
||||||
var mask = new ColorDrawable(Android.Graphics.Color.White);
|
|
||||||
return new RippleDrawable(GetPressedColorSelector(color), null, mask);
|
|
||||||
}
|
|
||||||
return new RippleDrawable(GetPressedColorSelector(color), background, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ColorStateList GetPressedColorSelector(int pressedColor)
|
|
||||||
{
|
|
||||||
return new ColorStateList(
|
|
||||||
new int[][]
|
|
||||||
{
|
|
||||||
new int[]{}
|
|
||||||
},
|
|
||||||
new int[]
|
|
||||||
{
|
|
||||||
pressedColor,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user