mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-25 12:05:59 +01:00
Forms update with CollectionView conversion (#1374)
* Forms update with CollectionView conversion * updates * removed unnecessary import
This commit is contained in:
parent
29979f6b04
commit
1d4e742d66
@ -77,19 +77,19 @@
|
||||
<PackageReference Include="Portable.BouncyCastle">
|
||||
<Version>1.8.10</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.3-beta01" />
|
||||
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.6" />
|
||||
<PackageReference Include="Xamarin.Essentials">
|
||||
<Version>1.5.3.2</Version>
|
||||
<Version>1.6.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Firebase.Messaging">
|
||||
<Version>121.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.0.0" />
|
||||
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.1.0" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V4" Version="1.0.0" />
|
||||
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0" />
|
||||
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.1.0" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Migration" Version="1.0.6" />
|
||||
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.3.0.1" />
|
||||
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.2.0.7" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V4" Version="1.0.0.7" />
|
||||
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0.8" />
|
||||
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.2.2.1" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Migration" Version="1.0.8" />
|
||||
<PackageReference Include="Xamarin.Google.Dagger" Version="2.27.0" />
|
||||
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
|
||||
<Version>117.0.0</Version>
|
||||
@ -120,18 +120,17 @@
|
||||
<Compile Include="Receivers\EventUploadReceiver.cs" />
|
||||
<Compile Include="Receivers\LockAlarmReceiver.cs" />
|
||||
<Compile Include="Receivers\PackageReplacedReceiver.cs" />
|
||||
<Compile Include="Renderers\CipherViewCellRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedGridRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedDatePickerRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomTabbedRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedStackLayoutRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedTimePickerRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedSliderRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomEditorRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomPickerRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomEntryRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomSearchBarRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedListViewRenderer.cs" />
|
||||
<Compile Include="Renderers\HybridWebViewRenderer.cs" />
|
||||
<Compile Include="Renderers\SendViewCellRenderer.cs" />
|
||||
<Compile Include="Services\AndroidPushNotificationService.cs" />
|
||||
<Compile Include="Services\AndroidLogService.cs" />
|
||||
<Compile Include="MainApplication.cs" />
|
||||
@ -173,6 +172,9 @@
|
||||
<AndroidResource Include="Resources\drawable\ic_launcher_foreground.xml" />
|
||||
<AndroidResource Include="Resources\drawable\id.xml" />
|
||||
<AndroidResource Include="Resources\drawable\info.xml" />
|
||||
<AndroidResource Include="Resources\drawable\list_item_bg.xml" />
|
||||
<AndroidResource Include="Resources\drawable\list_item_bg_dark.xml" />
|
||||
<AndroidResource Include="Resources\drawable\list_item_bg_nord.xml" />
|
||||
<AndroidResource Include="Resources\drawable\lock.xml" />
|
||||
<AndroidResource Include="Resources\drawable\login.xml" />
|
||||
<AndroidResource Include="Resources\drawable\logo.xml" />
|
||||
@ -185,7 +187,6 @@
|
||||
<AndroidResource Include="Resources\drawable\shield.xml" />
|
||||
<AndroidResource Include="Resources\drawable-v23\splash_screen.xml" />
|
||||
<AndroidResource Include="Resources\drawable-v23\splash_screen_dark.xml" />
|
||||
<AndroidResource Include="Resources\layout\SendViewCell.axml" />
|
||||
<AndroidResource Include="Resources\layout\Tabbar.axml" />
|
||||
<AndroidResource Include="Resources\layout\Toolbar.axml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />
|
||||
@ -262,12 +263,6 @@
|
||||
<SubType>Designer</SubType>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\CipherViewCell.axml">
|
||||
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\xml\app_restrictions.xml">
|
||||
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
|
||||
|
@ -1,242 +0,0 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Runtime;
|
||||
using Android.Util;
|
||||
using Android.Views;
|
||||
using Android.Views.InputMethods;
|
||||
using Android.Widget;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Droid.Renderers;
|
||||
using FFImageLoading;
|
||||
using FFImageLoading.Views;
|
||||
using FFImageLoading.Work;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(CipherViewCell), typeof(CipherViewCellRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class CipherViewCellRenderer : ViewCellRenderer
|
||||
{
|
||||
private static Typeface _faTypeface;
|
||||
private static Typeface _miTypeface;
|
||||
private static Android.Graphics.Color _textColor;
|
||||
private static Android.Graphics.Color _mutedColor;
|
||||
private static Android.Graphics.Color _disabledIconColor;
|
||||
private static bool _usingLightTheme;
|
||||
|
||||
private AndroidCipherCell _cell;
|
||||
|
||||
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView,
|
||||
ViewGroup parent, Context context)
|
||||
{
|
||||
// TODO expand beyond light/dark detection once we support custom theme switching without app restart
|
||||
var themeChanged = _usingLightTheme != ThemeManager.UsingLightTheme;
|
||||
if (_faTypeface == null)
|
||||
{
|
||||
_faTypeface = Typeface.CreateFromAsset(context.Assets, "FontAwesome.ttf");
|
||||
}
|
||||
if (_miTypeface == null)
|
||||
{
|
||||
_miTypeface = Typeface.CreateFromAsset(context.Assets, "MaterialIcons_Regular.ttf");
|
||||
}
|
||||
if (_textColor == default(Android.Graphics.Color) || themeChanged)
|
||||
{
|
||||
_textColor = ThemeManager.GetResourceColor("TextColor").ToAndroid();
|
||||
}
|
||||
if (_mutedColor == default(Android.Graphics.Color) || themeChanged)
|
||||
{
|
||||
_mutedColor = ThemeManager.GetResourceColor("MutedColor").ToAndroid();
|
||||
}
|
||||
if (_disabledIconColor == default(Android.Graphics.Color) || themeChanged)
|
||||
{
|
||||
_disabledIconColor = ThemeManager.GetResourceColor("DisabledIconColor").ToAndroid();
|
||||
}
|
||||
_usingLightTheme = ThemeManager.UsingLightTheme;
|
||||
|
||||
var cipherCell = item as CipherViewCell;
|
||||
_cell = convertView as AndroidCipherCell;
|
||||
if (_cell == null)
|
||||
{
|
||||
_cell = new AndroidCipherCell(context, cipherCell, _faTypeface, _miTypeface);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cell.CipherViewCell.PropertyChanged -= CellPropertyChanged;
|
||||
}
|
||||
cipherCell.PropertyChanged += CellPropertyChanged;
|
||||
_cell.UpdateCell(cipherCell);
|
||||
_cell.UpdateColors(_textColor, _mutedColor, _disabledIconColor);
|
||||
return _cell;
|
||||
}
|
||||
|
||||
public void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var cipherCell = sender as CipherViewCell;
|
||||
_cell.CipherViewCell = cipherCell;
|
||||
if (e.PropertyName == CipherViewCell.CipherProperty.PropertyName)
|
||||
{
|
||||
_cell.UpdateCell(cipherCell);
|
||||
}
|
||||
else if (e.PropertyName == CipherViewCell.WebsiteIconsEnabledProperty.PropertyName)
|
||||
{
|
||||
_cell.UpdateIconImage(cipherCell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AndroidCipherCell : LinearLayout, INativeElementView
|
||||
{
|
||||
private readonly Typeface _faTypeface;
|
||||
private readonly Typeface _miTypeface;
|
||||
|
||||
private IScheduledWork _currentTask;
|
||||
|
||||
public AndroidCipherCell(Context context, CipherViewCell cipherView, Typeface faTypeface, Typeface miTypeface)
|
||||
: base(context)
|
||||
{
|
||||
CipherViewCell = cipherView;
|
||||
_faTypeface = faTypeface;
|
||||
_miTypeface = miTypeface;
|
||||
|
||||
var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.CipherViewCell, null);
|
||||
IconImage = view.FindViewById<IconImageView>(Resource.Id.CipherCellIconImage);
|
||||
Icon = view.FindViewById<TextView>(Resource.Id.CipherCellIcon);
|
||||
Name = view.FindViewById<TextView>(Resource.Id.CipherCellName);
|
||||
SubTitle = view.FindViewById<TextView>(Resource.Id.CipherCellSubTitle);
|
||||
SharedIcon = view.FindViewById<TextView>(Resource.Id.CipherCellSharedIcon);
|
||||
AttachmentsIcon = view.FindViewById<TextView>(Resource.Id.CipherCellAttachmentsIcon);
|
||||
MoreButton = view.FindViewById<Android.Widget.Button>(Resource.Id.CipherCellButton);
|
||||
MoreButton.Click += MoreButton_Click;
|
||||
|
||||
Icon.Typeface = _faTypeface;
|
||||
SharedIcon.Typeface = _faTypeface;
|
||||
AttachmentsIcon.Typeface = _faTypeface;
|
||||
MoreButton.Typeface = _miTypeface;
|
||||
|
||||
var small = (float)Device.GetNamedSize(NamedSize.Small, typeof(Label));
|
||||
Icon.SetTextSize(ComplexUnitType.Pt, 10);
|
||||
Name.SetTextSize(ComplexUnitType.Sp, (float)Device.GetNamedSize(NamedSize.Medium, typeof(Label)));
|
||||
SubTitle.SetTextSize(ComplexUnitType.Sp, small);
|
||||
SharedIcon.SetTextSize(ComplexUnitType.Sp, small);
|
||||
AttachmentsIcon.SetTextSize(ComplexUnitType.Sp, small);
|
||||
MoreButton.SetTextSize(ComplexUnitType.Sp, 25);
|
||||
|
||||
AddView(view);
|
||||
}
|
||||
|
||||
public CipherViewCell CipherViewCell { get; set; }
|
||||
public Element Element => CipherViewCell;
|
||||
|
||||
public IconImageView IconImage { get; set; }
|
||||
public TextView Icon { get; set; }
|
||||
public TextView Name { get; set; }
|
||||
public TextView SubTitle { get; set; }
|
||||
public TextView SharedIcon { get; set; }
|
||||
public TextView AttachmentsIcon { get; set; }
|
||||
public Android.Widget.Button MoreButton { get; set; }
|
||||
|
||||
public void UpdateCell(CipherViewCell cipherCell)
|
||||
{
|
||||
UpdateIconImage(cipherCell);
|
||||
|
||||
var cipher = cipherCell.Cipher;
|
||||
Name.Text = cipher.Name;
|
||||
if (!string.IsNullOrWhiteSpace(cipher.SubTitle))
|
||||
{
|
||||
SubTitle.Text = cipher.SubTitle;
|
||||
SubTitle.Visibility = ViewStates.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
SubTitle.Visibility = ViewStates.Invisible;
|
||||
}
|
||||
SharedIcon.Visibility = cipher.Shared ? ViewStates.Visible : ViewStates.Gone;
|
||||
AttachmentsIcon.Visibility = cipher.HasAttachments ? ViewStates.Visible : ViewStates.Gone;
|
||||
}
|
||||
|
||||
public void UpdateIconImage(CipherViewCell cipherCell)
|
||||
{
|
||||
if (_currentTask != null && !_currentTask.IsCancelled && !_currentTask.IsCompleted)
|
||||
{
|
||||
_currentTask.Cancel();
|
||||
}
|
||||
|
||||
var cipher = cipherCell.Cipher;
|
||||
|
||||
var iconImage = cipherCell.GetIconImage(cipher);
|
||||
if (iconImage.Item2 != null)
|
||||
{
|
||||
IconImage.SetImageResource(Resource.Drawable.login);
|
||||
IconImage.Visibility = ViewStates.Visible;
|
||||
Icon.Visibility = ViewStates.Gone;
|
||||
_currentTask = ImageService.Instance.LoadUrl(iconImage.Item2).DownSample(64).Into(IconImage);
|
||||
IconImage.Key = iconImage.Item2;
|
||||
}
|
||||
else
|
||||
{
|
||||
IconImage.Visibility = ViewStates.Gone;
|
||||
Icon.Visibility = ViewStates.Visible;
|
||||
Icon.Text = iconImage.Item1;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateColors(Android.Graphics.Color textColor, Android.Graphics.Color mutedColor,
|
||||
Android.Graphics.Color iconDisabledColor)
|
||||
{
|
||||
Name.SetTextColor(textColor);
|
||||
SubTitle.SetTextColor(mutedColor);
|
||||
Icon.SetTextColor(mutedColor);
|
||||
SharedIcon.SetTextColor(mutedColor);
|
||||
AttachmentsIcon.SetTextColor(mutedColor);
|
||||
MoreButton.SetTextColor(iconDisabledColor);
|
||||
}
|
||||
|
||||
private void MoreButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (CipherViewCell.ButtonCommand?.CanExecute(CipherViewCell.Cipher) ?? false)
|
||||
{
|
||||
CipherViewCell.ButtonCommand.Execute(CipherViewCell.Cipher);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
MoreButton.Click -= MoreButton_Click;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
[Android.Runtime.Preserve(AllMembers = true)]
|
||||
[Register("bit.droid.renderers.IconImageView")]
|
||||
public class IconImageView : ImageViewAsync
|
||||
{
|
||||
public IconImageView(Context context) : base(context)
|
||||
{ }
|
||||
|
||||
public IconImageView(IntPtr javaReference, JniHandleOwnership transfer)
|
||||
: base(javaReference, transfer)
|
||||
{ }
|
||||
|
||||
public IconImageView(Context context, IAttributeSet attrs)
|
||||
: base(context, attrs)
|
||||
{ }
|
||||
|
||||
public string Key { get; set; }
|
||||
|
||||
protected override void JavaFinalize()
|
||||
{
|
||||
SetImageDrawable(null);
|
||||
SetImageBitmap(null);
|
||||
ImageService.Instance.InvalidateCacheEntryAsync(Key, FFImageLoading.Cache.CacheType.Memory);
|
||||
base.JavaFinalize();
|
||||
}
|
||||
}
|
||||
}
|
43
src/Android/Renderers/ExtendedGridRenderer.cs
Normal file
43
src/Android/Renderers/ExtendedGridRenderer.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Android.Content;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedGrid), typeof(ExtendedGridRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class ExtendedGridRenderer : ViewRenderer
|
||||
{
|
||||
private static int? _bgResId;
|
||||
|
||||
public ExtendedGridRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
||||
{
|
||||
base.OnElementChanged(elementChangedEvent);
|
||||
if (elementChangedEvent.NewElement != null)
|
||||
{
|
||||
SetBackgroundResource(GetBgResId());
|
||||
}
|
||||
}
|
||||
|
||||
private int GetBgResId()
|
||||
{
|
||||
if (_bgResId == null)
|
||||
{
|
||||
if (ThemeManager.GetTheme(true) == "nord")
|
||||
{
|
||||
_bgResId = Resource.Drawable.list_item_bg_nord;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bgResId ??= ThemeManager.UsingLightTheme ? Resource.Drawable.list_item_bg :
|
||||
Resource.Drawable.list_item_bg_dark;
|
||||
}
|
||||
}
|
||||
return _bgResId.Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
using Android.Content;
|
||||
using Android.Views;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedListView), typeof(ExtendedListViewRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class ExtendedListViewRenderer : ListViewRenderer
|
||||
{
|
||||
public ExtendedListViewRenderer(Context context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && e.NewElement != null && e.NewElement is ExtendedListView listView)
|
||||
{
|
||||
// Pad for FAB
|
||||
Control.SetPadding(0, 0, 0, 170);
|
||||
Control.SetClipToPadding(false);
|
||||
Control.ScrollBarStyle = ScrollbarStyles.OutsideOverlay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
src/Android/Renderers/ExtendedStackLayoutRenderer.cs
Normal file
43
src/Android/Renderers/ExtendedStackLayoutRenderer.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Android.Content;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Droid.Renderers;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedStackLayout), typeof(ExtendedStackLayoutRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class ExtendedStackLayoutRenderer : ViewRenderer
|
||||
{
|
||||
private static int? _bgResId;
|
||||
|
||||
public ExtendedStackLayoutRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
||||
{
|
||||
base.OnElementChanged(elementChangedEvent);
|
||||
if (elementChangedEvent.NewElement != null)
|
||||
{
|
||||
SetBackgroundResource(GetBgResId());
|
||||
}
|
||||
}
|
||||
|
||||
private int GetBgResId()
|
||||
{
|
||||
if (_bgResId == null)
|
||||
{
|
||||
if (ThemeManager.GetTheme(true) == "nord")
|
||||
{
|
||||
_bgResId = Resource.Drawable.list_item_bg_nord;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bgResId ??= ThemeManager.UsingLightTheme ? Resource.Drawable.list_item_bg :
|
||||
Resource.Drawable.list_item_bg_dark;
|
||||
}
|
||||
}
|
||||
return _bgResId.Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,210 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Util;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Droid.Renderers;
|
||||
using FFImageLoading.Work;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using Button = Android.Widget.Button;
|
||||
using Color = Android.Graphics.Color;
|
||||
using View = Android.Views.View;
|
||||
|
||||
[assembly: ExportRenderer(typeof(SendViewCell), typeof(SendViewCellRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class SendViewCellRenderer : ViewCellRenderer
|
||||
{
|
||||
private static Typeface _faTypeface;
|
||||
private static Typeface _miTypeface;
|
||||
private static Color _textColor;
|
||||
private static Color _mutedColor;
|
||||
private static Color _disabledIconColor;
|
||||
private static bool _usingLightTheme;
|
||||
|
||||
private AndroidSendCell _cell;
|
||||
|
||||
protected override View GetCellCore(Cell item, View convertView,
|
||||
ViewGroup parent, Context context)
|
||||
{
|
||||
// TODO expand beyond light/dark detection once we support custom theme switching without app restart
|
||||
var themeChanged = _usingLightTheme != ThemeManager.UsingLightTheme;
|
||||
if (_faTypeface == null)
|
||||
{
|
||||
_faTypeface = Typeface.CreateFromAsset(context.Assets, "FontAwesome.ttf");
|
||||
}
|
||||
if (_miTypeface == null)
|
||||
{
|
||||
_miTypeface = Typeface.CreateFromAsset(context.Assets, "MaterialIcons_Regular.ttf");
|
||||
}
|
||||
if (_textColor == default(Color) || themeChanged)
|
||||
{
|
||||
_textColor = ThemeManager.GetResourceColor("TextColor").ToAndroid();
|
||||
}
|
||||
if (_mutedColor == default(Color) || themeChanged)
|
||||
{
|
||||
_mutedColor = ThemeManager.GetResourceColor("MutedColor").ToAndroid();
|
||||
}
|
||||
if (_disabledIconColor == default(Color) || themeChanged)
|
||||
{
|
||||
_disabledIconColor = ThemeManager.GetResourceColor("DisabledIconColor").ToAndroid();
|
||||
}
|
||||
_usingLightTheme = ThemeManager.UsingLightTheme;
|
||||
|
||||
var sendCell = item as SendViewCell;
|
||||
_cell = convertView as AndroidSendCell;
|
||||
if (_cell == null)
|
||||
{
|
||||
_cell = new AndroidSendCell(context, sendCell, _faTypeface, _miTypeface);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cell.SendViewCell.PropertyChanged -= CellPropertyChanged;
|
||||
}
|
||||
sendCell.PropertyChanged += CellPropertyChanged;
|
||||
_cell.UpdateCell(sendCell);
|
||||
_cell.UpdateColors(_textColor, _mutedColor, _disabledIconColor);
|
||||
return _cell;
|
||||
}
|
||||
|
||||
public void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var sendCell = sender as SendViewCell;
|
||||
_cell.SendViewCell = sendCell;
|
||||
if (e.PropertyName == SendViewCell.SendProperty.PropertyName)
|
||||
{
|
||||
_cell.UpdateCell(sendCell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AndroidSendCell : LinearLayout, INativeElementView
|
||||
{
|
||||
private readonly Typeface _faTypeface;
|
||||
private readonly Typeface _miTypeface;
|
||||
|
||||
private IScheduledWork _currentTask;
|
||||
|
||||
public AndroidSendCell(Context context, SendViewCell sendView, Typeface faTypeface, Typeface miTypeface)
|
||||
: base(context)
|
||||
{
|
||||
SendViewCell = sendView;
|
||||
_faTypeface = faTypeface;
|
||||
_miTypeface = miTypeface;
|
||||
|
||||
var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.SendViewCell, null);
|
||||
Icon = view.FindViewById<TextView>(Resource.Id.SendCellIcon);
|
||||
Name = view.FindViewById<TextView>(Resource.Id.SendCellName);
|
||||
SubTitle = view.FindViewById<TextView>(Resource.Id.SendCellSubTitle);
|
||||
DisabledIcon = view.FindViewById<TextView>(Resource.Id.SendCellDisabledIcon);
|
||||
HasPasswordIcon = view.FindViewById<TextView>(Resource.Id.SendCellHasPasswordIcon);
|
||||
MaxAccessCountReachedIcon = view.FindViewById<TextView>(Resource.Id.SendCellMaxAccessCountReachedIcon);
|
||||
ExpiredIcon = view.FindViewById<TextView>(Resource.Id.SendCellExpiredIcon);
|
||||
PendingDeleteIcon = view.FindViewById<TextView>(Resource.Id.SendCellPendingDeleteIcon);
|
||||
MoreButton = view.FindViewById<Button>(Resource.Id.SendCellButton);
|
||||
MoreButton.Click += MoreButton_Click;
|
||||
|
||||
Icon.Typeface = _faTypeface;
|
||||
DisabledIcon.Typeface = _faTypeface;
|
||||
HasPasswordIcon.Typeface = _faTypeface;
|
||||
MaxAccessCountReachedIcon.Typeface = _faTypeface;
|
||||
ExpiredIcon.Typeface = _faTypeface;
|
||||
PendingDeleteIcon.Typeface = _faTypeface;
|
||||
MoreButton.Typeface = _miTypeface;
|
||||
|
||||
var small = (float)Device.GetNamedSize(NamedSize.Small, typeof(Label));
|
||||
Icon.SetTextSize(ComplexUnitType.Pt, 10);
|
||||
Name.SetTextSize(ComplexUnitType.Sp, (float)Device.GetNamedSize(NamedSize.Medium, typeof(Label)));
|
||||
SubTitle.SetTextSize(ComplexUnitType.Sp, small);
|
||||
DisabledIcon.SetTextSize(ComplexUnitType.Sp, small);
|
||||
HasPasswordIcon.SetTextSize(ComplexUnitType.Sp, small);
|
||||
MaxAccessCountReachedIcon.SetTextSize(ComplexUnitType.Sp, small);
|
||||
ExpiredIcon.SetTextSize(ComplexUnitType.Sp, small);
|
||||
PendingDeleteIcon.SetTextSize(ComplexUnitType.Sp, small);
|
||||
MoreButton.SetTextSize(ComplexUnitType.Sp, 25);
|
||||
|
||||
if (!SendViewCell.ShowOptions)
|
||||
{
|
||||
MoreButton.Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
AddView(view);
|
||||
}
|
||||
|
||||
public SendViewCell SendViewCell { get; set; }
|
||||
public Element Element => SendViewCell;
|
||||
|
||||
public TextView Icon { get; set; }
|
||||
public TextView Name { get; set; }
|
||||
public TextView SubTitle { get; set; }
|
||||
public TextView DisabledIcon { get; set; }
|
||||
public TextView HasPasswordIcon { get; set; }
|
||||
public TextView MaxAccessCountReachedIcon { get; set; }
|
||||
public TextView ExpiredIcon { get; set; }
|
||||
public TextView PendingDeleteIcon { get; set; }
|
||||
public Button MoreButton { get; set; }
|
||||
|
||||
public void UpdateCell(SendViewCell sendCell)
|
||||
{
|
||||
UpdateIconImage(sendCell);
|
||||
|
||||
var send = sendCell.Send;
|
||||
Name.Text = send.Name;
|
||||
SubTitle.Text = send.DisplayDate;
|
||||
DisabledIcon.Visibility = send.Disabled ? ViewStates.Visible : ViewStates.Gone;
|
||||
HasPasswordIcon.Visibility = send.HasPassword ? ViewStates.Visible : ViewStates.Gone;
|
||||
MaxAccessCountReachedIcon.Visibility = send.MaxAccessCountReached ? ViewStates.Visible : ViewStates.Gone;
|
||||
ExpiredIcon.Visibility = send.Expired ? ViewStates.Visible : ViewStates.Gone;
|
||||
PendingDeleteIcon.Visibility = send.PendingDelete ? ViewStates.Visible : ViewStates.Gone;
|
||||
}
|
||||
|
||||
public void UpdateIconImage(SendViewCell sendCell)
|
||||
{
|
||||
if (_currentTask != null && !_currentTask.IsCancelled && !_currentTask.IsCompleted)
|
||||
{
|
||||
_currentTask.Cancel();
|
||||
}
|
||||
|
||||
var send = sendCell.Send;
|
||||
var iconImage = sendCell.GetIconImage(send);
|
||||
Icon.Text = iconImage;
|
||||
}
|
||||
|
||||
public void UpdateColors(Color textColor, Color mutedColor,
|
||||
Color iconDisabledColor)
|
||||
{
|
||||
Name.SetTextColor(textColor);
|
||||
SubTitle.SetTextColor(mutedColor);
|
||||
Icon.SetTextColor(mutedColor);
|
||||
DisabledIcon.SetTextColor(mutedColor);
|
||||
HasPasswordIcon.SetTextColor(mutedColor);
|
||||
MaxAccessCountReachedIcon.SetTextColor(mutedColor);
|
||||
ExpiredIcon.SetTextColor(mutedColor);
|
||||
PendingDeleteIcon.SetTextColor(mutedColor);
|
||||
MoreButton.SetTextColor(iconDisabledColor);
|
||||
}
|
||||
|
||||
private void MoreButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (SendViewCell.ButtonCommand?.CanExecute(SendViewCell.Send) ?? false)
|
||||
{
|
||||
SendViewCell.ButtonCommand.Execute(SendViewCell.Send);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
MoreButton.Click -= MoreButton_Click;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
7
src/Android/Resources/drawable/list_item_bg.xml
Normal file
7
src/Android/Resources/drawable/list_item_bg.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/itemPressed">
|
||||
|
||||
<item
|
||||
android:id="@android:id/mask"
|
||||
android:drawable="@android:color/white" />
|
||||
</ripple>
|
7
src/Android/Resources/drawable/list_item_bg_dark.xml
Normal file
7
src/Android/Resources/drawable/list_item_bg_dark.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/dark_primary">
|
||||
|
||||
<item
|
||||
android:id="@android:id/mask"
|
||||
android:drawable="@android:color/white" />
|
||||
</ripple>
|
7
src/Android/Resources/drawable/list_item_bg_nord.xml
Normal file
7
src/Android/Resources/drawable/list_item_bg_nord.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/nord_primary">
|
||||
|
||||
<item
|
||||
android:id="@android:id/mask"
|
||||
android:drawable="@android:color/white" />
|
||||
</ripple>
|
@ -1,86 +0,0 @@
|
||||
<?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:gravity="center_vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="2.2dp">
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="39.8dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center">
|
||||
<bit.droid.renderers.IconImageView
|
||||
android:id="@+id/CipherCellIconImage"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center" />
|
||||
<TextView
|
||||
android:id="@+id/CipherCellIcon"
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="26dp"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:text="[X]" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/CipherCellContent"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="7.65dp">
|
||||
<LinearLayout
|
||||
android:id="@+id/CipherCellContentTop"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/CipherCellName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:text="Name" />
|
||||
<TextView
|
||||
android:id="@+id/CipherCellSharedIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="" />
|
||||
<TextView
|
||||
android:id="@+id/CipherCellAttachmentsIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/CipherCellSubTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:text="SubTitle" />
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:id="@+id/CipherCellButton"
|
||||
android:layout_width="37dp"
|
||||
android:layout_height="match_parent"
|
||||
android:text=""
|
||||
android:gravity="center"
|
||||
android:padding="0dp"
|
||||
android:background="@android:color/transparent" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
@ -1,104 +0,0 @@
|
||||
<?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:gravity="center_vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="2.2dp">
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="39.8dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center">
|
||||
<TextView
|
||||
android:id="@+id/SendCellIcon"
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="26dp"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:text="[X]" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/SendCellContent"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="7.65dp">
|
||||
<LinearLayout
|
||||
android:id="@+id/SendCellContentTop"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/SendCellName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:text="Name" />
|
||||
<TextView
|
||||
android:id="@+id/SendCellDisabledIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="" />
|
||||
<TextView
|
||||
android:id="@+id/SendCellHasPasswordIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="" />
|
||||
<TextView
|
||||
android:id="@+id/SendCellMaxAccessCountReachedIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="" />
|
||||
<TextView
|
||||
android:id="@+id/SendCellExpiredIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="" />
|
||||
<TextView
|
||||
android:id="@+id/SendCellPendingDeleteIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/SendCellSubTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:text="SubTitle" />
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:id="@+id/SendCellButton"
|
||||
android:layout_width="37dp"
|
||||
android:layout_height="match_parent"
|
||||
android:text=""
|
||||
android:gravity="center"
|
||||
android:padding="0dp"
|
||||
android:background="@android:color/transparent" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
@ -6,6 +6,7 @@
|
||||
<color name="primary">#175DDC</color>
|
||||
<color name="notificationBar">#1452BC</color>
|
||||
<color name="border">#dddddd</color>
|
||||
<color name="itemPressed">#bbbbbb</color>
|
||||
|
||||
<!-- Dark theme -->
|
||||
<color name="dark_primary">#52bdfb</color>
|
||||
|
@ -15,9 +15,9 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="4.2.0" />
|
||||
<PackageReference Include="Plugin.Fingerprint" Version="2.1.4" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.5.3.2" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
|
||||
<PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.4.11.982" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="4.5.0.725" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2012" />
|
||||
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
|
||||
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
|
||||
</ItemGroup>
|
||||
@ -411,4 +411,4 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -1,114 +1,111 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Bit.App.Controls.CipherViewCell"
|
||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||
xmlns:ff="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms">
|
||||
<controls:ExtendedGrid xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Bit.App.Controls.CipherViewCell"
|
||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||
xmlns:ff="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
|
||||
StyleClass="list-row, list-row-platform"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="0"
|
||||
x:DataType="controls:CipherViewCellViewModel">
|
||||
|
||||
<Grid
|
||||
x:Name="_grid"
|
||||
StyleClass="list-row, list-row-platform"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="0"
|
||||
x:DataType="controls:CipherViewCellViewModel">
|
||||
<Grid.Resources>
|
||||
<u:IconGlyphConverter x:Key="iconGlyphConverter"/>
|
||||
<u:IconImageConverter x:Key="iconImageConverter"/>
|
||||
<u:InverseBoolConverter x:Key="inverseBool" />
|
||||
</Grid.Resources>
|
||||
|
||||
<Grid.BindingContext>
|
||||
<controls:CipherViewCellViewModel />
|
||||
</Grid.BindingContext>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="40" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="60" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<controls:FaLabel
|
||||
Grid.Column="0"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform"
|
||||
IsVisible="{Binding ShowIconImage, Converter={StaticResource inverseBool}}"
|
||||
Text="{Binding Cipher, Converter={StaticResource iconGlyphConverter}}"
|
||||
AutomationProperties.IsInAccessibleTree="False" />
|
||||
|
||||
<ff:CachedImage
|
||||
Grid.Column="0"
|
||||
BitmapOptimizations="True"
|
||||
ErrorPlaceholder="login.png"
|
||||
LoadingPlaceholder="login.png"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
WidthRequest="22"
|
||||
HeightRequest="22"
|
||||
IsVisible="{Binding ShowIconImage}"
|
||||
Source="{Binding Cipher, Converter={StaticResource iconImageConverter}}"
|
||||
AutomationProperties.IsInAccessibleTree="False" />
|
||||
|
||||
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center" Padding="0, 7">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="40" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="60" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
Text="{Binding Cipher.Name}" />
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding Cipher.SubTitle}" />
|
||||
<controls:FaLabel
|
||||
x:Name="_icon"
|
||||
Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
HorizontalOptions="Center"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform"
|
||||
AutomationProperties.IsInAccessibleTree="False" />
|
||||
|
||||
<ff:CachedImage
|
||||
x:Name="_image"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
BitmapOptimizations="True"
|
||||
ErrorPlaceholder="login.png"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
WidthRequest="22"
|
||||
HeightRequest="22"
|
||||
IsVisible="False"
|
||||
AutomationProperties.IsInAccessibleTree="False" />
|
||||
|
||||
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
Text="{Binding Cipher.Name, Mode=OneWay}" />
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding Cipher.SubTitle, Mode=OneWay}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Cipher.Shared, Mode=OneWay}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Shared}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="2"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Cipher.HasAttachments, Mode=OneWay}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Attachments}" />
|
||||
</Grid>
|
||||
|
||||
<controls:MiButton
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Text=""
|
||||
StyleClass="list-row-button, list-row-button-platform, btn-disabled"
|
||||
Clicked="MoreButton_Clicked"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="EndAndExpand"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Cipher.Shared, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
|
||||
AutomationProperties.Name="{u:I18n Shared}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="2"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Cipher.HasAttachments, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Attachments}" />
|
||||
</Grid>
|
||||
|
||||
</ViewCell>
|
||||
<controls:MiButton
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Text=""
|
||||
StyleClass="list-row-button, list-row-button-platform, btn-disabled"
|
||||
Clicked="MoreButton_Clicked"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="EndAndExpand"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
|
||||
</controls:ExtendedGrid>
|
||||
|
@ -1,45 +1,26 @@
|
||||
using Bit.App.Pages;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using System;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public partial class CipherViewCell : ViewCell
|
||||
public partial class CipherViewCell : ExtendedGrid
|
||||
{
|
||||
public static readonly BindableProperty CipherProperty = BindableProperty.Create(
|
||||
nameof(Cipher), typeof(CipherView), typeof(CipherViewCell), default(CipherView), BindingMode.OneWay);
|
||||
|
||||
public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
|
||||
nameof(WebsiteIconsEnabled), typeof(bool), typeof(CipherViewCell), true, BindingMode.OneWay);
|
||||
nameof(WebsiteIconsEnabled), typeof(bool?), typeof(CipherViewCell));
|
||||
|
||||
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
|
||||
nameof(ButtonCommand), typeof(Command<CipherView>), typeof(CipherViewCell));
|
||||
|
||||
private readonly IEnvironmentService _environmentService;
|
||||
|
||||
private CipherViewCellViewModel _viewModel;
|
||||
private bool _usingNativeCell;
|
||||
|
||||
public CipherViewCell()
|
||||
{
|
||||
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
|
||||
if (Device.RuntimePlatform == Device.iOS)
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = _grid.BindingContext as CipherViewCellViewModel;
|
||||
}
|
||||
else
|
||||
{
|
||||
_usingNativeCell = true;
|
||||
}
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public bool WebsiteIconsEnabled
|
||||
public bool? WebsiteIconsEnabled
|
||||
{
|
||||
get => (bool)GetValue(WebsiteIconsEnabledProperty);
|
||||
set => SetValue(WebsiteIconsEnabledProperty, value);
|
||||
@ -60,130 +41,31 @@ namespace Bit.App.Controls
|
||||
protected override void OnPropertyChanged(string propertyName = null)
|
||||
{
|
||||
base.OnPropertyChanged(propertyName);
|
||||
if (_usingNativeCell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (propertyName == CipherProperty.PropertyName)
|
||||
{
|
||||
_viewModel.Cipher = Cipher;
|
||||
if (Cipher == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BindingContext = new CipherViewCellViewModel(Cipher, WebsiteIconsEnabled ?? false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBindingContextChanged()
|
||||
{
|
||||
base.OnBindingContextChanged();
|
||||
if (_usingNativeCell)
|
||||
else if (propertyName == WebsiteIconsEnabledProperty.PropertyName)
|
||||
{
|
||||
return;
|
||||
if (Cipher == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
((CipherViewCellViewModel)BindingContext).WebsiteIconsEnabled = WebsiteIconsEnabled ?? false;
|
||||
}
|
||||
|
||||
_image.Source = null;
|
||||
CipherView cipher = null;
|
||||
if (BindingContext is GroupingsPageListItem groupingsPageListItem)
|
||||
{
|
||||
cipher = groupingsPageListItem.Cipher;
|
||||
}
|
||||
else if (BindingContext is CipherView cv)
|
||||
{
|
||||
cipher = cv;
|
||||
}
|
||||
if (cipher != null)
|
||||
{
|
||||
var iconImage = GetIconImage(cipher);
|
||||
if (iconImage.Item2 != null)
|
||||
{
|
||||
_image.IsVisible = true;
|
||||
_icon.IsVisible = false;
|
||||
_image.Source = iconImage.Item2;
|
||||
_image.LoadingPlaceholder = "login.png";
|
||||
}
|
||||
else
|
||||
{
|
||||
_image.IsVisible = false;
|
||||
_icon.IsVisible = true;
|
||||
_icon.Text = iconImage.Item1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Tuple<string, string> GetIconImage(CipherView cipher)
|
||||
{
|
||||
string icon = null;
|
||||
string image = null;
|
||||
switch (cipher.Type)
|
||||
{
|
||||
case CipherType.Login:
|
||||
var loginIconImage = GetLoginIconImage(cipher);
|
||||
icon = loginIconImage.Item1;
|
||||
image = loginIconImage.Item2;
|
||||
break;
|
||||
case CipherType.SecureNote:
|
||||
icon = "";
|
||||
break;
|
||||
case CipherType.Card:
|
||||
icon = "";
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
icon = "";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new Tuple<string, string>(icon, image);
|
||||
}
|
||||
|
||||
private Tuple<string, string> GetLoginIconImage(CipherView cipher)
|
||||
{
|
||||
string icon = "";
|
||||
string image = null;
|
||||
if (cipher.Login.Uri != null)
|
||||
{
|
||||
var hostnameUri = cipher.Login.Uri;
|
||||
var isWebsite = false;
|
||||
|
||||
if (hostnameUri.StartsWith(Constants.AndroidAppProtocol))
|
||||
{
|
||||
icon = "";
|
||||
}
|
||||
else if (hostnameUri.StartsWith(Constants.iOSAppProtocol))
|
||||
{
|
||||
icon = "";
|
||||
}
|
||||
else if (WebsiteIconsEnabled && !hostnameUri.Contains("://") && hostnameUri.Contains("."))
|
||||
{
|
||||
hostnameUri = string.Concat("http://", hostnameUri);
|
||||
isWebsite = true;
|
||||
}
|
||||
else if (WebsiteIconsEnabled)
|
||||
{
|
||||
isWebsite = hostnameUri.StartsWith("http") && hostnameUri.Contains(".");
|
||||
}
|
||||
|
||||
if (WebsiteIconsEnabled && isWebsite)
|
||||
{
|
||||
var hostname = CoreHelpers.GetHostname(hostnameUri);
|
||||
var iconsUrl = _environmentService.IconsUrl;
|
||||
if (string.IsNullOrWhiteSpace(iconsUrl))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_environmentService.BaseUrl))
|
||||
{
|
||||
iconsUrl = string.Format("{0}/icons", _environmentService.BaseUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
iconsUrl = "https://icons.bitwarden.net";
|
||||
}
|
||||
}
|
||||
image = string.Format("{0}/{1}/icon.png", iconsUrl, hostname);
|
||||
}
|
||||
}
|
||||
return new Tuple<string, string>(icon, image);
|
||||
}
|
||||
|
||||
private void MoreButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
ButtonCommand?.Execute(Cipher);
|
||||
var cipher = ((sender as MiButton)?.BindingContext as CipherViewCellViewModel)?.Cipher;
|
||||
if (cipher != null)
|
||||
{
|
||||
ButtonCommand?.Execute(cipher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,30 @@ namespace Bit.App.Controls
|
||||
public class CipherViewCellViewModel : ExtendedViewModel
|
||||
{
|
||||
private CipherView _cipher;
|
||||
private bool _websiteIconsEnabled;
|
||||
|
||||
public CipherViewCellViewModel(CipherView cipherView, bool websiteIconsEnabled)
|
||||
{
|
||||
Cipher = cipherView;
|
||||
WebsiteIconsEnabled = websiteIconsEnabled;
|
||||
}
|
||||
|
||||
public CipherView Cipher
|
||||
{
|
||||
get => _cipher;
|
||||
set => SetProperty(ref _cipher, value);
|
||||
}
|
||||
|
||||
public bool WebsiteIconsEnabled
|
||||
{
|
||||
get => _websiteIconsEnabled;
|
||||
set => SetProperty(ref _websiteIconsEnabled, value);
|
||||
}
|
||||
|
||||
public bool ShowIconImage
|
||||
{
|
||||
get => WebsiteIconsEnabled && !string.IsNullOrWhiteSpace(Cipher.Login?.Uri) &&
|
||||
Cipher.Login.Uri.StartsWith("http");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
src/App/Controls/ExtendedCollectionView.cs
Normal file
8
src/App/Controls/ExtendedCollectionView.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class ExtendedCollectionView : CollectionView
|
||||
{
|
||||
}
|
||||
}
|
8
src/App/Controls/ExtendedGrid.cs
Normal file
8
src/App/Controls/ExtendedGrid.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class ExtendedGrid : Grid
|
||||
{
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class ExtendedListView : ListView
|
||||
{
|
||||
public ExtendedListView() { }
|
||||
|
||||
public ExtendedListView(ListViewCachingStrategy cachingStrategy)
|
||||
: base(cachingStrategy) { }
|
||||
}
|
||||
}
|
8
src/App/Controls/ExtendedStackLayout.cs
Normal file
8
src/App/Controls/ExtendedStackLayout.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class ExtendedStackLayout : StackLayout
|
||||
{
|
||||
}
|
||||
}
|
@ -1,137 +1,132 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Bit.App.Controls.SendViewCell"
|
||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||
xmlns:u="clr-namespace:Bit.App.Utilities">
|
||||
<controls:ExtendedGrid xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Bit.App.Controls.SendViewCell"
|
||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||
StyleClass="list-row, list-row-platform"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="0"
|
||||
x:DataType="controls:SendViewCellViewModel">
|
||||
|
||||
<Grid
|
||||
x:Name="_grid"
|
||||
StyleClass="list-row, list-row-platform"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="0"
|
||||
x:DataType="controls:SendViewCellViewModel">
|
||||
<Grid.Resources>
|
||||
<u:SendIconGlyphConverter x:Key="sendIconGlyphConverter"/>
|
||||
</Grid.Resources>
|
||||
|
||||
<Grid.BindingContext>
|
||||
<controls:SendViewCellViewModel />
|
||||
</Grid.BindingContext>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="40" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="60" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<controls:FaLabel
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform"
|
||||
Text="{Binding Send, Converter={StaticResource sendIconGlyphConverter}}"
|
||||
AutomationProperties.IsInAccessibleTree="False" />
|
||||
|
||||
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center" Padding="0, 7">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="40" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="60" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<controls:FaLabel
|
||||
x:Name="_icon"
|
||||
Grid.Row="0"
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform"
|
||||
AutomationProperties.IsInAccessibleTree="False" />
|
||||
|
||||
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
Text="{Binding Send.Name, Mode=OneWay}" />
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="6"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding Send.DisplayDate, Mode=OneWay}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.Disabled, Mode=OneWay}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Disabled}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="2"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.HasPassword, Mode=OneWay}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Password}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="3"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.MaxAccessCountReached, Mode=OneWay}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n MaxAccessCountReached}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="4"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.Expired, Mode=OneWay}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Expired}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="5"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.PendingDelete, Mode=OneWay}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n PendingDelete}" />
|
||||
</Grid>
|
||||
|
||||
<controls:MiButton
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Text=""
|
||||
IsVisible="{Binding ShowOptions, Mode=OneWay}"
|
||||
StyleClass="list-row-button, list-row-button-platform, btn-disabled"
|
||||
Clicked="MoreButton_Clicked"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="EndAndExpand"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
Text="{Binding Send.Name}" />
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="6"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding Send.DisplayDate}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.Disabled, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
|
||||
AutomationProperties.Name="{u:I18n Disabled}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="2"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.HasPassword, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Password}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="3"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.MaxAccessCountReached, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n MaxAccessCountReached}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="4"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.Expired, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Expired}" />
|
||||
<controls:FaLabel
|
||||
Grid.Column="5"
|
||||
Grid.Row="0"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-title-icon"
|
||||
Margin="5, 0, 0, 0"
|
||||
Text=""
|
||||
IsVisible="{Binding Send.PendingDelete, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n PendingDelete}" />
|
||||
</Grid>
|
||||
|
||||
</ViewCell>
|
||||
<controls:MiButton
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Text=""
|
||||
IsVisible="{Binding ShowOptions, Mode=OneWay}"
|
||||
StyleClass="list-row-button, list-row-button-platform, btn-disabled"
|
||||
Clicked="MoreButton_Clicked"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="EndAndExpand"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
|
||||
</controls:ExtendedGrid>
|
||||
|
@ -1,14 +1,10 @@
|
||||
using System;
|
||||
using Bit.App.Pages;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public partial class SendViewCell : ViewCell
|
||||
public partial class SendViewCell : ExtendedGrid
|
||||
{
|
||||
public static readonly BindableProperty SendProperty = BindableProperty.Create(
|
||||
nameof(Send), typeof(SendView), typeof(SendViewCell), default(SendView), BindingMode.OneWay);
|
||||
@ -17,25 +13,11 @@ namespace Bit.App.Controls
|
||||
nameof(ButtonCommand), typeof(Command<SendView>), typeof(SendViewCell));
|
||||
|
||||
public static readonly BindableProperty ShowOptionsProperty = BindableProperty.Create(
|
||||
nameof(ShowOptions), typeof(bool), typeof(SendViewCell));
|
||||
|
||||
private readonly IEnvironmentService _environmentService;
|
||||
|
||||
private SendViewCellViewModel _viewModel;
|
||||
private bool _usingNativeCell;
|
||||
nameof(ShowOptions), typeof(bool), typeof(SendViewCell), true, BindingMode.OneWay);
|
||||
|
||||
public SendViewCell()
|
||||
{
|
||||
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
|
||||
if (Device.RuntimePlatform == Device.iOS)
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = _grid.BindingContext as SendViewCellViewModel;
|
||||
}
|
||||
else
|
||||
{
|
||||
_usingNativeCell = true;
|
||||
}
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public SendView Send
|
||||
@ -52,72 +34,30 @@ namespace Bit.App.Controls
|
||||
|
||||
public bool ShowOptions
|
||||
{
|
||||
get => GetValue(ShowOptionsProperty) is bool && (bool)GetValue(ShowOptionsProperty);
|
||||
get => (bool)GetValue(ShowOptionsProperty);
|
||||
set => SetValue(ShowOptionsProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(string propertyName = null)
|
||||
{
|
||||
base.OnPropertyChanged(propertyName);
|
||||
if (_usingNativeCell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (propertyName == SendProperty.PropertyName)
|
||||
{
|
||||
_viewModel.Send = Send;
|
||||
if (Send == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BindingContext = new SendViewCellViewModel(Send, ShowOptions);
|
||||
}
|
||||
else if (propertyName == ShowOptionsProperty.PropertyName)
|
||||
{
|
||||
_viewModel.ShowOptions = ShowOptions;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBindingContextChanged()
|
||||
{
|
||||
base.OnBindingContextChanged();
|
||||
if (_usingNativeCell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendView send = null;
|
||||
if (BindingContext is SendGroupingsPageListItem sendGroupingsPageListItem)
|
||||
{
|
||||
send = sendGroupingsPageListItem.Send;
|
||||
}
|
||||
else if (BindingContext is SendView sv)
|
||||
{
|
||||
send = sv;
|
||||
}
|
||||
if (send != null)
|
||||
{
|
||||
var iconImage = GetIconImage(send);
|
||||
_icon.IsVisible = true;
|
||||
_icon.Text = iconImage;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetIconImage(SendView send)
|
||||
{
|
||||
string icon = null;
|
||||
switch (send.Type)
|
||||
{
|
||||
case SendType.Text:
|
||||
icon = "\uf0f6"; // fa-file-text-o
|
||||
break;
|
||||
case SendType.File:
|
||||
icon = "\uf016"; // fa-file-o
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
private void MoreButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
ButtonCommand?.Execute(Send);
|
||||
var send = ((sender as MiButton)?.BindingContext as SendViewCellViewModel)?.Send;
|
||||
if (send != null)
|
||||
{
|
||||
ButtonCommand?.Execute(send);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,12 @@ namespace Bit.App.Controls
|
||||
private SendView _send;
|
||||
private bool _showOptions;
|
||||
|
||||
public SendViewCellViewModel(SendView sendView, bool showOptions)
|
||||
{
|
||||
Send = sendView;
|
||||
ShowOptions = showOptions;
|
||||
}
|
||||
|
||||
public SendView Send
|
||||
{
|
||||
get => _send;
|
||||
|
@ -43,57 +43,53 @@
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="Center"></Label>
|
||||
<ListView x:Name="_listView"
|
||||
<controls:ExtendedCollectionView
|
||||
IsVisible="{Binding ShowNoData, Converter={StaticResource inverseBool}}"
|
||||
ItemsSource="{Binding History}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HasUnevenRows="true"
|
||||
CachingStrategy="RecycleElement"
|
||||
StyleClass="list, list-platform">
|
||||
<ListView.ItemTemplate>
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="domain:GeneratedPasswordHistory">
|
||||
<ViewCell>
|
||||
<Grid
|
||||
StyleClass="list-row, list-row-platform"
|
||||
Padding="10"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="10">
|
||||
<Grid
|
||||
StyleClass="list-row, list-row-platform"
|
||||
Padding="10"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="10">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<controls:MonoLabel LineBreakMode="CharacterWrap"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
TextType="Html"
|
||||
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
|
||||
<Label LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding Date, Mode=OneWay, Converter={StaticResource dateTime}}" />
|
||||
<controls:FaButton
|
||||
StyleClass="list-row-button, list-row-button-platform"
|
||||
Text=""
|
||||
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
|
||||
CommandParameter="{Binding .}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyPassword}" />
|
||||
</Grid>
|
||||
</ViewCell>
|
||||
<controls:MonoLabel LineBreakMode="CharacterWrap"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
TextType="Html"
|
||||
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
|
||||
<Label LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding Date, Mode=OneWay, Converter={StaticResource dateTime}}" />
|
||||
<controls:FaButton
|
||||
StyleClass="list-row-button, list-row-button-platform"
|
||||
Text=""
|
||||
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
|
||||
CommandParameter="{Binding .}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyPassword}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</CollectionView.ItemTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
</StackLayout>
|
||||
|
||||
</pages:BaseContentPage>
|
||||
|
@ -44,34 +44,32 @@
|
||||
<controls:SendViewCell
|
||||
Send="{Binding Send}"
|
||||
ButtonCommand="{Binding BindingContext.SendOptionsCommand, Source={x:Reference _page}}"
|
||||
ShowOptions="{Binding ShowOptions}" />
|
||||
ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="sendGroupTemplate"
|
||||
x:DataType="pages:SendGroupingsPageListItem">
|
||||
<ViewCell>
|
||||
<StackLayout Orientation="Horizontal"
|
||||
StyleClass="list-row, list-row-platform">
|
||||
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform">
|
||||
<controls:FaLabel.Effects>
|
||||
<effects:FixedSizeEffect />
|
||||
</controls:FaLabel.Effects>
|
||||
</controls:FaLabel>
|
||||
<Label Text="{Binding Name, Mode=OneWay}"
|
||||
LineBreakMode="TailTruncation"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
StyleClass="list-title" />
|
||||
<Label Text="{Binding ItemCount, Mode=OneWay}"
|
||||
HorizontalOptions="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
StyleClass="list-sub" />
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
||||
StyleClass="list-row, list-row-platform">
|
||||
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform">
|
||||
<controls:FaLabel.Effects>
|
||||
<effects:FixedSizeEffect />
|
||||
</controls:FaLabel.Effects>
|
||||
</controls:FaLabel>
|
||||
<Label Text="{Binding Name, Mode=OneWay}"
|
||||
LineBreakMode="TailTruncation"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
StyleClass="list-title" />
|
||||
<Label Text="{Binding ItemCount, Mode=OneWay}"
|
||||
HorizontalOptions="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
StyleClass="list-sub" />
|
||||
</controls:ExtendedStackLayout>
|
||||
</DataTemplate>
|
||||
|
||||
<pages:SendGroupingsPageListItemSelector x:Key="sendListItemDataTemplateSelector"
|
||||
@ -103,32 +101,25 @@
|
||||
Text="{Binding NoDataText}"
|
||||
HorizontalTextAlignment="Center" />
|
||||
<Button
|
||||
Text="{u:I18n AddAnItem}"
|
||||
Clicked="AddButton_Clicked"
|
||||
IsVisible="{Binding ShowAddSendButton}" />
|
||||
Text="{u:I18n AddASend}"
|
||||
Clicked="AddButton_Clicked" />
|
||||
</StackLayout>
|
||||
|
||||
<controls:ExtendedListView
|
||||
x:Name="_listView"
|
||||
<RefreshView
|
||||
IsVisible="{Binding ShowList}"
|
||||
ItemsSource="{Binding GroupedSends}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HasUnevenRows="True"
|
||||
RowHeight="-1"
|
||||
RefreshCommand="{Binding RefreshCommand}"
|
||||
IsPullToRefreshEnabled="True"
|
||||
IsRefreshing="{Binding Refreshing}"
|
||||
ItemTemplate="{StaticResource sendListItemDataTemplateSelector}"
|
||||
IsGroupingEnabled="True"
|
||||
ItemSelected="RowSelected"
|
||||
StyleClass="list, list-platform">
|
||||
<x:Arguments>
|
||||
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
|
||||
</x:Arguments>
|
||||
Command="{Binding RefreshCommand}">
|
||||
<controls:ExtendedCollectionView
|
||||
ItemsSource="{Binding GroupedSends}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
ItemTemplate="{StaticResource sendListItemDataTemplateSelector}"
|
||||
IsGrouped="True"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="RowSelected"
|
||||
StyleClass="list, list-platform">
|
||||
|
||||
<ListView.GroupHeaderTemplate>
|
||||
<DataTemplate x:DataType="pages:SendGroupingsPageListGroup">
|
||||
<ViewCell>
|
||||
<CollectionView.GroupHeaderTemplate>
|
||||
<DataTemplate x:DataType="pages:SendGroupingsPageListGroup">
|
||||
<StackLayout
|
||||
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
|
||||
StyleClass="list-row-header-container, list-row-header-container-platform">
|
||||
@ -146,10 +137,10 @@
|
||||
<BoxView
|
||||
StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
</DataTemplate>
|
||||
</ListView.GroupHeaderTemplate>
|
||||
</controls:ExtendedListView>
|
||||
</DataTemplate>
|
||||
</CollectionView.GroupHeaderTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
</RefreshView>
|
||||
</StackLayout>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
@ -20,14 +20,13 @@ namespace Bit.App.Pages
|
||||
private readonly string _pageName;
|
||||
|
||||
private AppOptions _appOptions;
|
||||
private PreviousPageInfo _previousPage;
|
||||
|
||||
public SendGroupingsPage(bool mainPage, SendType? type = null, string pageTitle = null,
|
||||
AppOptions appOptions = null, PreviousPageInfo previousPage = null)
|
||||
AppOptions appOptions = null)
|
||||
{
|
||||
_pageName = string.Concat(nameof(GroupingsPage), "_", DateTime.UtcNow.Ticks);
|
||||
_pageName = string.Concat(nameof(SendGroupingsPage), "_", DateTime.UtcNow.Ticks);
|
||||
InitializeComponent();
|
||||
ListView = _listView;
|
||||
SetActivityIndicator(_mainContent);
|
||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
||||
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
||||
@ -37,7 +36,6 @@ namespace Bit.App.Pages
|
||||
_vm.MainPage = mainPage;
|
||||
_vm.Type = type;
|
||||
_appOptions = appOptions;
|
||||
_previousPage = previousPage;
|
||||
if (pageTitle != null)
|
||||
{
|
||||
_vm.PageTitle = pageTitle;
|
||||
@ -46,7 +44,10 @@ namespace Bit.App.Pages
|
||||
if (Device.RuntimePlatform == Device.iOS)
|
||||
{
|
||||
_absLayout.Children.Remove(_fab);
|
||||
ToolbarItems.Add(_aboutIconItem);
|
||||
if (type == null)
|
||||
{
|
||||
ToolbarItems.Add(_aboutIconItem);
|
||||
}
|
||||
ToolbarItems.Add(_addItem);
|
||||
}
|
||||
else
|
||||
@ -57,8 +58,6 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
public ExtendedListView ListView { get; set; }
|
||||
|
||||
protected override async void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
@ -136,14 +135,14 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
((ListView)sender).SelectedItem = null;
|
||||
((ExtendedCollectionView)sender).SelectedItem = null;
|
||||
if (!DoOnce())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!(e.SelectedItem is SendGroupingsPageListItem item))
|
||||
if (!(e.CurrentSelection?.FirstOrDefault() is SendGroupingsPageListItem item))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ namespace Bit.App.Pages
|
||||
public SendGroupingsPageListGroup(string name, int count, bool doUpper = true, bool first = false)
|
||||
: this(new List<SendGroupingsPageListItem>(), name, count, doUpper, first) { }
|
||||
|
||||
public SendGroupingsPageListGroup(List<SendGroupingsPageListItem> groupItems, string name, int count,
|
||||
public SendGroupingsPageListGroup(List<SendGroupingsPageListItem> sendGroupItems, string name, int count,
|
||||
bool doUpper = true, bool first = false)
|
||||
{
|
||||
AddRange(groupItems);
|
||||
AddRange(sendGroupItems);
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
Name = "-";
|
||||
|
@ -23,7 +23,6 @@ namespace Bit.App.Pages
|
||||
private bool _doingLoad;
|
||||
private bool _loading;
|
||||
private bool _loaded;
|
||||
private bool _showAddSendButton;
|
||||
private bool _showNoData;
|
||||
private bool _showList;
|
||||
private bool _syncRefreshing;
|
||||
@ -91,11 +90,6 @@ namespace Bit.App.Pages
|
||||
get => _loaded;
|
||||
set => SetProperty(ref _loaded, value);
|
||||
}
|
||||
public bool ShowAddSendButton
|
||||
{
|
||||
get => _showAddSendButton;
|
||||
set => SetProperty(ref _showAddSendButton, value);
|
||||
}
|
||||
public bool ShowNoData
|
||||
{
|
||||
get => _showNoData;
|
||||
|
@ -60,23 +60,22 @@
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="Center" />
|
||||
<ListView x:Name="_listView"
|
||||
<controls:ExtendedCollectionView
|
||||
IsVisible="{Binding ShowList}"
|
||||
ItemsSource="{Binding Sends}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HasUnevenRows="true"
|
||||
CachingStrategy="RecycleElement"
|
||||
ItemSelected="RowSelected"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="RowSelected"
|
||||
StyleClass="list, list-platform">
|
||||
<ListView.ItemTemplate>
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:SendView">
|
||||
<controls:SendViewCell
|
||||
Send="{Binding .}"
|
||||
ButtonCommand="{Binding BindingContext.SendOptionsCommand, Source={x:Reference _page}}"
|
||||
ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}" />
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</CollectionView.ItemTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
</StackLayout>
|
||||
|
||||
</pages:BaseContentPage>
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Models.View;
|
||||
using Xamarin.Forms;
|
||||
@ -87,15 +88,15 @@ namespace Bit.App.Pages
|
||||
Navigation.PopModalAsync(false);
|
||||
}
|
||||
|
||||
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
((ListView)sender).SelectedItem = null;
|
||||
((ExtendedCollectionView)sender).SelectedItem = null;
|
||||
if (!DoOnce())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.SelectedItem is SendView send)
|
||||
if (e.CurrentSelection is SendView send)
|
||||
{
|
||||
await _vm.SelectSendAsync(send);
|
||||
}
|
||||
|
@ -32,27 +32,25 @@
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="Center"></Label>
|
||||
<ListView x:Name="_listView"
|
||||
<controls:ExtendedCollectionView
|
||||
IsVisible="{Binding ShowNoData, Converter={StaticResource inverseBool}}"
|
||||
ItemsSource="{Binding Folders}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
CachingStrategy="RecycleElement"
|
||||
ItemSelected="RowSelected"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="RowSelected"
|
||||
StyleClass="list, list-platform">
|
||||
<ListView.ItemTemplate>
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:FolderView">
|
||||
<ViewCell>
|
||||
<StackLayout
|
||||
StyleClass="list-row, list-row-platform"
|
||||
Padding="10">
|
||||
<Label LineBreakMode="TailTruncation"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
Text="{Binding Name, Mode=OneWay}" />
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
<controls:ExtendedStackLayout
|
||||
StyleClass="list-row, list-row-platform"
|
||||
Padding="10">
|
||||
<Label LineBreakMode="TailTruncation"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
Text="{Binding Name, Mode=OneWay}" />
|
||||
</controls:ExtendedStackLayout>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</CollectionView.ItemTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
</StackLayout>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
@ -1,5 +1,7 @@
|
||||
using Bit.Core.Models.View;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
@ -32,14 +34,14 @@ namespace Bit.App.Pages
|
||||
}, _mainContent);
|
||||
}
|
||||
|
||||
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
((ListView)sender).SelectedItem = null;
|
||||
((ExtendedCollectionView)sender).SelectedItem = null;
|
||||
if (!DoOnce())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!(e.SelectedItem is FolderView folder))
|
||||
if (!(e.CurrentSelection?.FirstOrDefault() is FolderView folder))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -19,23 +19,21 @@
|
||||
<DataTemplate
|
||||
x:Key="regularTemplate"
|
||||
x:DataType="pages:SettingsPageListItem">
|
||||
<ViewCell>
|
||||
<StackLayout Orientation="Horizontal"
|
||||
StyleClass="list-row, list-row-platform">
|
||||
<Label Text="{Binding Name, Mode=OneWay}"
|
||||
LineBreakMode="TailTruncation"
|
||||
HorizontalOptions="StartAndExpand"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
StyleClass="list-title"/>
|
||||
<Label Text="{Binding SubLabel, Mode=OneWay}"
|
||||
IsVisible="{Binding SubLabel, Converter={StaticResource stringHasValue}}"
|
||||
HorizontalOptions="End"
|
||||
HorizontalTextAlignment="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
TextColor="{Binding SubLabelColor}"
|
||||
StyleClass="list-sub" />
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
||||
StyleClass="list-row, list-row-platform">
|
||||
<Label Text="{Binding Name, Mode=OneWay}"
|
||||
LineBreakMode="TailTruncation"
|
||||
HorizontalOptions="StartAndExpand"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
StyleClass="list-title"/>
|
||||
<Label Text="{Binding SubLabel, Mode=OneWay}"
|
||||
IsVisible="{Binding SubLabel, Converter={StaticResource stringHasValue}}"
|
||||
HorizontalOptions="End"
|
||||
HorizontalTextAlignment="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
TextColor="{Binding SubLabelColor}"
|
||||
StyleClass="list-sub" />
|
||||
</controls:ExtendedStackLayout>
|
||||
</DataTemplate>
|
||||
|
||||
<pages:SettingsPageListItemSelector
|
||||
@ -44,35 +42,32 @@
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<ListView
|
||||
<controls:ExtendedCollectionView
|
||||
ItemsSource="{Binding GroupedItems}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HasUnevenRows="True"
|
||||
RowHeight="-1"
|
||||
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
|
||||
IsGroupingEnabled="True"
|
||||
ItemSelected="RowSelected"
|
||||
IsGrouped="True"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="RowSelected"
|
||||
StyleClass="list, list-platform">
|
||||
|
||||
<ListView.GroupHeaderTemplate>
|
||||
<CollectionView.GroupHeaderTemplate>
|
||||
<DataTemplate x:DataType="pages:SettingsPageListGroup">
|
||||
<ViewCell>
|
||||
<StackLayout
|
||||
Padding="0" Spacing="0" VerticalOptions="FillAndExpand"
|
||||
StyleClass="list-row-header-container, list-row-header-container-platform">
|
||||
<BoxView
|
||||
StyleClass="list-section-separator-top, list-section-separator-top-platform"
|
||||
IsVisible="{Binding First, Converter={StaticResource inverseBool}}" />
|
||||
<StackLayout StyleClass="list-row-header, list-row-header-platform">
|
||||
<Label
|
||||
Text="{Binding Name}"
|
||||
StyleClass="list-header, list-header-platform" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
|
||||
<StackLayout
|
||||
Padding="0" Spacing="0" VerticalOptions="FillAndExpand"
|
||||
StyleClass="list-row-header-container, list-row-header-container-platform">
|
||||
<BoxView
|
||||
StyleClass="list-section-separator-top, list-section-separator-top-platform"
|
||||
IsVisible="{Binding First, Converter={StaticResource inverseBool}}" />
|
||||
<StackLayout StyleClass="list-row-header, list-row-header-platform">
|
||||
<Label
|
||||
Text="{Binding Name}"
|
||||
StyleClass="list-header, list-header-platform" />
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
|
||||
</StackLayout>
|
||||
</DataTemplate>
|
||||
</ListView.GroupHeaderTemplate>
|
||||
</ListView>
|
||||
</CollectionView.GroupHeaderTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
|
||||
</pages:BaseContentPage>
|
||||
|
@ -1,7 +1,9 @@
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Utilities;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
@ -41,14 +43,14 @@ namespace Bit.App.Pages
|
||||
return base.OnBackButtonPressed();
|
||||
}
|
||||
|
||||
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
((ListView)sender).SelectedItem = null;
|
||||
((ExtendedCollectionView)sender).SelectedItem = null;
|
||||
if (!DoOnce())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!(e.SelectedItem is SettingsPageListItem item))
|
||||
if (!(e.CurrentSelection?.FirstOrDefault() is SettingsPageListItem item))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -47,40 +47,35 @@
|
||||
Clicked="AddButton_Clicked"></Button>
|
||||
</StackLayout>
|
||||
|
||||
<controls:ExtendedListView
|
||||
<controls:ExtendedCollectionView
|
||||
IsVisible="{Binding ShowList}"
|
||||
ItemsSource="{Binding GroupedItems}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HasUnevenRows="true"
|
||||
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
|
||||
IsGroupingEnabled="True"
|
||||
ItemSelected="RowSelected"
|
||||
IsGrouped="True"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="RowSelected"
|
||||
StyleClass="list, list-platform">
|
||||
<x:Arguments>
|
||||
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
|
||||
</x:Arguments>
|
||||
|
||||
<ListView.GroupHeaderTemplate>
|
||||
<CollectionView.GroupHeaderTemplate>
|
||||
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
|
||||
<ViewCell>
|
||||
<StackLayout
|
||||
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
|
||||
StyleClass="list-row-header-container, list-row-header-container-platform">
|
||||
<BoxView
|
||||
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
|
||||
<StackLayout StyleClass="list-row-header, list-row-header-platform">
|
||||
<Label
|
||||
Text="{Binding Name}"
|
||||
StyleClass="list-header, list-header-platform" />
|
||||
<Label
|
||||
Text="{Binding ItemCount}"
|
||||
StyleClass="list-header-sub" />
|
||||
</StackLayout>
|
||||
<StackLayout
|
||||
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
|
||||
StyleClass="list-row-header-container, list-row-header-container-platform">
|
||||
<BoxView
|
||||
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
|
||||
<StackLayout StyleClass="list-row-header, list-row-header-platform">
|
||||
<Label
|
||||
Text="{Binding Name}"
|
||||
StyleClass="list-header, list-header-platform" />
|
||||
<Label
|
||||
Text="{Binding ItemCount}"
|
||||
StyleClass="list-header-sub" />
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
</StackLayout>
|
||||
</DataTemplate>
|
||||
</ListView.GroupHeaderTemplate>
|
||||
</controls:ExtendedListView>
|
||||
</CollectionView.GroupHeaderTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
</StackLayout>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
@ -4,7 +4,9 @@ using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Utilities;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
@ -44,14 +46,14 @@ namespace Bit.App.Pages
|
||||
}, _mainContent);
|
||||
}
|
||||
|
||||
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
((ListView)sender).SelectedItem = null;
|
||||
((ExtendedCollectionView)sender).SelectedItem = null;
|
||||
if (!DoOnce())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (e.SelectedItem is GroupingsPageListItem item && item.Cipher != null)
|
||||
if (e.CurrentSelection?.FirstOrDefault() is GroupingsPageListItem item && item.Cipher != null)
|
||||
{
|
||||
await _vm.SelectCipherAsync(item.Cipher, item.FuzzyAutofill);
|
||||
}
|
||||
|
@ -60,15 +60,14 @@
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="Center" />
|
||||
<ListView x:Name="_listView"
|
||||
<controls:ExtendedCollectionView
|
||||
IsVisible="{Binding ShowList}"
|
||||
ItemsSource="{Binding Ciphers}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HasUnevenRows="true"
|
||||
CachingStrategy="RecycleElement"
|
||||
ItemSelected="RowSelected"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="RowSelected"
|
||||
StyleClass="list, list-platform">
|
||||
<ListView.ItemTemplate>
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:CipherView">
|
||||
<controls:CipherViewCell
|
||||
Cipher="{Binding .}"
|
||||
@ -76,8 +75,8 @@
|
||||
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}"
|
||||
/>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</CollectionView.ItemTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
</StackLayout>
|
||||
|
||||
</pages:BaseContentPage>
|
||||
|
@ -3,6 +3,7 @@ using Bit.App.Resources;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
using System;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
@ -119,15 +120,15 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
((ListView)sender).SelectedItem = null;
|
||||
((ExtendedCollectionView)sender).SelectedItem = null;
|
||||
if (!DoOnce())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.SelectedItem is CipherView cipher)
|
||||
if (e.CurrentSelection is CipherView cipher)
|
||||
{
|
||||
await _vm.SelectCipherAsync(cipher);
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<pages:BaseContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Bit.App.Pages.GroupingsPage"
|
||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||
xmlns:effects="clr-namespace:Bit.App.Effects"
|
||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||
x:DataType="pages:GroupingsPageViewModel"
|
||||
Title="{Binding PageTitle}"
|
||||
x:Name="_page">
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Bit.App.Pages.GroupingsPage"
|
||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||
xmlns:effects="clr-namespace:Bit.App.Effects"
|
||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||
x:DataType="pages:GroupingsPageViewModel"
|
||||
Title="{Binding PageTitle}"
|
||||
x:Name="_page">
|
||||
|
||||
<ContentPage.BindingContext>
|
||||
<pages:GroupingsPageViewModel />
|
||||
@ -45,29 +45,27 @@
|
||||
|
||||
<DataTemplate x:Key="groupTemplate"
|
||||
x:DataType="pages:GroupingsPageListItem">
|
||||
<ViewCell>
|
||||
<StackLayout Orientation="Horizontal"
|
||||
StyleClass="list-row, list-row-platform">
|
||||
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform">
|
||||
<controls:FaLabel.Effects>
|
||||
<effects:FixedSizeEffect />
|
||||
</controls:FaLabel.Effects>
|
||||
</controls:FaLabel>
|
||||
<Label Text="{Binding Name, Mode=OneWay}"
|
||||
LineBreakMode="TailTruncation"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
StyleClass="list-title"/>
|
||||
<Label Text="{Binding ItemCount, Mode=OneWay}"
|
||||
HorizontalOptions="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
StyleClass="list-sub"/>
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
||||
StyleClass="list-row, list-row-platform">
|
||||
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform">
|
||||
<controls:FaLabel.Effects>
|
||||
<effects:FixedSizeEffect />
|
||||
</controls:FaLabel.Effects>
|
||||
</controls:FaLabel>
|
||||
<Label Text="{Binding Name, Mode=OneWay}"
|
||||
LineBreakMode="TailTruncation"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
StyleClass="list-title"/>
|
||||
<Label Text="{Binding ItemCount, Mode=OneWay}"
|
||||
HorizontalOptions="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
StyleClass="list-sub"/>
|
||||
</controls:ExtendedStackLayout>
|
||||
</DataTemplate>
|
||||
|
||||
<pages:GroupingsPageListItemSelector x:Key="listItemDataTemplateSelector"
|
||||
@ -89,27 +87,21 @@
|
||||
IsVisible="{Binding ShowAddCipherButton}"></Button>
|
||||
</StackLayout>
|
||||
|
||||
<controls:ExtendedListView
|
||||
x:Name="_listView"
|
||||
<RefreshView
|
||||
IsVisible="{Binding ShowList}"
|
||||
ItemsSource="{Binding GroupedItems}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HasUnevenRows="True"
|
||||
RowHeight="-1"
|
||||
RefreshCommand="{Binding RefreshCommand}"
|
||||
IsPullToRefreshEnabled="True"
|
||||
IsRefreshing="{Binding Refreshing}"
|
||||
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
|
||||
IsGroupingEnabled="True"
|
||||
ItemSelected="RowSelected"
|
||||
StyleClass="list, list-platform">
|
||||
<x:Arguments>
|
||||
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
|
||||
</x:Arguments>
|
||||
Command="{Binding RefreshCommand}">
|
||||
<controls:ExtendedCollectionView
|
||||
ItemsSource="{Binding GroupedItems}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
|
||||
IsGrouped="True"
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="RowSelected"
|
||||
StyleClass="list, list-platform">
|
||||
|
||||
<ListView.GroupHeaderTemplate>
|
||||
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
|
||||
<ViewCell>
|
||||
<CollectionView.GroupHeaderTemplate>
|
||||
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
|
||||
<StackLayout
|
||||
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
|
||||
StyleClass="list-row-header-container, list-row-header-container-platform">
|
||||
@ -126,10 +118,10 @@
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
</DataTemplate>
|
||||
</ListView.GroupHeaderTemplate>
|
||||
</controls:ExtendedListView>
|
||||
</DataTemplate>
|
||||
</CollectionView.GroupHeaderTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
</RefreshView>
|
||||
</StackLayout>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Models;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core;
|
||||
@ -9,6 +8,7 @@ using Bit.Core.Utilities;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Controls;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
@ -33,7 +33,6 @@ namespace Bit.App.Pages
|
||||
{
|
||||
_pageName = string.Concat(nameof(GroupingsPage), "_", DateTime.UtcNow.Ticks);
|
||||
InitializeComponent();
|
||||
ListView = _listView;
|
||||
SetActivityIndicator(_mainContent);
|
||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
||||
@ -73,8 +72,6 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
public ExtendedListView ListView { get; set; }
|
||||
|
||||
protected async override void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
@ -197,14 +194,14 @@ namespace Bit.App.Pages
|
||||
_vm.DisableRefreshing();
|
||||
}
|
||||
|
||||
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
((ListView)sender).SelectedItem = null;
|
||||
((ExtendedCollectionView)sender).SelectedItem = null;
|
||||
if (!DoOnce())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!(e.SelectedItem is GroupingsPageListItem item))
|
||||
if (!(e.CurrentSelection?.FirstOrDefault() is GroupingsPageListItem item))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -75,30 +75,30 @@ namespace Bit.App.Pages
|
||||
}
|
||||
else if (Folder != null)
|
||||
{
|
||||
_icon = Folder.Id == null ? "" : "";
|
||||
_icon = Folder.Id == null ? "\uf115" : "\uf07c"; // fa-folder-open-o : fa-folder-open
|
||||
}
|
||||
else if (Collection != null)
|
||||
{
|
||||
_icon = "";
|
||||
_icon = "\uf1b2"; // fa-cube
|
||||
}
|
||||
else if (Type != null)
|
||||
{
|
||||
switch (Type.Value)
|
||||
{
|
||||
case CipherType.Login:
|
||||
_icon = "";
|
||||
_icon = "\uf0ac"; // fa-globe
|
||||
break;
|
||||
case CipherType.SecureNote:
|
||||
_icon = "";
|
||||
_icon = "\uf24a"; // fa-sticky-note-o
|
||||
break;
|
||||
case CipherType.Card:
|
||||
_icon = "";
|
||||
_icon = "\uf09d"; // fa-credit-card
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
_icon = "";
|
||||
_icon = "\uf2c3"; // fa-id-card-o
|
||||
break;
|
||||
default:
|
||||
_icon = "";
|
||||
_icon = "\uf0ac"; // fa-globe
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -34,57 +34,53 @@
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="Center"></Label>
|
||||
<ListView x:Name="_listView"
|
||||
<controls:ExtendedCollectionView
|
||||
IsVisible="{Binding ShowNoData, Converter={StaticResource inverseBool}}"
|
||||
ItemsSource="{Binding History}"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HasUnevenRows="true"
|
||||
CachingStrategy="RecycleElement"
|
||||
StyleClass="list, list-platform">
|
||||
<ListView.ItemTemplate>
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:PasswordHistoryView">
|
||||
<ViewCell>
|
||||
<Grid
|
||||
StyleClass="list-row, list-row-platform"
|
||||
Padding="10"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="10">
|
||||
<Grid
|
||||
StyleClass="list-row, list-row-platform"
|
||||
Padding="10"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="10">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<controls:MonoLabel LineBreakMode="CharacterWrap"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
TextType="Html"
|
||||
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
|
||||
<Label LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding LastUsedDate, Mode=OneWay, Converter={StaticResource dateTime}}" />
|
||||
<controls:FaButton
|
||||
StyleClass="list-row-button, list-row-button-platform"
|
||||
Text=""
|
||||
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
|
||||
CommandParameter="{Binding .}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyPassword}" />
|
||||
</Grid>
|
||||
</ViewCell>
|
||||
<controls:MonoLabel LineBreakMode="CharacterWrap"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
TextType="Html"
|
||||
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
|
||||
<Label LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding LastUsedDate, Mode=OneWay, Converter={StaticResource dateTime}}" />
|
||||
<controls:FaButton
|
||||
StyleClass="list-row-button, list-row-button-platform"
|
||||
Text=""
|
||||
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
|
||||
CommandParameter="{Binding .}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyPassword}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</CollectionView.ItemTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
</StackLayout>
|
||||
|
||||
</pages:BaseContentPage>
|
||||
|
8
src/App/Resources/AppResources.Designer.cs
generated
8
src/App/Resources/AppResources.Designer.cs
generated
@ -1,7 +1,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@ -10,7 +9,6 @@
|
||||
|
||||
namespace Bit.App.Resources {
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
@ -3371,6 +3369,12 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
public static string AddASend {
|
||||
get {
|
||||
return ResourceManager.GetString("AddASend", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string CopyLink {
|
||||
get {
|
||||
return ResourceManager.GetString("CopyLink", resourceCulture);
|
||||
|
@ -1904,6 +1904,10 @@
|
||||
<value>There are no Sends in your account.</value>
|
||||
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
|
||||
</data>
|
||||
<data name="AddASend" xml:space="preserve">
|
||||
<value>Add a Send</value>
|
||||
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
|
||||
</data>
|
||||
<data name="CopyLink" xml:space="preserve">
|
||||
<value>Copy Link</value>
|
||||
</data>
|
||||
|
@ -68,10 +68,10 @@
|
||||
|
||||
<!-- List -->
|
||||
|
||||
<Style TargetType="ListView"
|
||||
Class="list-platform"
|
||||
<Style TargetType="BoxView"
|
||||
Class="list-item-separator-bottom-platform"
|
||||
ApplyToDerivedTypes="True">
|
||||
<Setter Property="SeparatorColor"
|
||||
<Setter Property="BackgroundColor"
|
||||
Value="Transparent" />
|
||||
</Style>
|
||||
<Style TargetType="StackLayout"
|
||||
@ -105,9 +105,15 @@
|
||||
<Style TargetType="StackLayout"
|
||||
Class="list-row-platform">
|
||||
</Style>
|
||||
<Style TargetType="controls:ExtendedStackLayout"
|
||||
Class="list-row-platform">
|
||||
</Style>
|
||||
<Style TargetType="Grid"
|
||||
Class="list-row-platform">
|
||||
</Style>
|
||||
<Style TargetType="controls:ExtendedGrid"
|
||||
Class="list-row-platform">
|
||||
</Style>
|
||||
<Style TargetType="Label"
|
||||
Class="list-icon-platform"
|
||||
ApplyToDerivedTypes="True">
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:controls="clr-namespace:Bit.App.Controls;assembly=BitwardenApp"
|
||||
x:Class="Bit.App.Styles.Base">
|
||||
|
||||
<!-- General -->
|
||||
@ -124,7 +125,7 @@
|
||||
</Style>
|
||||
|
||||
<!-- List -->
|
||||
<Style TargetType="ListView"
|
||||
<Style TargetType="CollectionView"
|
||||
Class="list">
|
||||
</Style>
|
||||
<Style TargetType="StackLayout"
|
||||
@ -161,11 +162,21 @@
|
||||
<Setter Property="Padding"
|
||||
Value="10, 12" />
|
||||
</Style>
|
||||
<Style TargetType="controls:ExtendedStackLayout"
|
||||
Class="list-row">
|
||||
<Setter Property="Padding"
|
||||
Value="10, 12" />
|
||||
</Style>
|
||||
<Style TargetType="Grid"
|
||||
Class="list-row">
|
||||
<Setter Property="Padding"
|
||||
Value="2, 5, 0, 5" />
|
||||
</Style>
|
||||
<Style TargetType="controls:ExtendedGrid"
|
||||
Class="list-row">
|
||||
<Setter Property="Padding"
|
||||
Value="2, 5, 0, 5" />
|
||||
</Style>
|
||||
<Style TargetType="BoxView"
|
||||
Class="list-section-separator-top">
|
||||
<Setter Property="HeightRequest"
|
||||
@ -176,6 +187,11 @@
|
||||
<Setter Property="HeightRequest"
|
||||
Value="1" />
|
||||
</Style>
|
||||
<Style TargetType="BoxView"
|
||||
Class="list-item-separator-bottom">
|
||||
<Setter Property="HeightRequest"
|
||||
Value="1" />
|
||||
</Style>
|
||||
<Style TargetType="Label"
|
||||
Class="list-title">
|
||||
</Style>
|
||||
|
@ -51,11 +51,14 @@
|
||||
<Setter Property="BackgroundColor"
|
||||
Value="{StaticResource BackgroundColor}" />
|
||||
</Style>
|
||||
<Style TargetType="ListView"
|
||||
<Style TargetType="CollectionView"
|
||||
ApplyToDerivedTypes="True">
|
||||
<Setter Property="BackgroundColor"
|
||||
Value="{StaticResource BackgroundColor}" />
|
||||
<Setter Property="RefreshControlColor"
|
||||
</Style>
|
||||
<Style TargetType="RefreshView"
|
||||
ApplyToDerivedTypes="True">
|
||||
<Setter Property="RefreshColor"
|
||||
Value="{StaticResource PrimaryColor}" />
|
||||
</Style>
|
||||
<Style TargetType="ActivityIndicator"
|
||||
@ -93,10 +96,10 @@
|
||||
|
||||
<!-- List -->
|
||||
|
||||
<Style TargetType="ListView"
|
||||
Class="list-platform"
|
||||
<Style TargetType="BoxView"
|
||||
Class="list-item-separator-bottom-platform"
|
||||
ApplyToDerivedTypes="True">
|
||||
<Setter Property="SeparatorColor"
|
||||
<Setter Property="BackgroundColor"
|
||||
Value="{StaticResource ListItemBorderColor}" />
|
||||
</Style>
|
||||
<Style TargetType="StackLayout"
|
||||
@ -107,7 +110,7 @@
|
||||
<Style TargetType="StackLayout"
|
||||
Class="list-row-header-platform">
|
||||
<Setter Property="Padding"
|
||||
Value="10, 0, 10, 5" />
|
||||
Value="10, 22, 10, 5" />
|
||||
<Setter Property="VerticalOptions"
|
||||
Value="EndAndExpand" />
|
||||
</Style>
|
||||
@ -127,15 +130,19 @@
|
||||
Class="list-section-separator-bottom-platform">
|
||||
<Setter Property="Color"
|
||||
Value="{StaticResource ListSectionBorderBottomColor}" />
|
||||
<Setter Property="Margin"
|
||||
Value="0, 0, 0, -1" />
|
||||
</Style>
|
||||
<Style TargetType="StackLayout"
|
||||
Class="list-row-platform">
|
||||
</Style>
|
||||
<Style TargetType="controls:ExtendedStackLayout"
|
||||
Class="list-row-platform">
|
||||
</Style>
|
||||
<Style TargetType="Grid"
|
||||
Class="list-row-platform">
|
||||
</Style>
|
||||
<Style TargetType="controls:ExtendedGrid"
|
||||
Class="list-row-platform">
|
||||
</Style>
|
||||
<Style TargetType="Label"
|
||||
Class="list-icon-platform"
|
||||
ApplyToDerivedTypes="True">
|
||||
|
64
src/App/Utilities/IconGlyphConverter.cs
Normal file
64
src/App/Utilities/IconGlyphConverter.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.View;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Utilities
|
||||
{
|
||||
public class IconGlyphConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var cipher = value as CipherView;
|
||||
return GetIcon(cipher);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string GetIcon(CipherView cipher)
|
||||
{
|
||||
string icon = null;
|
||||
switch (cipher.Type)
|
||||
{
|
||||
case CipherType.Login:
|
||||
icon = GetLoginIconGlyph(cipher);
|
||||
break;
|
||||
case CipherType.SecureNote:
|
||||
icon = "\uf24a"; // fa-sticky-note-o
|
||||
break;
|
||||
case CipherType.Card:
|
||||
icon = "\uf09d"; // fa-credit-card
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
icon = "\uf2c3"; // fa-id-card-o
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
string GetLoginIconGlyph(CipherView cipher)
|
||||
{
|
||||
var icon = "\uf0ac"; // fa-globe
|
||||
if (cipher.Login.Uri != null)
|
||||
{
|
||||
var hostnameUri = cipher.Login.Uri;
|
||||
if (hostnameUri.StartsWith(Constants.AndroidAppProtocol))
|
||||
{
|
||||
icon = "\uf17b"; // fa-android
|
||||
}
|
||||
else if (hostnameUri.StartsWith(Constants.iOSAppProtocol))
|
||||
{
|
||||
icon = "\uf179"; // fa-apple
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
}
|
79
src/App/Utilities/IconImageConverter.cs
Normal file
79
src/App/Utilities/IconImageConverter.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Utilities
|
||||
{
|
||||
public class IconImageConverter : IValueConverter
|
||||
{
|
||||
private readonly IEnvironmentService _environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var cipher = value as CipherView;
|
||||
return GetIcon(cipher);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string GetIcon(CipherView cipher)
|
||||
{
|
||||
string icon = null;
|
||||
switch (cipher.Type)
|
||||
{
|
||||
case CipherType.Login:
|
||||
icon = GetLoginIconImage(cipher);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
string GetLoginIconImage(CipherView cipher)
|
||||
{
|
||||
string image = null;
|
||||
if (cipher.Login.Uri != null)
|
||||
{
|
||||
var hostnameUri = cipher.Login.Uri;
|
||||
var isWebsite = false;
|
||||
|
||||
if (!hostnameUri.Contains("://") && hostnameUri.Contains("."))
|
||||
{
|
||||
hostnameUri = string.Concat("http://", hostnameUri);
|
||||
isWebsite = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isWebsite = hostnameUri.StartsWith("http") && hostnameUri.Contains(".");
|
||||
}
|
||||
|
||||
if (isWebsite)
|
||||
{
|
||||
var hostname = CoreHelpers.GetHostname(hostnameUri);
|
||||
var iconsUrl = _environmentService.IconsUrl;
|
||||
if (string.IsNullOrWhiteSpace(iconsUrl))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_environmentService.BaseUrl))
|
||||
{
|
||||
iconsUrl = string.Format("{0}/icons", _environmentService.BaseUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
iconsUrl = "https://icons.bitwarden.net";
|
||||
}
|
||||
}
|
||||
image = string.Format("{0}/{1}/icon.png", iconsUrl, hostname);
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
36
src/App/Utilities/SendIconGlyphConverter.cs
Normal file
36
src/App/Utilities/SendIconGlyphConverter.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.View;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Utilities
|
||||
{
|
||||
public class SendIconGlyphConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var send = value as SendView;
|
||||
if (send == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string icon = null;
|
||||
switch (send.Type)
|
||||
{
|
||||
case SendType.Text:
|
||||
icon = "\uf0f6"; // fa-file-text-o
|
||||
break;
|
||||
case SendType.File:
|
||||
icon = "\uf016"; // fa-file-o
|
||||
break;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -66,10 +66,9 @@ namespace Bit.iOS.Core.Services
|
||||
{
|
||||
Duration = TimeSpan.FromSeconds(longDuration ? 5 : 3)
|
||||
};
|
||||
if (TabBarVisible())
|
||||
{
|
||||
_toast.BottomMargin = 55;
|
||||
}
|
||||
_toast.BottomMargin = 110;
|
||||
_toast.LeftMargin = 20;
|
||||
_toast.RightMargin = 20;
|
||||
_toast.Show();
|
||||
_toast.DismissCallback = () =>
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ namespace Bit.iOS.Core.Views
|
||||
bgColor = Color.FromHex("#4c566a").ToUIColor();
|
||||
}
|
||||
BackgroundColor = bgColor.ColorWithAlpha(0.9f);
|
||||
Layer.CornerRadius = 15;
|
||||
Layer.CornerRadius = 18;
|
||||
Layer.MasksToBounds = true;
|
||||
|
||||
MessageLabel = new UILabel
|
||||
|
@ -163,7 +163,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Xamarin.Essentials">
|
||||
<Version>1.5.3.2</Version>
|
||||
<Version>1.6.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
||||
|
Loading…
Reference in New Issue
Block a user