mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 23:25:45 +03:00
BoxedView with LabelCell
This commit is contained in:
parent
2b2342bcad
commit
61e95e03c8
21 changed files with 2945 additions and 285 deletions
|
@ -63,8 +63,15 @@
|
|||
<PackageReference Include="Xamarin.Android.Support.v7.MediaRouter" Version="28.0.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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\LabelCellRenderer.cs" />
|
||||
<Compile Include="MainApplication.cs" />
|
||||
<Compile Include="MainActivity.cs" />
|
||||
<Compile Include="Renderers\RendererUtils.cs" />
|
||||
<Compile Include="Resources\Resource.designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||
|
@ -194,5 +201,17 @@
|
|||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\lock.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\CellBaseView.axml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\ContentCell.axml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\FooterCell.axml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\HeaderCell.axml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
</Project>
|
532
src/Android/Renderers/BoxedView/BoxedViewRecyclerAdapter.cs
Normal file
532
src/Android/Renderers/BoxedView/BoxedViewRecyclerAdapter.cs
Normal file
|
@ -0,0 +1,532 @@
|
|||
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
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
public class BoxedViewRecyclerAdapter : RecyclerView.Adapter, AView.IOnClickListener
|
||||
{
|
||||
private const int ViewTypeHeader = 0;
|
||||
private const int ViewTypeFooter = 1;
|
||||
|
||||
private float MinRowHeight => _context.ToPixels(44);
|
||||
|
||||
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;
|
||||
BoxedView _boxedView;
|
||||
RecyclerView _recyclerView;
|
||||
|
||||
List<ViewHolder> _viewHolders = new List<ViewHolder>();
|
||||
|
||||
public BoxedViewRecyclerAdapter(Context context, BoxedView boxedView, RecyclerView recyclerView)
|
||||
{
|
||||
_context = context;
|
||||
_boxedView = boxedView;
|
||||
_recyclerView = recyclerView;
|
||||
|
||||
_boxedView.ModelChanged += _boxedView_ModelChanged;
|
||||
}
|
||||
|
||||
void _boxedView_ModelChanged(object sender, EventArgs e)
|
||||
{
|
||||
if(_recyclerView != null)
|
||||
{
|
||||
_cellCaches = null;
|
||||
NotifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
//textview setting
|
||||
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.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;
|
||||
}
|
||||
|
||||
//textview setting
|
||||
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 neccesary 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, 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, 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);
|
||||
}
|
||||
}
|
||||
}
|
195
src/Android/Renderers/BoxedView/BoxedViewRenderer.cs
Normal file
195
src/Android/Renderers/BoxedView/BoxedViewRenderer.cs
Normal file
|
@ -0,0 +1,195 @@
|
|||
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;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(BoxedView), typeof(BoxedViewRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
public class BoxedViewRenderer : ViewRenderer<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<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 == BoxedView.SeparatorColorProperty.PropertyName)
|
||||
{
|
||||
_adapter.NotifyDataSetChanged();
|
||||
}
|
||||
else if(e.PropertyName == BoxedView.BackgroundColorProperty.PropertyName)
|
||||
{
|
||||
UpdateBackgroundColor();
|
||||
}
|
||||
else if(e.PropertyName == TableView.RowHeightProperty.PropertyName)
|
||||
{
|
||||
UpdateRowHeight();
|
||||
}
|
||||
else if(e.PropertyName == BoxedView.SelectedColorProperty.PropertyName)
|
||||
{
|
||||
//_adapter.NotifyDataSetChanged();
|
||||
}
|
||||
else if(e.PropertyName == BoxedView.ShowSectionTopBottomBorderProperty.PropertyName)
|
||||
{
|
||||
_adapter.NotifyDataSetChanged();
|
||||
}
|
||||
else if(e.PropertyName == TableView.HasUnevenRowsProperty.PropertyName)
|
||||
{
|
||||
_adapter.NotifyDataSetChanged();
|
||||
}
|
||||
else if(e.PropertyName == BoxedView.ScrollToTopProperty.PropertyName)
|
||||
{
|
||||
UpdateScrollToTop();
|
||||
}
|
||||
else if(e.PropertyName == 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);
|
||||
}
|
||||
}
|
||||
}
|
104
src/Android/Renderers/BoxedView/BoxedViewSimpleCallback.cs
Normal file
104
src/Android/Renderers/BoxedView/BoxedViewSimpleCallback.cs
Normal file
|
@ -0,0 +1,104 @@
|
|||
using Android.Runtime;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Support.V7.Widget.Helper;
|
||||
using Bit.App.Controls.BoxedView;
|
||||
using System;
|
||||
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
public class BoxedViewSimpleCallback : ItemTouchHelper.SimpleCallback
|
||||
{
|
||||
private BoxedView _boxedView;
|
||||
private int _offset = 0;
|
||||
|
||||
public BoxedViewSimpleCallback(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);
|
||||
}
|
||||
}
|
||||
}
|
76
src/Android/Renderers/BoxedView/Cells/BaseCellRenderer.cs
Normal file
76
src/Android/Renderers/BoxedView/Cells/BaseCellRenderer.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
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
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
public class BaseCellRenderer<TNativeCell> : CellRenderer where TNativeCell : BaseCellView
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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 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 BoxedView parentElement)
|
||||
{
|
||||
parentElement.PropertyChanged -= nativeCell.ParentPropertyChanged;
|
||||
if(formsCell.Section != null)
|
||||
{
|
||||
formsCell.Section.PropertyChanged -= nativeCell.SectionPropertyChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
353
src/Android/Renderers/BoxedView/Cells/BaseCellView.cs
Normal file
353
src/Android/Renderers/BoxedView/Cells/BaseCellView.cs
Normal file
|
@ -0,0 +1,353 @@
|
|||
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
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
public class BaseCellView : ARelativeLayout, INativeElementView
|
||||
{
|
||||
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 BoxedView CellParent => Cell.Parent as BoxedView;
|
||||
public TextView TitleLabel { get; set; }
|
||||
public TextView DescriptionLabel { get; set; }
|
||||
public LinearLayout ContentStack { get; set; }
|
||||
public LinearLayout AccessoryStack { get; set; }
|
||||
|
||||
private void CreateContentView()
|
||||
{
|
||||
var contentView = (_Context as FormsAppCompatActivity)
|
||||
.LayoutInflater
|
||||
.Inflate(Resource.Layout.CellBaseView, this, true);
|
||||
|
||||
contentView.LayoutParameters = new ViewGroup.LayoutParams(-1, -1);
|
||||
|
||||
TitleLabel = contentView.FindViewById<TextView>(Resource.Id.CellTitle);
|
||||
DescriptionLabel = contentView.FindViewById<TextView>(Resource.Id.CellDescription);
|
||||
ContentStack = contentView.FindViewById<LinearLayout>(Resource.Id.CellContentStack);
|
||||
AccessoryStack = contentView.FindViewById<LinearLayout>(Resource.Id.CellAccessoryView);
|
||||
|
||||
_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(TitleLabel.CurrentTextColor);
|
||||
_defaultFontSize = TitleLabel.TextSize;
|
||||
}
|
||||
|
||||
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.DescriptionProperty.PropertyName)
|
||||
{
|
||||
UpdateDescriptionText();
|
||||
}
|
||||
else if(e.PropertyName == BaseCell.DescriptionFontSizeProperty.PropertyName)
|
||||
{
|
||||
UpdateDescriptionFontSize();
|
||||
}
|
||||
else if(e.PropertyName == BaseCell.DescriptionColorProperty.PropertyName)
|
||||
{
|
||||
UpdateDescriptionColor();
|
||||
}
|
||||
else if(e.PropertyName == BaseCell.BackgroundColorProperty.PropertyName)
|
||||
{
|
||||
UpdateBackgroundColor();
|
||||
}
|
||||
else if(e.PropertyName == Cell.IsEnabledProperty.PropertyName)
|
||||
{
|
||||
UpdateIsEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
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 == BoxedView.CellTitleColorProperty.PropertyName)
|
||||
{
|
||||
UpdateTitleColor();
|
||||
}
|
||||
else if(e.PropertyName == BoxedView.CellTitleFontSizeProperty.PropertyName)
|
||||
{
|
||||
UpdateWithForceLayout(UpdateTitleFontSize);
|
||||
}
|
||||
else if(e.PropertyName == BoxedView.CellDescriptionColorProperty.PropertyName)
|
||||
{
|
||||
UpdateDescriptionColor();
|
||||
}
|
||||
else if(e.PropertyName == BoxedView.CellDescriptionFontSizeProperty.PropertyName)
|
||||
{
|
||||
UpdateWithForceLayout(UpdateDescriptionFontSize);
|
||||
}
|
||||
else if(e.PropertyName == BoxedView.CellBackgroundColorProperty.PropertyName)
|
||||
{
|
||||
UpdateBackgroundColor();
|
||||
}
|
||||
else if(e.PropertyName == 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()
|
||||
{
|
||||
UpdateBackgroundColor();
|
||||
UpdateSelectedColor();
|
||||
UpdateTitleText();
|
||||
UpdateTitleColor();
|
||||
UpdateTitleFontSize();
|
||||
UpdateDescriptionText();
|
||||
UpdateDescriptionColor();
|
||||
UpdateDescriptionFontSize();
|
||||
|
||||
UpdateIsEnabled();
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
TitleLabel.Text = CellBase.Title;
|
||||
// Hide TextView right padding when TextView.Text empty.
|
||||
TitleLabel.Visibility = string.IsNullOrEmpty(TitleLabel.Text) ? ViewStates.Gone : ViewStates.Visible;
|
||||
}
|
||||
|
||||
private void UpdateTitleColor()
|
||||
{
|
||||
if(CellBase.TitleColor != Color.Default)
|
||||
{
|
||||
TitleLabel.SetTextColor(CellBase.TitleColor.ToAndroid());
|
||||
}
|
||||
else if(CellParent != null && CellParent.CellTitleColor != Color.Default)
|
||||
{
|
||||
TitleLabel.SetTextColor(CellParent.CellTitleColor.ToAndroid());
|
||||
}
|
||||
else
|
||||
{
|
||||
TitleLabel.SetTextColor(_defaultTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTitleFontSize()
|
||||
{
|
||||
if(CellBase.TitleFontSize > 0)
|
||||
{
|
||||
TitleLabel.SetTextSize(ComplexUnitType.Sp, (float)CellBase.TitleFontSize);
|
||||
}
|
||||
else if(CellParent != null)
|
||||
{
|
||||
TitleLabel.SetTextSize(ComplexUnitType.Sp, (float)CellParent.CellTitleFontSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
TitleLabel.SetTextSize(ComplexUnitType.Sp, _defaultFontSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDescriptionText()
|
||||
{
|
||||
DescriptionLabel.Text = CellBase.Description;
|
||||
DescriptionLabel.Visibility = string.IsNullOrEmpty(DescriptionLabel.Text) ?
|
||||
ViewStates.Gone : ViewStates.Visible;
|
||||
}
|
||||
|
||||
private void UpdateDescriptionFontSize()
|
||||
{
|
||||
if(CellBase.DescriptionFontSize > 0)
|
||||
{
|
||||
DescriptionLabel.SetTextSize(ComplexUnitType.Sp, (float)CellBase.DescriptionFontSize);
|
||||
}
|
||||
else if(CellParent != null)
|
||||
{
|
||||
DescriptionLabel.SetTextSize(ComplexUnitType.Sp, (float)CellParent.CellDescriptionFontSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
DescriptionLabel.SetTextSize(ComplexUnitType.Sp, _defaultFontSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDescriptionColor()
|
||||
{
|
||||
if(CellBase.DescriptionColor != Color.Default)
|
||||
{
|
||||
DescriptionLabel.SetTextColor(CellBase.DescriptionColor.ToAndroid());
|
||||
}
|
||||
else if(CellParent != null && CellParent.CellDescriptionColor != Color.Default)
|
||||
{
|
||||
DescriptionLabel.SetTextColor(CellParent.CellDescriptionColor.ToAndroid());
|
||||
}
|
||||
else
|
||||
{
|
||||
DescriptionLabel.SetTextColor(_defaultTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateIsEnabled()
|
||||
{
|
||||
SetEnabledAppearance(CellBase.IsEnabled);
|
||||
}
|
||||
|
||||
protected virtual void SetEnabledAppearance(bool isEnabled)
|
||||
{
|
||||
if(isEnabled)
|
||||
{
|
||||
Focusable = false;
|
||||
DescendantFocusability = DescendantFocusability.AfterDescendants;
|
||||
TitleLabel.Alpha = 1f;
|
||||
DescriptionLabel.Alpha = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not to invoke a ripple effect and not to selected
|
||||
Focusable = true;
|
||||
DescendantFocusability = DescendantFocusability.BlockDescendants;
|
||||
// to turn like disabled
|
||||
TitleLabel.Alpha = 0.3f;
|
||||
DescriptionLabel.Alpha = 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing)
|
||||
{
|
||||
CellBase.PropertyChanged -= CellPropertyChanged;
|
||||
CellParent.PropertyChanged -= ParentPropertyChanged;
|
||||
|
||||
if(CellBase.Section != null)
|
||||
{
|
||||
CellBase.Section.PropertyChanged -= SectionPropertyChanged;
|
||||
CellBase.Section = null;
|
||||
}
|
||||
|
||||
TitleLabel?.Dispose();
|
||||
TitleLabel = null;
|
||||
DescriptionLabel?.Dispose();
|
||||
DescriptionLabel = null;
|
||||
ContentStack?.Dispose();
|
||||
ContentStack = null;
|
||||
AccessoryStack?.Dispose();
|
||||
AccessoryStack = 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);
|
||||
}
|
||||
}
|
||||
}
|
133
src/Android/Renderers/BoxedView/Cells/LabelCellRenderer.cs
Normal file
133
src/Android/Renderers/BoxedView/Cells/LabelCellRenderer.cs
Normal file
|
@ -0,0 +1,133 @@
|
|||
using Android.Content;
|
||||
using Android.Runtime;
|
||||
using Android.Text;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Bit.App.Controls.BoxedView;
|
||||
using Bit.Droid.Renderers;
|
||||
using System.ComponentModel;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(LabelCell), typeof(LabelCellRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
public class LabelCellRenderer : BaseCellRenderer<LabelCellView>
|
||||
{ }
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class LabelCellView : BaseCellView
|
||||
{
|
||||
public LabelCellView(Context context, Cell cell)
|
||||
: base(context, cell)
|
||||
{
|
||||
ValueLabel = new TextView(context);
|
||||
ValueLabel.SetSingleLine(true);
|
||||
ValueLabel.Ellipsize = TextUtils.TruncateAt.End;
|
||||
ValueLabel.Gravity = GravityFlags.Right;
|
||||
|
||||
var textParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent,
|
||||
ViewGroup.LayoutParams.WrapContent);
|
||||
using(textParams)
|
||||
{
|
||||
ContentStack.AddView(ValueLabel, textParams);
|
||||
}
|
||||
}
|
||||
|
||||
private LabelCell _LabelCell => Cell as LabelCell;
|
||||
|
||||
public TextView ValueLabel { get; set; }
|
||||
|
||||
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 == BoxedView.CellValueTextColorProperty.PropertyName)
|
||||
{
|
||||
UpdateValueTextColor();
|
||||
}
|
||||
else if(e.PropertyName == BoxedView.CellValueTextFontSizeProperty.PropertyName)
|
||||
{
|
||||
UpdateValueTextFontSize();
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateCell()
|
||||
{
|
||||
base.UpdateCell();
|
||||
UpdateValueText();
|
||||
UpdateValueTextColor();
|
||||
UpdateValueTextFontSize();
|
||||
}
|
||||
|
||||
protected override void SetEnabledAppearance(bool isEnabled)
|
||||
{
|
||||
if(isEnabled)
|
||||
{
|
||||
ValueLabel.Alpha = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
ValueLabel.Alpha = 0.3f;
|
||||
}
|
||||
base.SetEnabledAppearance(isEnabled);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
79
src/Android/Renderers/RendererUtils.cs
Normal file
79
src/Android/Renderers/RendererUtils.cs
Normal file
|
@ -0,0 +1,79 @@
|
|||
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 ToAndroidVertical(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.Right | 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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
592
src/Android/Resources/Resource.designer.cs
generated
592
src/Android/Resources/Resource.designer.cs
generated
|
@ -6534,9 +6534,39 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a003a
|
||||
public const int CTRL = 2131361850;
|
||||
|
||||
// aapt resource value: 0x7f0a00a9
|
||||
public const int CellAccessoryView = 2131361961;
|
||||
|
||||
// aapt resource value: 0x7f0a00a5
|
||||
public const int CellBody = 2131361957;
|
||||
|
||||
// aapt resource value: 0x7f0a00a6
|
||||
public const int CellContentStack = 2131361958;
|
||||
|
||||
// aapt resource value: 0x7f0a00a8
|
||||
public const int CellDescription = 2131361960;
|
||||
|
||||
// aapt resource value: 0x7f0a00a7
|
||||
public const int CellTitle = 2131361959;
|
||||
|
||||
// aapt resource value: 0x7f0a00aa
|
||||
public const int ContentCellBody = 2131361962;
|
||||
|
||||
// aapt resource value: 0x7f0a00ab
|
||||
public const int ContentCellBorder = 2131361963;
|
||||
|
||||
// aapt resource value: 0x7f0a003b
|
||||
public const int FUNCTION = 2131361851;
|
||||
|
||||
// aapt resource value: 0x7f0a00ba
|
||||
public const int FooterCellText = 2131361978;
|
||||
|
||||
// aapt resource value: 0x7f0a00bc
|
||||
public const int HeaderCellBorder = 2131361980;
|
||||
|
||||
// aapt resource value: 0x7f0a00bb
|
||||
public const int HeaderCellText = 2131361979;
|
||||
|
||||
// aapt resource value: 0x7f0a003c
|
||||
public const int META = 2131361852;
|
||||
|
||||
|
@ -6546,8 +6576,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a003e
|
||||
public const int SYM = 2131361854;
|
||||
|
||||
// aapt resource value: 0x7f0a00e5
|
||||
public const int action0 = 2131362021;
|
||||
// aapt resource value: 0x7f0a00ef
|
||||
public const int action0 = 2131362031;
|
||||
|
||||
// aapt resource value: 0x7f0a008d
|
||||
public const int action_bar = 2131361933;
|
||||
|
@ -6570,17 +6600,17 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0069
|
||||
public const int action_bar_title = 2131361897;
|
||||
|
||||
// aapt resource value: 0x7f0a00e2
|
||||
public const int action_container = 2131362018;
|
||||
// aapt resource value: 0x7f0a00ec
|
||||
public const int action_container = 2131362028;
|
||||
|
||||
// aapt resource value: 0x7f0a008e
|
||||
public const int action_context_bar = 2131361934;
|
||||
|
||||
// aapt resource value: 0x7f0a00e9
|
||||
public const int action_divider = 2131362025;
|
||||
// aapt resource value: 0x7f0a00f3
|
||||
public const int action_divider = 2131362035;
|
||||
|
||||
// aapt resource value: 0x7f0a00e3
|
||||
public const int action_image = 2131362019;
|
||||
// aapt resource value: 0x7f0a00ed
|
||||
public const int action_image = 2131362029;
|
||||
|
||||
// aapt resource value: 0x7f0a0003
|
||||
public const int action_menu_divider = 2131361795;
|
||||
|
@ -6597,11 +6627,11 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a006b
|
||||
public const int action_mode_close_button = 2131361899;
|
||||
|
||||
// aapt resource value: 0x7f0a00e4
|
||||
public const int action_text = 2131362020;
|
||||
// aapt resource value: 0x7f0a00ee
|
||||
public const int action_text = 2131362030;
|
||||
|
||||
// aapt resource value: 0x7f0a00f2
|
||||
public const int actions = 2131362034;
|
||||
// aapt resource value: 0x7f0a00fc
|
||||
public const int actions = 2131362044;
|
||||
|
||||
// aapt resource value: 0x7f0a006c
|
||||
public const int activity_chooser_view_content = 2131361900;
|
||||
|
@ -6657,8 +6687,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0072
|
||||
public const int buttonPanel = 2131361906;
|
||||
|
||||
// aapt resource value: 0x7f0a00e6
|
||||
public const int cancel_action = 2131362022;
|
||||
// aapt resource value: 0x7f0a00f0
|
||||
public const int cancel_action = 2131362032;
|
||||
|
||||
// aapt resource value: 0x7f0a004c
|
||||
public const int center = 2131361868;
|
||||
|
@ -6672,8 +6702,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0086
|
||||
public const int checkbox = 2131361926;
|
||||
|
||||
// aapt resource value: 0x7f0a00ee
|
||||
public const int chronometer = 2131362030;
|
||||
// aapt resource value: 0x7f0a00f8
|
||||
public const int chronometer = 2131362040;
|
||||
|
||||
// aapt resource value: 0x7f0a0061
|
||||
public const int clip_horizontal = 2131361889;
|
||||
|
@ -6684,8 +6714,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0040
|
||||
public const int collapseActionView = 2131361856;
|
||||
|
||||
// aapt resource value: 0x7f0a00a7
|
||||
public const int container = 2131361959;
|
||||
// aapt resource value: 0x7f0a00ae
|
||||
public const int container = 2131361966;
|
||||
|
||||
// aapt resource value: 0x7f0a0082
|
||||
public const int content = 2131361922;
|
||||
|
@ -6693,8 +6723,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0075
|
||||
public const int contentPanel = 2131361909;
|
||||
|
||||
// aapt resource value: 0x7f0a00a8
|
||||
public const int coordinator = 2131361960;
|
||||
// aapt resource value: 0x7f0a00af
|
||||
public const int coordinator = 2131361967;
|
||||
|
||||
// aapt resource value: 0x7f0a007c
|
||||
public const int custom = 2131361916;
|
||||
|
@ -6708,20 +6738,20 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a006f
|
||||
public const int default_activity_button = 2131361903;
|
||||
|
||||
// aapt resource value: 0x7f0a00aa
|
||||
public const int design_bottom_sheet = 2131361962;
|
||||
// aapt resource value: 0x7f0a00b1
|
||||
public const int design_bottom_sheet = 2131361969;
|
||||
|
||||
// aapt resource value: 0x7f0a00af
|
||||
public const int design_menu_item_action_area = 2131361967;
|
||||
// aapt resource value: 0x7f0a00b6
|
||||
public const int design_menu_item_action_area = 2131361974;
|
||||
|
||||
// aapt resource value: 0x7f0a00ae
|
||||
public const int design_menu_item_action_area_stub = 2131361966;
|
||||
// aapt resource value: 0x7f0a00b5
|
||||
public const int design_menu_item_action_area_stub = 2131361973;
|
||||
|
||||
// aapt resource value: 0x7f0a00ad
|
||||
public const int design_menu_item_text = 2131361965;
|
||||
// aapt resource value: 0x7f0a00b4
|
||||
public const int design_menu_item_text = 2131361972;
|
||||
|
||||
// aapt resource value: 0x7f0a00ac
|
||||
public const int design_navigation_view = 2131361964;
|
||||
// aapt resource value: 0x7f0a00b3
|
||||
public const int design_navigation_view = 2131361971;
|
||||
|
||||
// aapt resource value: 0x7f0a0027
|
||||
public const int disableHome = 2131361831;
|
||||
|
@ -6732,8 +6762,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0037
|
||||
public const int end = 2131361847;
|
||||
|
||||
// aapt resource value: 0x7f0a00f4
|
||||
public const int end_padder = 2131362036;
|
||||
// aapt resource value: 0x7f0a00fe
|
||||
public const int end_padder = 2131362046;
|
||||
|
||||
// aapt resource value: 0x7f0a0046
|
||||
public const int enterAlways = 2131361862;
|
||||
|
@ -6765,11 +6795,11 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a005c
|
||||
public const int @fixed = 2131361884;
|
||||
|
||||
// aapt resource value: 0x7f0a00b1
|
||||
public const int flyoutcontent_appbar = 2131361969;
|
||||
// aapt resource value: 0x7f0a00b8
|
||||
public const int flyoutcontent_appbar = 2131361976;
|
||||
|
||||
// aapt resource value: 0x7f0a00b2
|
||||
public const int flyoutcontent_recycler = 2131361970;
|
||||
// aapt resource value: 0x7f0a00b9
|
||||
public const int flyoutcontent_recycler = 2131361977;
|
||||
|
||||
// aapt resource value: 0x7f0a0067
|
||||
public const int forever = 2131361895;
|
||||
|
@ -6789,8 +6819,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0071
|
||||
public const int icon = 2131361905;
|
||||
|
||||
// aapt resource value: 0x7f0a00f3
|
||||
public const int icon_group = 2131362035;
|
||||
// aapt resource value: 0x7f0a00fd
|
||||
public const int icon_group = 2131362045;
|
||||
|
||||
// aapt resource value: 0x7f0a0041
|
||||
public const int ifRoom = 2131361857;
|
||||
|
@ -6798,8 +6828,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a006e
|
||||
public const int image = 2131361902;
|
||||
|
||||
// aapt resource value: 0x7f0a00ef
|
||||
public const int info = 2131362031;
|
||||
// aapt resource value: 0x7f0a00f9
|
||||
public const int info = 2131362041;
|
||||
|
||||
// aapt resource value: 0x7f0a0068
|
||||
public const int italic = 2131361896;
|
||||
|
@ -6810,8 +6840,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a004e
|
||||
public const int labeled = 2131361870;
|
||||
|
||||
// aapt resource value: 0x7f0a00a6
|
||||
public const int largeLabel = 2131361958;
|
||||
// aapt resource value: 0x7f0a00ad
|
||||
public const int largeLabel = 2131361965;
|
||||
|
||||
// aapt resource value: 0x7f0a0054
|
||||
public const int left = 2131361876;
|
||||
|
@ -6828,23 +6858,23 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0070
|
||||
public const int list_item = 2131361904;
|
||||
|
||||
// aapt resource value: 0x7f0a00f5
|
||||
public const int main_appbar = 2131362037;
|
||||
|
||||
// aapt resource value: 0x7f0a00f8
|
||||
public const int main_scrollview = 2131362040;
|
||||
|
||||
// aapt resource value: 0x7f0a00f7
|
||||
public const int main_tablayout = 2131362039;
|
||||
|
||||
// aapt resource value: 0x7f0a00f6
|
||||
public const int main_toolbar = 2131362038;
|
||||
|
||||
// aapt resource value: 0x7f0a00ff
|
||||
public const int masked = 2131362047;
|
||||
public const int main_appbar = 2131362047;
|
||||
|
||||
// aapt resource value: 0x7f0a00e8
|
||||
public const int media_actions = 2131362024;
|
||||
// aapt resource value: 0x7f0a0102
|
||||
public const int main_scrollview = 2131362050;
|
||||
|
||||
// aapt resource value: 0x7f0a0101
|
||||
public const int main_tablayout = 2131362049;
|
||||
|
||||
// aapt resource value: 0x7f0a0100
|
||||
public const int main_toolbar = 2131362048;
|
||||
|
||||
// aapt resource value: 0x7f0a0109
|
||||
public const int masked = 2131362057;
|
||||
|
||||
// aapt resource value: 0x7f0a00f2
|
||||
public const int media_actions = 2131362034;
|
||||
|
||||
// aapt resource value: 0x7f0a009c
|
||||
public const int message = 2131361948;
|
||||
|
@ -6855,143 +6885,143 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0059
|
||||
public const int mini = 2131361881;
|
||||
|
||||
// aapt resource value: 0x7f0a00cf
|
||||
public const int mr_art = 2131361999;
|
||||
|
||||
// aapt resource value: 0x7f0a00c0
|
||||
public const int mr_cast_checkbox = 2131361984;
|
||||
|
||||
// aapt resource value: 0x7f0a00b9
|
||||
public const int mr_cast_close_button = 2131361977;
|
||||
|
||||
// aapt resource value: 0x7f0a00b4
|
||||
public const int mr_cast_group_icon = 2131361972;
|
||||
|
||||
// aapt resource value: 0x7f0a00b5
|
||||
public const int mr_cast_group_name = 2131361973;
|
||||
|
||||
// aapt resource value: 0x7f0a00b3
|
||||
public const int mr_cast_list = 2131361971;
|
||||
|
||||
// aapt resource value: 0x7f0a00b8
|
||||
public const int mr_cast_meta = 2131361976;
|
||||
|
||||
// aapt resource value: 0x7f0a00ba
|
||||
public const int mr_cast_meta_art = 2131361978;
|
||||
|
||||
// aapt resource value: 0x7f0a00bc
|
||||
public const int mr_cast_meta_subtitle = 2131361980;
|
||||
|
||||
// aapt resource value: 0x7f0a00bb
|
||||
public const int mr_cast_meta_title = 2131361979;
|
||||
|
||||
// aapt resource value: 0x7f0a00be
|
||||
public const int mr_cast_route_icon = 2131361982;
|
||||
|
||||
// aapt resource value: 0x7f0a00bf
|
||||
public const int mr_cast_route_name = 2131361983;
|
||||
|
||||
// aapt resource value: 0x7f0a00bd
|
||||
public const int mr_cast_stop_button = 2131361981;
|
||||
|
||||
// aapt resource value: 0x7f0a00c1
|
||||
public const int mr_cast_volume_layout = 2131361985;
|
||||
|
||||
// aapt resource value: 0x7f0a00c2
|
||||
public const int mr_cast_volume_slider = 2131361986;
|
||||
|
||||
// aapt resource value: 0x7f0a00c4
|
||||
public const int mr_chooser_list = 2131361988;
|
||||
|
||||
// aapt resource value: 0x7f0a00c7
|
||||
public const int mr_chooser_route_desc = 2131361991;
|
||||
|
||||
// aapt resource value: 0x7f0a00c5
|
||||
public const int mr_chooser_route_icon = 2131361989;
|
||||
|
||||
// aapt resource value: 0x7f0a00c6
|
||||
public const int mr_chooser_route_name = 2131361990;
|
||||
|
||||
// aapt resource value: 0x7f0a00c3
|
||||
public const int mr_chooser_title = 2131361987;
|
||||
|
||||
// aapt resource value: 0x7f0a00cc
|
||||
public const int mr_close = 2131361996;
|
||||
|
||||
// aapt resource value: 0x7f0a00d2
|
||||
public const int mr_control_divider = 2131362002;
|
||||
|
||||
// aapt resource value: 0x7f0a00dd
|
||||
public const int mr_control_playback_ctrl = 2131362013;
|
||||
|
||||
// aapt resource value: 0x7f0a00e0
|
||||
public const int mr_control_subtitle = 2131362016;
|
||||
|
||||
// aapt resource value: 0x7f0a00df
|
||||
public const int mr_control_title = 2131362015;
|
||||
|
||||
// aapt resource value: 0x7f0a00de
|
||||
public const int mr_control_title_container = 2131362014;
|
||||
|
||||
// aapt resource value: 0x7f0a00cd
|
||||
public const int mr_custom_control = 2131361997;
|
||||
|
||||
// aapt resource value: 0x7f0a00ce
|
||||
public const int mr_default_control = 2131361998;
|
||||
|
||||
// aapt resource value: 0x7f0a00c9
|
||||
public const int mr_dialog_area = 2131361993;
|
||||
|
||||
// aapt resource value: 0x7f0a00d8
|
||||
public const int mr_dialog_header_name = 2131362008;
|
||||
|
||||
// aapt resource value: 0x7f0a00c8
|
||||
public const int mr_expandable_area = 2131361992;
|
||||
|
||||
// aapt resource value: 0x7f0a00e1
|
||||
public const int mr_group_expand_collapse = 2131362017;
|
||||
|
||||
// aapt resource value: 0x7f0a00b6
|
||||
public const int mr_group_volume_route_name = 2131361974;
|
||||
|
||||
// aapt resource value: 0x7f0a00b7
|
||||
public const int mr_group_volume_slider = 2131361975;
|
||||
|
||||
// aapt resource value: 0x7f0a00d0
|
||||
public const int mr_media_main_control = 2131362000;
|
||||
|
||||
// aapt resource value: 0x7f0a00cb
|
||||
public const int mr_name = 2131361995;
|
||||
|
||||
// aapt resource value: 0x7f0a00d9
|
||||
public const int mr_picker_close_button = 2131362009;
|
||||
|
||||
// aapt resource value: 0x7f0a00da
|
||||
public const int mr_picker_list = 2131362010;
|
||||
|
||||
// aapt resource value: 0x7f0a00db
|
||||
public const int mr_picker_route_icon = 2131362011;
|
||||
|
||||
// aapt resource value: 0x7f0a00dc
|
||||
public const int mr_picker_route_name = 2131362012;
|
||||
|
||||
// aapt resource value: 0x7f0a00d1
|
||||
public const int mr_playback_control = 2131362001;
|
||||
public const int mr_art = 2131362009;
|
||||
|
||||
// aapt resource value: 0x7f0a00ca
|
||||
public const int mr_title_bar = 2131361994;
|
||||
public const int mr_cast_checkbox = 2131361994;
|
||||
|
||||
// aapt resource value: 0x7f0a00d3
|
||||
public const int mr_volume_control = 2131362003;
|
||||
// aapt resource value: 0x7f0a00c3
|
||||
public const int mr_cast_close_button = 2131361987;
|
||||
|
||||
// aapt resource value: 0x7f0a00d4
|
||||
public const int mr_volume_group_list = 2131362004;
|
||||
// aapt resource value: 0x7f0a00be
|
||||
public const int mr_cast_group_icon = 2131361982;
|
||||
|
||||
// aapt resource value: 0x7f0a00bf
|
||||
public const int mr_cast_group_name = 2131361983;
|
||||
|
||||
// aapt resource value: 0x7f0a00bd
|
||||
public const int mr_cast_list = 2131361981;
|
||||
|
||||
// aapt resource value: 0x7f0a00c2
|
||||
public const int mr_cast_meta = 2131361986;
|
||||
|
||||
// aapt resource value: 0x7f0a00c4
|
||||
public const int mr_cast_meta_art = 2131361988;
|
||||
|
||||
// aapt resource value: 0x7f0a00c6
|
||||
public const int mr_cast_meta_subtitle = 2131361990;
|
||||
|
||||
// aapt resource value: 0x7f0a00c5
|
||||
public const int mr_cast_meta_title = 2131361989;
|
||||
|
||||
// aapt resource value: 0x7f0a00c8
|
||||
public const int mr_cast_route_icon = 2131361992;
|
||||
|
||||
// aapt resource value: 0x7f0a00c9
|
||||
public const int mr_cast_route_name = 2131361993;
|
||||
|
||||
// aapt resource value: 0x7f0a00c7
|
||||
public const int mr_cast_stop_button = 2131361991;
|
||||
|
||||
// aapt resource value: 0x7f0a00cb
|
||||
public const int mr_cast_volume_layout = 2131361995;
|
||||
|
||||
// aapt resource value: 0x7f0a00cc
|
||||
public const int mr_cast_volume_slider = 2131361996;
|
||||
|
||||
// aapt resource value: 0x7f0a00ce
|
||||
public const int mr_chooser_list = 2131361998;
|
||||
|
||||
// aapt resource value: 0x7f0a00d1
|
||||
public const int mr_chooser_route_desc = 2131362001;
|
||||
|
||||
// aapt resource value: 0x7f0a00cf
|
||||
public const int mr_chooser_route_icon = 2131361999;
|
||||
|
||||
// aapt resource value: 0x7f0a00d0
|
||||
public const int mr_chooser_route_name = 2131362000;
|
||||
|
||||
// aapt resource value: 0x7f0a00cd
|
||||
public const int mr_chooser_title = 2131361997;
|
||||
|
||||
// aapt resource value: 0x7f0a00d6
|
||||
public const int mr_volume_item_icon = 2131362006;
|
||||
public const int mr_close = 2131362006;
|
||||
|
||||
// aapt resource value: 0x7f0a00dc
|
||||
public const int mr_control_divider = 2131362012;
|
||||
|
||||
// aapt resource value: 0x7f0a00e7
|
||||
public const int mr_control_playback_ctrl = 2131362023;
|
||||
|
||||
// aapt resource value: 0x7f0a00ea
|
||||
public const int mr_control_subtitle = 2131362026;
|
||||
|
||||
// aapt resource value: 0x7f0a00e9
|
||||
public const int mr_control_title = 2131362025;
|
||||
|
||||
// aapt resource value: 0x7f0a00e8
|
||||
public const int mr_control_title_container = 2131362024;
|
||||
|
||||
// aapt resource value: 0x7f0a00d7
|
||||
public const int mr_volume_slider = 2131362007;
|
||||
public const int mr_custom_control = 2131362007;
|
||||
|
||||
// aapt resource value: 0x7f0a00d8
|
||||
public const int mr_default_control = 2131362008;
|
||||
|
||||
// aapt resource value: 0x7f0a00d3
|
||||
public const int mr_dialog_area = 2131362003;
|
||||
|
||||
// aapt resource value: 0x7f0a00e2
|
||||
public const int mr_dialog_header_name = 2131362018;
|
||||
|
||||
// aapt resource value: 0x7f0a00d2
|
||||
public const int mr_expandable_area = 2131362002;
|
||||
|
||||
// aapt resource value: 0x7f0a00eb
|
||||
public const int mr_group_expand_collapse = 2131362027;
|
||||
|
||||
// aapt resource value: 0x7f0a00c0
|
||||
public const int mr_group_volume_route_name = 2131361984;
|
||||
|
||||
// aapt resource value: 0x7f0a00c1
|
||||
public const int mr_group_volume_slider = 2131361985;
|
||||
|
||||
// aapt resource value: 0x7f0a00da
|
||||
public const int mr_media_main_control = 2131362010;
|
||||
|
||||
// aapt resource value: 0x7f0a00d5
|
||||
public const int mr_name = 2131362005;
|
||||
|
||||
// aapt resource value: 0x7f0a00e3
|
||||
public const int mr_picker_close_button = 2131362019;
|
||||
|
||||
// aapt resource value: 0x7f0a00e4
|
||||
public const int mr_picker_list = 2131362020;
|
||||
|
||||
// aapt resource value: 0x7f0a00e5
|
||||
public const int mr_picker_route_icon = 2131362021;
|
||||
|
||||
// aapt resource value: 0x7f0a00e6
|
||||
public const int mr_picker_route_name = 2131362022;
|
||||
|
||||
// aapt resource value: 0x7f0a00db
|
||||
public const int mr_playback_control = 2131362011;
|
||||
|
||||
// aapt resource value: 0x7f0a00d4
|
||||
public const int mr_title_bar = 2131362004;
|
||||
|
||||
// aapt resource value: 0x7f0a00dd
|
||||
public const int mr_volume_control = 2131362013;
|
||||
|
||||
// aapt resource value: 0x7f0a00de
|
||||
public const int mr_volume_group_list = 2131362014;
|
||||
|
||||
// aapt resource value: 0x7f0a00e0
|
||||
public const int mr_volume_item_icon = 2131362016;
|
||||
|
||||
// aapt resource value: 0x7f0a00e1
|
||||
public const int mr_volume_slider = 2131362017;
|
||||
|
||||
// aapt resource value: 0x7f0a0014
|
||||
public const int mtrl_child_content_container = 2131361812;
|
||||
|
@ -7002,8 +7032,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a002f
|
||||
public const int multiply = 2131361839;
|
||||
|
||||
// aapt resource value: 0x7f0a00ab
|
||||
public const int navigation_header_container = 2131361963;
|
||||
// aapt resource value: 0x7f0a00b2
|
||||
public const int navigation_header_container = 2131361970;
|
||||
|
||||
// aapt resource value: 0x7f0a0042
|
||||
public const int never = 2131361858;
|
||||
|
@ -7014,14 +7044,14 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0025
|
||||
public const int normal = 2131361829;
|
||||
|
||||
// aapt resource value: 0x7f0a00f1
|
||||
public const int notification_background = 2131362033;
|
||||
// aapt resource value: 0x7f0a00fb
|
||||
public const int notification_background = 2131362043;
|
||||
|
||||
// aapt resource value: 0x7f0a00eb
|
||||
public const int notification_main_column = 2131362027;
|
||||
// aapt resource value: 0x7f0a00f5
|
||||
public const int notification_main_column = 2131362037;
|
||||
|
||||
// aapt resource value: 0x7f0a00ea
|
||||
public const int notification_main_column_container = 2131362026;
|
||||
// aapt resource value: 0x7f0a00f4
|
||||
public const int notification_main_column_container = 2131362036;
|
||||
|
||||
// aapt resource value: 0x7f0a0060
|
||||
public const int outline = 2131361888;
|
||||
|
@ -7050,11 +7080,11 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0055
|
||||
public const int right = 2131361877;
|
||||
|
||||
// aapt resource value: 0x7f0a00f0
|
||||
public const int right_icon = 2131362032;
|
||||
// aapt resource value: 0x7f0a00fa
|
||||
public const int right_icon = 2131362042;
|
||||
|
||||
// aapt resource value: 0x7f0a00ec
|
||||
public const int right_side = 2131362028;
|
||||
// aapt resource value: 0x7f0a00f6
|
||||
public const int right_side = 2131362038;
|
||||
|
||||
// aapt resource value: 0x7f0a000c
|
||||
public const int save_image_matrix = 2131361804;
|
||||
|
@ -7119,14 +7149,14 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a004f
|
||||
public const int selected = 2131361871;
|
||||
|
||||
// aapt resource value: 0x7f0a00f9
|
||||
public const int shellcontent_appbar = 2131362041;
|
||||
// aapt resource value: 0x7f0a0103
|
||||
public const int shellcontent_appbar = 2131362051;
|
||||
|
||||
// aapt resource value: 0x7f0a00fb
|
||||
public const int shellcontent_scrollview = 2131362043;
|
||||
// aapt resource value: 0x7f0a0105
|
||||
public const int shellcontent_scrollview = 2131362053;
|
||||
|
||||
// aapt resource value: 0x7f0a00fa
|
||||
public const int shellcontent_toolbar = 2131362042;
|
||||
// aapt resource value: 0x7f0a0104
|
||||
public const int shellcontent_toolbar = 2131362052;
|
||||
|
||||
// aapt resource value: 0x7f0a0083
|
||||
public const int shortcut = 2131361923;
|
||||
|
@ -7140,11 +7170,11 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a002c
|
||||
public const int showTitle = 2131361836;
|
||||
|
||||
// aapt resource value: 0x7f0a00fc
|
||||
public const int sliding_tabs = 2131362044;
|
||||
// aapt resource value: 0x7f0a0106
|
||||
public const int sliding_tabs = 2131362054;
|
||||
|
||||
// aapt resource value: 0x7f0a00a5
|
||||
public const int smallLabel = 2131361957;
|
||||
// aapt resource value: 0x7f0a00ac
|
||||
public const int smallLabel = 2131361964;
|
||||
|
||||
// aapt resource value: 0x7f0a0016
|
||||
public const int snackbar_action = 2131361814;
|
||||
|
@ -7176,8 +7206,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a0056
|
||||
public const int start = 2131361878;
|
||||
|
||||
// aapt resource value: 0x7f0a00e7
|
||||
public const int status_bar_latest_event_content = 2131362023;
|
||||
// aapt resource value: 0x7f0a00f1
|
||||
public const int status_bar_latest_event_content = 2131362033;
|
||||
|
||||
// aapt resource value: 0x7f0a005b
|
||||
public const int stretch = 2131361883;
|
||||
|
@ -7218,8 +7248,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a005a
|
||||
public const int textStart = 2131361882;
|
||||
|
||||
// aapt resource value: 0x7f0a00b0
|
||||
public const int text_input_password_toggle = 2131361968;
|
||||
// aapt resource value: 0x7f0a00b7
|
||||
public const int text_input_password_toggle = 2131361975;
|
||||
|
||||
// aapt resource value: 0x7f0a0018
|
||||
public const int textinput_counter = 2131361816;
|
||||
|
@ -7230,8 +7260,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a001a
|
||||
public const int textinput_helper_text = 2131361818;
|
||||
|
||||
// aapt resource value: 0x7f0a00ed
|
||||
public const int time = 2131362029;
|
||||
// aapt resource value: 0x7f0a00f7
|
||||
public const int time = 2131362039;
|
||||
|
||||
// aapt resource value: 0x7f0a0023
|
||||
public const int title = 2131361827;
|
||||
|
@ -7242,8 +7272,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a007e
|
||||
public const int title_template = 2131361918;
|
||||
|
||||
// aapt resource value: 0x7f0a00fd
|
||||
public const int toolbar = 2131362045;
|
||||
// aapt resource value: 0x7f0a0107
|
||||
public const int toolbar = 2131362055;
|
||||
|
||||
// aapt resource value: 0x7f0a0045
|
||||
public const int top = 2131361861;
|
||||
|
@ -7251,8 +7281,8 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a007d
|
||||
public const int topPanel = 2131361917;
|
||||
|
||||
// aapt resource value: 0x7f0a00a9
|
||||
public const int touch_outside = 2131361961;
|
||||
// aapt resource value: 0x7f0a00b0
|
||||
public const int touch_outside = 2131361968;
|
||||
|
||||
// aapt resource value: 0x7f0a000f
|
||||
public const int transition_current_scene = 2131361807;
|
||||
|
@ -7284,11 +7314,11 @@ namespace Bit.Droid
|
|||
// aapt resource value: 0x7f0a001b
|
||||
public const int view_offset_helper = 2131361819;
|
||||
|
||||
// aapt resource value: 0x7f0a00fe
|
||||
public const int visible = 2131362046;
|
||||
// aapt resource value: 0x7f0a0108
|
||||
public const int visible = 2131362056;
|
||||
|
||||
// aapt resource value: 0x7f0a00d5
|
||||
public const int volume_item_container = 2131362005;
|
||||
// aapt resource value: 0x7f0a00df
|
||||
public const int volume_item_container = 2131362015;
|
||||
|
||||
// aapt resource value: 0x7f0a0043
|
||||
public const int withText = 2131361859;
|
||||
|
@ -7507,166 +7537,178 @@ namespace Bit.Droid
|
|||
public const int browser_actions_context_menu_row = 2130968607;
|
||||
|
||||
// aapt resource value: 0x7f040020
|
||||
public const int design_bottom_navigation_item = 2130968608;
|
||||
public const int CellBaseView = 2130968608;
|
||||
|
||||
// aapt resource value: 0x7f040021
|
||||
public const int design_bottom_sheet_dialog = 2130968609;
|
||||
public const int ContentCell = 2130968609;
|
||||
|
||||
// aapt resource value: 0x7f040022
|
||||
public const int design_layout_snackbar = 2130968610;
|
||||
public const int design_bottom_navigation_item = 2130968610;
|
||||
|
||||
// aapt resource value: 0x7f040023
|
||||
public const int design_layout_snackbar_include = 2130968611;
|
||||
public const int design_bottom_sheet_dialog = 2130968611;
|
||||
|
||||
// aapt resource value: 0x7f040024
|
||||
public const int design_layout_tab_icon = 2130968612;
|
||||
public const int design_layout_snackbar = 2130968612;
|
||||
|
||||
// aapt resource value: 0x7f040025
|
||||
public const int design_layout_tab_text = 2130968613;
|
||||
public const int design_layout_snackbar_include = 2130968613;
|
||||
|
||||
// aapt resource value: 0x7f040026
|
||||
public const int design_menu_item_action_area = 2130968614;
|
||||
public const int design_layout_tab_icon = 2130968614;
|
||||
|
||||
// aapt resource value: 0x7f040027
|
||||
public const int design_navigation_item = 2130968615;
|
||||
public const int design_layout_tab_text = 2130968615;
|
||||
|
||||
// aapt resource value: 0x7f040028
|
||||
public const int design_navigation_item_header = 2130968616;
|
||||
public const int design_menu_item_action_area = 2130968616;
|
||||
|
||||
// aapt resource value: 0x7f040029
|
||||
public const int design_navigation_item_separator = 2130968617;
|
||||
public const int design_navigation_item = 2130968617;
|
||||
|
||||
// aapt resource value: 0x7f04002a
|
||||
public const int design_navigation_item_subheader = 2130968618;
|
||||
public const int design_navigation_item_header = 2130968618;
|
||||
|
||||
// aapt resource value: 0x7f04002b
|
||||
public const int design_navigation_menu = 2130968619;
|
||||
public const int design_navigation_item_separator = 2130968619;
|
||||
|
||||
// aapt resource value: 0x7f04002c
|
||||
public const int design_navigation_menu_item = 2130968620;
|
||||
public const int design_navigation_item_subheader = 2130968620;
|
||||
|
||||
// aapt resource value: 0x7f04002d
|
||||
public const int design_text_input_password_icon = 2130968621;
|
||||
public const int design_navigation_menu = 2130968621;
|
||||
|
||||
// aapt resource value: 0x7f04002e
|
||||
public const int FlyoutContent = 2130968622;
|
||||
public const int design_navigation_menu_item = 2130968622;
|
||||
|
||||
// aapt resource value: 0x7f04002f
|
||||
public const int mr_cast_dialog = 2130968623;
|
||||
public const int design_text_input_password_icon = 2130968623;
|
||||
|
||||
// aapt resource value: 0x7f040030
|
||||
public const int mr_cast_group_item = 2130968624;
|
||||
public const int FlyoutContent = 2130968624;
|
||||
|
||||
// aapt resource value: 0x7f040031
|
||||
public const int mr_cast_group_volume_item = 2130968625;
|
||||
public const int FooterCell = 2130968625;
|
||||
|
||||
// aapt resource value: 0x7f040032
|
||||
public const int mr_cast_media_metadata = 2130968626;
|
||||
public const int HeaderCell = 2130968626;
|
||||
|
||||
// aapt resource value: 0x7f040033
|
||||
public const int mr_cast_route_item = 2130968627;
|
||||
public const int mr_cast_dialog = 2130968627;
|
||||
|
||||
// aapt resource value: 0x7f040034
|
||||
public const int mr_chooser_dialog = 2130968628;
|
||||
public const int mr_cast_group_item = 2130968628;
|
||||
|
||||
// aapt resource value: 0x7f040035
|
||||
public const int mr_chooser_list_item = 2130968629;
|
||||
public const int mr_cast_group_volume_item = 2130968629;
|
||||
|
||||
// aapt resource value: 0x7f040036
|
||||
public const int mr_controller_material_dialog_b = 2130968630;
|
||||
public const int mr_cast_media_metadata = 2130968630;
|
||||
|
||||
// aapt resource value: 0x7f040037
|
||||
public const int mr_controller_volume_item = 2130968631;
|
||||
public const int mr_cast_route_item = 2130968631;
|
||||
|
||||
// aapt resource value: 0x7f040038
|
||||
public const int mr_dialog_header_item = 2130968632;
|
||||
public const int mr_chooser_dialog = 2130968632;
|
||||
|
||||
// aapt resource value: 0x7f040039
|
||||
public const int mr_picker_dialog = 2130968633;
|
||||
public const int mr_chooser_list_item = 2130968633;
|
||||
|
||||
// aapt resource value: 0x7f04003a
|
||||
public const int mr_picker_route_item = 2130968634;
|
||||
public const int mr_controller_material_dialog_b = 2130968634;
|
||||
|
||||
// aapt resource value: 0x7f04003b
|
||||
public const int mr_playback_control = 2130968635;
|
||||
public const int mr_controller_volume_item = 2130968635;
|
||||
|
||||
// aapt resource value: 0x7f04003c
|
||||
public const int mr_volume_control = 2130968636;
|
||||
public const int mr_dialog_header_item = 2130968636;
|
||||
|
||||
// aapt resource value: 0x7f04003d
|
||||
public const int mtrl_layout_snackbar = 2130968637;
|
||||
public const int mr_picker_dialog = 2130968637;
|
||||
|
||||
// aapt resource value: 0x7f04003e
|
||||
public const int mtrl_layout_snackbar_include = 2130968638;
|
||||
public const int mr_picker_route_item = 2130968638;
|
||||
|
||||
// aapt resource value: 0x7f04003f
|
||||
public const int notification_action = 2130968639;
|
||||
public const int mr_playback_control = 2130968639;
|
||||
|
||||
// aapt resource value: 0x7f040040
|
||||
public const int notification_action_tombstone = 2130968640;
|
||||
public const int mr_volume_control = 2130968640;
|
||||
|
||||
// aapt resource value: 0x7f040041
|
||||
public const int notification_media_action = 2130968641;
|
||||
public const int mtrl_layout_snackbar = 2130968641;
|
||||
|
||||
// aapt resource value: 0x7f040042
|
||||
public const int notification_media_cancel_action = 2130968642;
|
||||
public const int mtrl_layout_snackbar_include = 2130968642;
|
||||
|
||||
// aapt resource value: 0x7f040043
|
||||
public const int notification_template_big_media = 2130968643;
|
||||
public const int notification_action = 2130968643;
|
||||
|
||||
// aapt resource value: 0x7f040044
|
||||
public const int notification_template_big_media_custom = 2130968644;
|
||||
public const int notification_action_tombstone = 2130968644;
|
||||
|
||||
// aapt resource value: 0x7f040045
|
||||
public const int notification_template_big_media_narrow = 2130968645;
|
||||
public const int notification_media_action = 2130968645;
|
||||
|
||||
// aapt resource value: 0x7f040046
|
||||
public const int notification_template_big_media_narrow_custom = 2130968646;
|
||||
public const int notification_media_cancel_action = 2130968646;
|
||||
|
||||
// aapt resource value: 0x7f040047
|
||||
public const int notification_template_custom_big = 2130968647;
|
||||
public const int notification_template_big_media = 2130968647;
|
||||
|
||||
// aapt resource value: 0x7f040048
|
||||
public const int notification_template_icon_group = 2130968648;
|
||||
public const int notification_template_big_media_custom = 2130968648;
|
||||
|
||||
// aapt resource value: 0x7f040049
|
||||
public const int notification_template_lines_media = 2130968649;
|
||||
public const int notification_template_big_media_narrow = 2130968649;
|
||||
|
||||
// aapt resource value: 0x7f04004a
|
||||
public const int notification_template_media = 2130968650;
|
||||
public const int notification_template_big_media_narrow_custom = 2130968650;
|
||||
|
||||
// aapt resource value: 0x7f04004b
|
||||
public const int notification_template_media_custom = 2130968651;
|
||||
public const int notification_template_custom_big = 2130968651;
|
||||
|
||||
// aapt resource value: 0x7f04004c
|
||||
public const int notification_template_part_chronometer = 2130968652;
|
||||
public const int notification_template_icon_group = 2130968652;
|
||||
|
||||
// aapt resource value: 0x7f04004d
|
||||
public const int notification_template_part_time = 2130968653;
|
||||
public const int notification_template_lines_media = 2130968653;
|
||||
|
||||
// aapt resource value: 0x7f04004e
|
||||
public const int RootLayout = 2130968654;
|
||||
public const int notification_template_media = 2130968654;
|
||||
|
||||
// aapt resource value: 0x7f04004f
|
||||
public const int select_dialog_item_material = 2130968655;
|
||||
public const int notification_template_media_custom = 2130968655;
|
||||
|
||||
// aapt resource value: 0x7f040050
|
||||
public const int select_dialog_multichoice_material = 2130968656;
|
||||
public const int notification_template_part_chronometer = 2130968656;
|
||||
|
||||
// aapt resource value: 0x7f040051
|
||||
public const int select_dialog_singlechoice_material = 2130968657;
|
||||
public const int notification_template_part_time = 2130968657;
|
||||
|
||||
// aapt resource value: 0x7f040052
|
||||
public const int ShellContent = 2130968658;
|
||||
public const int RootLayout = 2130968658;
|
||||
|
||||
// aapt resource value: 0x7f040053
|
||||
public const int support_simple_spinner_dropdown_item = 2130968659;
|
||||
public const int select_dialog_item_material = 2130968659;
|
||||
|
||||
// aapt resource value: 0x7f040054
|
||||
public const int Tabbar = 2130968660;
|
||||
public const int select_dialog_multichoice_material = 2130968660;
|
||||
|
||||
// aapt resource value: 0x7f040055
|
||||
public const int Toolbar = 2130968661;
|
||||
public const int select_dialog_singlechoice_material = 2130968661;
|
||||
|
||||
// aapt resource value: 0x7f040056
|
||||
public const int ShellContent = 2130968662;
|
||||
|
||||
// aapt resource value: 0x7f040057
|
||||
public const int support_simple_spinner_dropdown_item = 2130968663;
|
||||
|
||||
// aapt resource value: 0x7f040058
|
||||
public const int Tabbar = 2130968664;
|
||||
|
||||
// aapt resource value: 0x7f040059
|
||||
public const int Toolbar = 2130968665;
|
||||
|
||||
static Layout()
|
||||
{
|
||||
|
|
50
src/Android/Resources/layout/CellBaseView.axml
Normal file
50
src/Android/Resources/layout/CellBaseView.axml
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:minHeight="44dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp">
|
||||
<LinearLayout
|
||||
android:id="@+id/CellBody"
|
||||
android:orientation="vertical"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="4dp">
|
||||
<LinearLayout
|
||||
android:id="@+id/CellContentStack"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:weightSum="1">
|
||||
<TextView
|
||||
android:id="@+id/CellTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:gravity="left"
|
||||
android:paddingRight="6dp"
|
||||
android:layout_gravity="left|center_vertical" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/CellDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="left"
|
||||
android:layout_gravity="left"
|
||||
android:layout_marginTop="2dp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/CellAccessoryView"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical" />
|
||||
</RelativeLayout>
|
21
src/Android/Resources/layout/ContentCell.axml
Normal file
21
src/Android/Resources/layout/ContentCell.axml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="44dp">
|
||||
<LinearLayout
|
||||
android:id="@+id/ContentCellBody"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<LinearLayout
|
||||
android:id="@+id/ContentCellBorder"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px" />
|
||||
</RelativeLayout>
|
15
src/Android/Resources/layout/FooterCell.axml
Normal file
15
src/Android/Resources/layout/FooterCell.axml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="0dp">
|
||||
<TextView
|
||||
android:id="@+id/FooterCellText"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="top|left" />
|
||||
</RelativeLayout>
|
22
src/Android/Resources/layout/HeaderCell.axml
Normal file
22
src/Android/Resources/layout/HeaderCell.axml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="0dp">
|
||||
<TextView
|
||||
android:id="@+id/HeaderCellText"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="left" />
|
||||
<LinearLayout
|
||||
android:id="@+id/HeaderCellBorder"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px" />
|
||||
</RelativeLayout>
|
85
src/App/Controls/BoxedView/BoxedModel.cs
Normal file
85
src/App/Controls/BoxedView/BoxedModel.cs
Normal file
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
namespace Bit.App.Controls.BoxedView
|
||||
{
|
||||
public class BoxedModel : TableModel
|
||||
{
|
||||
private static readonly BindableProperty PathProperty = BindableProperty.Create(
|
||||
"Path", typeof(Tuple<int, int>), typeof(Cell), null);
|
||||
|
||||
private BoxedRoot _root;
|
||||
private IEnumerable<BoxedSection> _visibleSections;
|
||||
|
||||
public BoxedModel(BoxedRoot root)
|
||||
{
|
||||
_root = root;
|
||||
_visibleSections = _root.Where(x => x.IsVisible);
|
||||
}
|
||||
|
||||
public override Cell GetCell(int section, int row)
|
||||
{
|
||||
var cell = (Cell)GetItem(section, row);
|
||||
SetPath(cell, new Tuple<int, int>(section, row));
|
||||
return cell;
|
||||
}
|
||||
|
||||
public override object GetItem(int section, int row)
|
||||
{
|
||||
return _visibleSections.ElementAt(section)[row];
|
||||
}
|
||||
|
||||
public override int GetRowCount(int section)
|
||||
{
|
||||
return _visibleSections.ElementAt(section).Count;
|
||||
}
|
||||
|
||||
public override int GetSectionCount()
|
||||
{
|
||||
return _visibleSections.Count();
|
||||
}
|
||||
|
||||
public virtual BoxedSection GetSection(int section)
|
||||
{
|
||||
return _visibleSections.ElementAtOrDefault(section);
|
||||
}
|
||||
|
||||
public override string GetSectionTitle(int section)
|
||||
{
|
||||
return _visibleSections.ElementAt(section).Title;
|
||||
}
|
||||
|
||||
public virtual string GetFooterText(int section)
|
||||
{
|
||||
return _visibleSections.ElementAt(section).FooterText;
|
||||
}
|
||||
|
||||
protected override void OnRowSelected(object item)
|
||||
{
|
||||
base.OnRowSelected(item);
|
||||
(item as BaseCell)?.OnTapped();
|
||||
}
|
||||
|
||||
public virtual double GetHeaderHeight(int section)
|
||||
{
|
||||
return _visibleSections.ElementAt(section).HeaderHeight;
|
||||
}
|
||||
|
||||
public static Tuple<int, int> GetPath(Cell item)
|
||||
{
|
||||
if(item == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
}
|
||||
return item.GetValue(PathProperty) as Tuple<int, int>;
|
||||
}
|
||||
|
||||
private static void SetPath(Cell item, Tuple<int, int> index)
|
||||
{
|
||||
item?.SetValue(PathProperty, index);
|
||||
}
|
||||
}
|
||||
}
|
61
src/App/Controls/BoxedView/BoxedRoot.cs
Normal file
61
src/App/Controls/BoxedView/BoxedRoot.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls.BoxedView
|
||||
{
|
||||
public class BoxedRoot : TableSectionBase<BoxedSection>
|
||||
{
|
||||
public BoxedRoot()
|
||||
{
|
||||
SetupEvents();
|
||||
}
|
||||
|
||||
public event EventHandler<EventArgs> SectionCollectionChanged;
|
||||
|
||||
private void ChildCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
SectionCollectionChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if(e.PropertyName == TitleProperty.PropertyName)
|
||||
{
|
||||
OnPropertyChanged(TitleProperty.PropertyName);
|
||||
}
|
||||
else if(e.PropertyName == BoxedSection.FooterTextProperty.PropertyName)
|
||||
{
|
||||
OnPropertyChanged(BoxedSection.FooterTextProperty.PropertyName);
|
||||
}
|
||||
else if(e.PropertyName == BoxedSection.IsVisibleProperty.PropertyName)
|
||||
{
|
||||
OnPropertyChanged(BoxedSection.IsVisibleProperty.PropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupEvents()
|
||||
{
|
||||
CollectionChanged += (sender, args) =>
|
||||
{
|
||||
if(args.NewItems != null)
|
||||
{
|
||||
foreach(BoxedSection section in args.NewItems)
|
||||
{
|
||||
section.CollectionChanged += ChildCollectionChanged;
|
||||
section.PropertyChanged += ChildPropertyChanged;
|
||||
}
|
||||
}
|
||||
if(args.OldItems != null)
|
||||
{
|
||||
foreach(BoxedSection section in args.OldItems)
|
||||
{
|
||||
section.CollectionChanged -= ChildCollectionChanged;
|
||||
section.PropertyChanged -= ChildPropertyChanged;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
147
src/App/Controls/BoxedView/BoxedSection.cs
Normal file
147
src/App/Controls/BoxedView/BoxedSection.cs
Normal file
|
@ -0,0 +1,147 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls.BoxedView
|
||||
{
|
||||
public class BoxedSection : TableSectionBase<Cell>
|
||||
{
|
||||
public static BindableProperty IsVisibleProperty = BindableProperty.Create(
|
||||
nameof(IsVisible), typeof(bool), typeof(BoxedSection), true, defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty FooterTextProperty = BindableProperty.Create(
|
||||
nameof(FooterText), typeof(string), typeof(BoxedSection), default(string),
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty ItemTemplateProperty = BindableProperty.Create(
|
||||
nameof(ItemTemplate), typeof(DataTemplate), typeof(BoxedSection), default(DataTemplate),
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty ItemsSourceProperty = BindableProperty.Create(
|
||||
nameof(ItemsSource), typeof(IList), typeof(BoxedSection), default(IList),
|
||||
defaultBindingMode: BindingMode.OneWay, propertyChanged: ItemsChanged);
|
||||
|
||||
public static BindableProperty HeaderHeightProperty = BindableProperty.Create(
|
||||
nameof(HeaderHeight), typeof(double), typeof(BoxedSection), -1d, defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty UseDragSortProperty = BindableProperty.Create(
|
||||
nameof(UseDragSort), typeof(bool), typeof(BoxedSection), false, defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public BoxedSection()
|
||||
{ }
|
||||
|
||||
public BoxedSection(string title)
|
||||
: base(title)
|
||||
{ }
|
||||
|
||||
public bool IsVisible
|
||||
{
|
||||
get => (bool)GetValue(IsVisibleProperty);
|
||||
set => SetValue(IsVisibleProperty, value);
|
||||
}
|
||||
|
||||
public string FooterText
|
||||
{
|
||||
get => (string)GetValue(FooterTextProperty);
|
||||
set => SetValue(FooterTextProperty, value);
|
||||
}
|
||||
|
||||
public DataTemplate ItemTemplate
|
||||
{
|
||||
get => (DataTemplate)GetValue(ItemTemplateProperty);
|
||||
set => SetValue(ItemTemplateProperty, value);
|
||||
}
|
||||
|
||||
public IList ItemsSource
|
||||
{
|
||||
get => (IList)GetValue(ItemsSourceProperty);
|
||||
set => SetValue(ItemsSourceProperty, value);
|
||||
}
|
||||
|
||||
public double HeaderHeight
|
||||
{
|
||||
get => (double)GetValue(HeaderHeightProperty);
|
||||
set => SetValue(HeaderHeightProperty, value);
|
||||
}
|
||||
|
||||
public bool UseDragSort
|
||||
{
|
||||
get => (bool)GetValue(UseDragSortProperty);
|
||||
set => SetValue(UseDragSortProperty, value);
|
||||
}
|
||||
|
||||
private static void ItemsChanged(BindableObject bindable, object oldValue, object newValue)
|
||||
{
|
||||
var section = bindable as BoxedSection;
|
||||
if(section.ItemTemplate == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(oldValue is INotifyCollectionChanged oldObservableCollection)
|
||||
{
|
||||
oldObservableCollection.CollectionChanged -= section.OnItemsSourceCollectionChanged;
|
||||
}
|
||||
if(newValue is INotifyCollectionChanged newObservableCollection)
|
||||
{
|
||||
newObservableCollection.CollectionChanged += section.OnItemsSourceCollectionChanged;
|
||||
}
|
||||
|
||||
section.Clear();
|
||||
|
||||
if(newValue is IList newValueAsEnumerable)
|
||||
{
|
||||
foreach(var item in newValueAsEnumerable)
|
||||
{
|
||||
var view = CreateChildViewFor(section.ItemTemplate, item, section);
|
||||
section.Add(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if(e.Action == NotifyCollectionChangedAction.Replace)
|
||||
{
|
||||
RemoveAt(e.OldStartingIndex);
|
||||
var item = e.NewItems[e.NewStartingIndex];
|
||||
var view = CreateChildViewFor(ItemTemplate, item, this);
|
||||
Insert(e.NewStartingIndex, view);
|
||||
}
|
||||
else if(e.Action == NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
if(e.NewItems != null)
|
||||
{
|
||||
for(var i = 0; i < e.NewItems.Count; ++i)
|
||||
{
|
||||
var item = e.NewItems[i];
|
||||
var view = CreateChildViewFor(ItemTemplate, item, this);
|
||||
Insert(i + e.NewStartingIndex, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(e.Action == NotifyCollectionChangedAction.Remove)
|
||||
{
|
||||
if(e.OldItems != null)
|
||||
{
|
||||
RemoveAt(e.OldStartingIndex);
|
||||
}
|
||||
}
|
||||
else if(e.Action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static Cell CreateChildViewFor(DataTemplate template, object item, BindableObject container)
|
||||
{
|
||||
if(template is DataTemplateSelector selector)
|
||||
{
|
||||
template = selector.SelectTemplate(item, container);
|
||||
}
|
||||
// Binding context
|
||||
template.SetValue(BindingContextProperty, item);
|
||||
return template.CreateContent() as Cell;
|
||||
}
|
||||
}
|
||||
}
|
602
src/App/Controls/BoxedView/BoxedView.cs
Normal file
602
src/App/Controls/BoxedView/BoxedView.cs
Normal file
|
@ -0,0 +1,602 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls.BoxedView
|
||||
{
|
||||
[ContentProperty("Root")]
|
||||
public class BoxedView : TableView
|
||||
{
|
||||
private BoxedRoot _root;
|
||||
|
||||
public new event EventHandler ModelChanged;
|
||||
|
||||
public BoxedView()
|
||||
{
|
||||
VerticalOptions = HorizontalOptions = LayoutOptions.FillAndExpand;
|
||||
Root = new BoxedRoot();
|
||||
Model = new BoxedModel(Root);
|
||||
}
|
||||
|
||||
public new BoxedModel Model { get; set; }
|
||||
|
||||
public new BoxedRoot Root
|
||||
{
|
||||
get => _root;
|
||||
set
|
||||
{
|
||||
if(_root != null)
|
||||
{
|
||||
_root.PropertyChanged -= RootOnPropertyChanged;
|
||||
_root.CollectionChanged -= OnCollectionChanged;
|
||||
_root.SectionCollectionChanged -= OnSectionCollectionChanged;
|
||||
}
|
||||
|
||||
_root = value;
|
||||
|
||||
// Transfer binding context to the children (maybe...)
|
||||
SetInheritedBindingContext(_root, BindingContext);
|
||||
|
||||
_root.PropertyChanged += RootOnPropertyChanged;
|
||||
_root.CollectionChanged += OnCollectionChanged;
|
||||
_root.SectionCollectionChanged += OnSectionCollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBindingContextChanged()
|
||||
{
|
||||
base.OnBindingContextChanged();
|
||||
if(Root != null)
|
||||
{
|
||||
SetInheritedBindingContext(Root, BindingContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void RootOnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if(e.PropertyName == TableSectionBase.TitleProperty.PropertyName ||
|
||||
e.PropertyName == BoxedSection.FooterTextProperty.PropertyName ||
|
||||
e.PropertyName == BoxedSection.IsVisibleProperty.PropertyName)
|
||||
{
|
||||
OnModelChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(string propertyName = null)
|
||||
{
|
||||
base.OnPropertyChanged(propertyName);
|
||||
var changed = propertyName == HasUnevenRowsProperty.PropertyName ||
|
||||
propertyName == HeaderHeightProperty.PropertyName ||
|
||||
propertyName == HeaderFontSizeProperty.PropertyName ||
|
||||
propertyName == HeaderTextColorProperty.PropertyName ||
|
||||
propertyName == HeaderBackgroundColorProperty.PropertyName ||
|
||||
propertyName == HeaderTextVerticalAlignProperty.PropertyName ||
|
||||
propertyName == HeaderPaddingProperty.PropertyName ||
|
||||
propertyName == FooterFontSizeProperty.PropertyName ||
|
||||
propertyName == FooterTextColorProperty.PropertyName ||
|
||||
propertyName == FooterBackgroundColorProperty.PropertyName ||
|
||||
propertyName == FooterPaddingProperty.PropertyName;
|
||||
if(changed)
|
||||
{
|
||||
OnModelChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnModelChanged();
|
||||
}
|
||||
|
||||
public void OnSectionCollectionChanged(object sender, EventArgs childCollectionChangedEventArgs)
|
||||
{
|
||||
OnModelChanged();
|
||||
}
|
||||
|
||||
protected new void OnModelChanged()
|
||||
{
|
||||
var cells = Root?.SelectMany(r => r);
|
||||
if(cells == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach(var cell in cells)
|
||||
{
|
||||
cell.Parent = this;
|
||||
}
|
||||
ModelChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
// Make the unnecessary property existing at TableView sealed.
|
||||
private new int Intent { get; set; }
|
||||
|
||||
public static new BindableProperty BackgroundColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(BackgroundColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public new Color BackgroundColor
|
||||
{
|
||||
get { return (Color)GetValue(BackgroundColorProperty); }
|
||||
set { SetValue(BackgroundColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty SeparatorColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(SeparatorColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
Color.FromRgb(199, 199, 204),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color SeparatorColor
|
||||
{
|
||||
get { return (Color)GetValue(SeparatorColorProperty); }
|
||||
set { SetValue(SeparatorColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty SelectedColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(SelectedColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color SelectedColor
|
||||
{
|
||||
get { return (Color)GetValue(SelectedColorProperty); }
|
||||
set { SetValue(SelectedColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty HeaderPaddingProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(HeaderPadding),
|
||||
typeof(Thickness),
|
||||
typeof(BoxedView),
|
||||
new Thickness(14, 8, 8, 8),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Thickness HeaderPadding
|
||||
{
|
||||
get { return (Thickness)GetValue(HeaderPaddingProperty); }
|
||||
set { SetValue(HeaderPaddingProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty HeaderTextColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(HeaderTextColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color HeaderTextColor
|
||||
{
|
||||
get { return (Color)GetValue(HeaderTextColorProperty); }
|
||||
set { SetValue(HeaderTextColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty HeaderFontSizeProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(HeaderFontSize),
|
||||
typeof(double),
|
||||
typeof(BoxedView),
|
||||
-1.0d,
|
||||
defaultBindingMode: BindingMode.OneWay,
|
||||
defaultValueCreator: bindable => Device.GetNamedSize(NamedSize.Small, (BoxedView)bindable)
|
||||
);
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double HeaderFontSize
|
||||
{
|
||||
get { return (double)GetValue(HeaderFontSizeProperty); }
|
||||
set { SetValue(HeaderFontSizeProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty HeaderTextVerticalAlignProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(HeaderTextVerticalAlign),
|
||||
typeof(LayoutAlignment),
|
||||
typeof(BoxedView),
|
||||
LayoutAlignment.End,
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public LayoutAlignment HeaderTextVerticalAlign
|
||||
{
|
||||
get { return (LayoutAlignment)GetValue(HeaderTextVerticalAlignProperty); }
|
||||
set { SetValue(HeaderTextVerticalAlignProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty HeaderBackgroundColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(HeaderBackgroundColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color HeaderBackgroundColor
|
||||
{
|
||||
get { return (Color)GetValue(HeaderBackgroundColorProperty); }
|
||||
set { SetValue(HeaderBackgroundColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty HeaderHeightProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(HeaderHeight),
|
||||
typeof(double),
|
||||
typeof(BoxedView),
|
||||
-1d,
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public double HeaderHeight
|
||||
{
|
||||
get { return (double)GetValue(HeaderHeightProperty); }
|
||||
set { SetValue(HeaderHeightProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty FooterTextColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(FooterTextColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color FooterTextColor
|
||||
{
|
||||
get { return (Color)GetValue(FooterTextColorProperty); }
|
||||
set { SetValue(FooterTextColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty FooterFontSizeProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(FooterFontSize),
|
||||
typeof(double),
|
||||
typeof(BoxedView),
|
||||
-1.0d,
|
||||
defaultBindingMode: BindingMode.OneWay,
|
||||
defaultValueCreator: bindable => Device.GetNamedSize(NamedSize.Small, (BoxedView)bindable)
|
||||
);
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double FooterFontSize
|
||||
{
|
||||
get { return (double)GetValue(FooterFontSizeProperty); }
|
||||
set { SetValue(FooterFontSizeProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty FooterBackgroundColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(FooterBackgroundColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color FooterBackgroundColor
|
||||
{
|
||||
get { return (Color)GetValue(FooterBackgroundColorProperty); }
|
||||
set { SetValue(FooterBackgroundColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty FooterPaddingProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(FooterPadding),
|
||||
typeof(Thickness),
|
||||
typeof(BoxedView),
|
||||
new Thickness(14, 8, 14, 8),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Thickness FooterPadding
|
||||
{
|
||||
get { return (Thickness)GetValue(FooterPaddingProperty); }
|
||||
set { SetValue(FooterPaddingProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty CellTitleColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CellTitleColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color CellTitleColor
|
||||
{
|
||||
get { return (Color)GetValue(CellTitleColorProperty); }
|
||||
set { SetValue(CellTitleColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty CellTitleFontSizeProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CellTitleFontSize),
|
||||
typeof(double),
|
||||
typeof(BoxedView),
|
||||
-1.0,
|
||||
defaultBindingMode: BindingMode.OneWay,
|
||||
defaultValueCreator: bindable => Device.GetNamedSize(NamedSize.Default, (BoxedView)bindable)
|
||||
);
|
||||
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double CellTitleFontSize
|
||||
{
|
||||
get { return (double)GetValue(CellTitleFontSizeProperty); }
|
||||
set { SetValue(CellTitleFontSizeProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty CellValueTextColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CellValueTextColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color CellValueTextColor
|
||||
{
|
||||
get { return (Color)GetValue(CellValueTextColorProperty); }
|
||||
set { SetValue(CellValueTextColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty CellValueTextFontSizeProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CellValueTextFontSize),
|
||||
typeof(double),
|
||||
typeof(BoxedView),
|
||||
-1.0d,
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double CellValueTextFontSize
|
||||
{
|
||||
get { return (double)GetValue(CellValueTextFontSizeProperty); }
|
||||
set { SetValue(CellValueTextFontSizeProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty CellDescriptionColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CellDescriptionColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color CellDescriptionColor
|
||||
{
|
||||
get { return (Color)GetValue(CellDescriptionColorProperty); }
|
||||
set { SetValue(CellDescriptionColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty CellDescriptionFontSizeProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CellDescriptionFontSize),
|
||||
typeof(double),
|
||||
typeof(BoxedView),
|
||||
-1.0d,
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double CellDescriptionFontSize
|
||||
{
|
||||
get { return (double)GetValue(CellDescriptionFontSizeProperty); }
|
||||
set { SetValue(CellDescriptionFontSizeProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty CellBackgroundColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CellBackgroundColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color CellBackgroundColor
|
||||
{
|
||||
get { return (Color)GetValue(CellBackgroundColorProperty); }
|
||||
set { SetValue(CellBackgroundColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty CellAccentColorProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CellAccentColor),
|
||||
typeof(Color),
|
||||
typeof(BoxedView),
|
||||
Color.Accent,
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public Color CellAccentColor
|
||||
{
|
||||
get { return (Color)GetValue(CellAccentColorProperty); }
|
||||
set { SetValue(CellAccentColorProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty ShowSectionTopBottomBorderProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(ShowSectionTopBottomBorder),
|
||||
typeof(bool),
|
||||
typeof(BoxedView),
|
||||
true,
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public bool ShowSectionTopBottomBorder
|
||||
{
|
||||
get { return (bool)GetValue(ShowSectionTopBottomBorderProperty); }
|
||||
set { SetValue(ShowSectionTopBottomBorderProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty ScrollToBottomProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(ScrollToBottom),
|
||||
typeof(bool),
|
||||
typeof(BoxedView),
|
||||
default(bool),
|
||||
defaultBindingMode: BindingMode.TwoWay
|
||||
);
|
||||
|
||||
public bool ScrollToBottom
|
||||
{
|
||||
get { return (bool)GetValue(ScrollToBottomProperty); }
|
||||
set { SetValue(ScrollToBottomProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty ScrollToTopProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(ScrollToTop),
|
||||
typeof(bool),
|
||||
typeof(BoxedView),
|
||||
default(bool),
|
||||
defaultBindingMode: BindingMode.TwoWay
|
||||
);
|
||||
|
||||
public bool ScrollToTop
|
||||
{
|
||||
get { return (bool)GetValue(ScrollToTopProperty); }
|
||||
set { SetValue(ScrollToTopProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty VisibleContentHeightProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(VisibleContentHeight),
|
||||
typeof(double),
|
||||
typeof(BoxedView),
|
||||
-1d,
|
||||
defaultBindingMode: BindingMode.OneWayToSource
|
||||
);
|
||||
|
||||
public double VisibleContentHeight
|
||||
{
|
||||
get { return (double)GetValue(VisibleContentHeightProperty); }
|
||||
set { SetValue(VisibleContentHeightProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty ItemsSourceProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(ItemsSource),
|
||||
typeof(IEnumerable),
|
||||
typeof(BoxedView),
|
||||
default(IEnumerable),
|
||||
defaultBindingMode: BindingMode.OneWay,
|
||||
propertyChanged: ItemsChanged
|
||||
);
|
||||
|
||||
public IEnumerable ItemsSource
|
||||
{
|
||||
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
|
||||
set { SetValue(ItemsSourceProperty, value); }
|
||||
}
|
||||
|
||||
public static BindableProperty ItemTemplateProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(ItemTemplate),
|
||||
typeof(DataTemplate),
|
||||
typeof(BoxedView),
|
||||
default(DataTemplate),
|
||||
defaultBindingMode: BindingMode.OneWay
|
||||
);
|
||||
|
||||
public DataTemplate ItemTemplate
|
||||
{
|
||||
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
|
||||
set { SetValue(ItemTemplateProperty, value); }
|
||||
}
|
||||
|
||||
private static void ItemsChanged(BindableObject bindable, object oldValue, object newValue)
|
||||
{
|
||||
var boxedView = bindable as BoxedView;
|
||||
if(boxedView.ItemTemplate == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(oldValue is INotifyCollectionChanged oldObservableCollection)
|
||||
{
|
||||
oldObservableCollection.CollectionChanged -= boxedView.OnItemsSourceCollectionChanged;
|
||||
}
|
||||
if(newValue is INotifyCollectionChanged newObservableCollection)
|
||||
{
|
||||
newObservableCollection.CollectionChanged += boxedView.OnItemsSourceCollectionChanged;
|
||||
}
|
||||
|
||||
boxedView.Root.Clear();
|
||||
|
||||
if(newValue is IList newValueAsEnumerable)
|
||||
{
|
||||
foreach(var item in newValueAsEnumerable)
|
||||
{
|
||||
var view = CreateChildViewFor(boxedView.ItemTemplate, item, boxedView);
|
||||
boxedView.Root.Add(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if(e.Action == NotifyCollectionChangedAction.Replace)
|
||||
{
|
||||
Root.RemoveAt(e.OldStartingIndex);
|
||||
var item = e.NewItems[e.NewStartingIndex];
|
||||
var view = CreateChildViewFor(ItemTemplate, item, this);
|
||||
Root.Insert(e.NewStartingIndex, view);
|
||||
}
|
||||
else if(e.Action == NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
if(e.NewItems != null)
|
||||
{
|
||||
for(var i = 0; i < e.NewItems.Count; ++i)
|
||||
{
|
||||
var item = e.NewItems[i];
|
||||
var view = CreateChildViewFor(ItemTemplate, item, this);
|
||||
Root.Insert(i + e.NewStartingIndex, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(e.Action == NotifyCollectionChangedAction.Remove)
|
||||
{
|
||||
if(e.OldItems != null)
|
||||
{
|
||||
Root.RemoveAt(e.OldStartingIndex);
|
||||
}
|
||||
}
|
||||
else if(e.Action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
Root.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static BoxedSection CreateChildViewFor(DataTemplate template, object item, BindableObject container)
|
||||
{
|
||||
if(template is DataTemplateSelector selector)
|
||||
{
|
||||
template = selector.SelectTemplate(item, container);
|
||||
}
|
||||
template.SetValue(BindingContextProperty, item);
|
||||
return template.CreateContent() as BoxedSection;
|
||||
}
|
||||
}
|
||||
}
|
87
src/App/Controls/BoxedView/Cells/BaseCell.cs
Normal file
87
src/App/Controls/BoxedView/Cells/BaseCell.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls.BoxedView
|
||||
{
|
||||
public class BaseCell : Cell
|
||||
{
|
||||
public new event EventHandler Tapped;
|
||||
|
||||
internal new void OnTapped()
|
||||
{
|
||||
Tapped?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public static BindableProperty TitleProperty = BindableProperty.Create(
|
||||
nameof(Title), typeof(string), typeof(BaseCell), default(string), defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty TitleColorProperty = BindableProperty.Create(
|
||||
nameof(TitleColor), typeof(Color), typeof(BaseCell), default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty TitleFontSizeProperty = BindableProperty.Create(
|
||||
nameof(TitleFontSize), typeof(double), typeof(BaseCell), -1.0, defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty DescriptionProperty = BindableProperty.Create(
|
||||
nameof(Description), typeof(string), typeof(BaseCell), default(string),
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty DescriptionColorProperty = BindableProperty.Create(
|
||||
nameof(DescriptionColor), typeof(Color), typeof(BaseCell), default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty DescriptionFontSizeProperty = BindableProperty.Create(
|
||||
nameof(DescriptionFontSize), typeof(double), typeof(BaseCell), -1.0d,
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty BackgroundColorProperty = BindableProperty.Create(
|
||||
nameof(BackgroundColor), typeof(Color), typeof(BaseCell), default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public string Title
|
||||
{
|
||||
get => (string)GetValue(TitleProperty);
|
||||
set => SetValue(TitleProperty, value);
|
||||
}
|
||||
|
||||
public Color TitleColor
|
||||
{
|
||||
get => (Color)GetValue(TitleColorProperty);
|
||||
set => SetValue(TitleColorProperty, value);
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double TitleFontSize
|
||||
{
|
||||
get => (double)GetValue(TitleFontSizeProperty);
|
||||
set => SetValue(TitleFontSizeProperty, value);
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get => (string)GetValue(DescriptionProperty);
|
||||
set => SetValue(DescriptionProperty, value);
|
||||
}
|
||||
|
||||
public Color DescriptionColor
|
||||
{
|
||||
get => (Color)GetValue(DescriptionColorProperty);
|
||||
set => SetValue(DescriptionColorProperty, value);
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double DescriptionFontSize
|
||||
{
|
||||
get => (double)GetValue(DescriptionFontSizeProperty);
|
||||
set => SetValue(DescriptionFontSizeProperty, value);
|
||||
}
|
||||
|
||||
public Color BackgroundColor
|
||||
{
|
||||
get => (Color)GetValue(BackgroundColorProperty);
|
||||
set => SetValue(BackgroundColorProperty, value);
|
||||
}
|
||||
|
||||
public BoxedSection Section { get; set; }
|
||||
}
|
||||
}
|
38
src/App/Controls/BoxedView/Cells/LabelCell.cs
Normal file
38
src/App/Controls/BoxedView/Cells/LabelCell.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls.BoxedView
|
||||
{
|
||||
public class LabelCell : BaseCell
|
||||
{
|
||||
public static BindableProperty ValueTextProperty = BindableProperty.Create(
|
||||
nameof(ValueText), typeof(string), typeof(LabelCell), default(string),
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty ValueTextColorProperty = BindableProperty.Create(
|
||||
nameof(ValueTextColor), typeof(Color), typeof(LabelCell), default(Color),
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public static BindableProperty ValueTextFontSizeProperty = BindableProperty.Create(
|
||||
nameof(ValueTextFontSize), typeof(double), typeof(LabelCell), -1.0d,
|
||||
defaultBindingMode: BindingMode.OneWay);
|
||||
|
||||
public string ValueText
|
||||
{
|
||||
get => (string)GetValue(ValueTextProperty);
|
||||
set => SetValue(ValueTextProperty, value);
|
||||
}
|
||||
|
||||
public Color ValueTextColor
|
||||
{
|
||||
get => (Color)GetValue(ValueTextColorProperty);
|
||||
set => SetValue(ValueTextColorProperty, value);
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double ValueTextFontSize
|
||||
{
|
||||
get => (double)GetValue(ValueTextFontSizeProperty);
|
||||
set => SetValue(ValueTextFontSizeProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Bit.Core.Utilities;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
|
@ -11,5 +12,7 @@ namespace Bit.App.Pages
|
|||
get => _pageTitle;
|
||||
set => SetProperty(ref _pageTitle, value);
|
||||
}
|
||||
|
||||
public ContentPage Page { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,21 +4,17 @@
|
|||
x:Class="Bit.App.Pages.SettingsPage"
|
||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||
xmlns:bv="clr-namespace:Bit.App.Controls.BoxedView"
|
||||
x:DataType="pages:SettingsPageViewModel"
|
||||
Title="{Binding PageTitle}">
|
||||
<ContentPage.BindingContext>
|
||||
<pages:SettingsPageViewModel />
|
||||
</ContentPage.BindingContext>
|
||||
|
||||
<StackLayout>
|
||||
<!-- Place new controls here -->
|
||||
<Label Text="Settings!"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="CenterAndExpand" />
|
||||
<controls:FaLabel Text=""
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="CenterAndExpand">
|
||||
</controls:FaLabel>
|
||||
</StackLayout>
|
||||
<bv:BoxedView>
|
||||
<bv:BoxedSection Title="The Title" FooterText="The Footer">
|
||||
<bv:LabelCell Title="The title" ValueText="The value" />
|
||||
</bv:BoxedSection>
|
||||
</bv:BoxedView>
|
||||
|
||||
</ContentPage>
|
||||
|
|
Loading…
Reference in a new issue