cipher view cell and groupings styles

This commit is contained in:
Kyle Spearrin 2019-04-22 17:08:37 -04:00
parent 6cd1171fd5
commit 913cd23c45
18 changed files with 256 additions and 35 deletions

View file

@ -58,7 +58,7 @@
<PackageReference Include="Xamarin.Essentials"> <PackageReference Include="Xamarin.Essentials">
<Version>1.1.0</Version> <Version>1.1.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms" Version="3.6.0.293080" /> <PackageReference Include="Xamarin.Forms" Version="3.6.0.344457" />
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" /> <PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.1" /> <PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" /> <PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />

View file

@ -39,6 +39,8 @@ namespace Bit.Droid
private void RegisterLocalServices() private void RegisterLocalServices()
{ {
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(true);
var preferencesStorage = new PreferencesStorageService(null); var preferencesStorage = new PreferencesStorageService(null);
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
var liteDbStorage = new LiteDbStorageService(Path.Combine(documentsPath, "bitwarden.db")); var liteDbStorage = new LiteDbStorageService(Path.Combine(documentsPath, "bitwarden.db"));

View file

@ -13,7 +13,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Xamarin.Essentials" Version="1.1.0" /> <PackageReference Include="Xamarin.Essentials" Version="1.1.0" />
<PackageReference Include="Xamarin.Forms" Version="3.6.0.293080" /> <PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.4.5.909-pre" />
<PackageReference Include="Xamarin.Forms" Version="3.6.0.344457" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -2,21 +2,82 @@
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" <ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.CipherViewCell" x:Class="Bit.App.Controls.CipherViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"> xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:ff="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms">
<ViewCell.View> <ViewCell.View>
<StackLayout x:Name="_layout" <Grid x:Name="_grid"
x:DataType="controls:CipherViewCellViewModel" StyleClass="list-row, list-row-platform"
StyleClass="list-row"> RowSpacing="0"
<StackLayout.BindingContext> ColumnSpacing="0"
x:DataType="controls:CipherViewCellViewModel">
<Grid.BindingContext>
<controls:CipherViewCellViewModel /> <controls:CipherViewCellViewModel />
</StackLayout.BindingContext> </Grid.BindingContext>
<Label Text="{Binding Cipher.Name, Mode=OneWay}" <Grid.RowDefinitions>
StyleClass="list-title" /> <RowDefinition Height="*" />
<Label Text="{Binding Cipher.SubTitle, Mode=OneWay}" <RowDefinition Height="*" />
StyleClass="list-subtitle" /> </Grid.RowDefinitions>
</StackLayout> <Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<controls:FaLabel x:Name="_icon"
HorizontalOptions="Center"
VerticalOptions="Center"
StyleClass="list-icon" />
<ff:CachedImage x:Name="_image"
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
BitmapOptimizations="True"
ErrorPlaceholder="login.png"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="20"
HeightRequest="20"
IsVisible="False"/>
<Label LineBreakMode="TailTruncation"
Grid.Column="1"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
Text="{Binding Cipher.Name, Mode=OneWay}" />
<Label LineBreakMode="TailTruncation"
Grid.Column="1"
Grid.Row="1"
Grid.ColumnSpan="3"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Cipher.SubTitle, Mode=OneWay}" />
<controls:FaLabel Grid.Column="2"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf1e0;"
IsVisible="{Binding Cipher.Shared, Mode=OneWay}" />
<controls:FaLabel Grid.Column="3"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf0c6;"
IsVisible="{Binding Cipher.HasAttachments, Mode=OneWay}" />
<Button WidthRequest="60"
Grid.Column="4"
Grid.Row="0"
Grid.RowSpan="2"
BackgroundColor="Transparent" />
</Grid>
</ViewCell.View> </ViewCell.View>
</ViewCell> </ViewCell>

View file

@ -1,4 +1,9 @@
using Bit.Core.Models.View; using Bit.App.Pages;
using Bit.Core;
using Bit.Core.Enums;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using System;
using Xamarin.Forms; using Xamarin.Forms;
namespace Bit.App.Controls namespace Bit.App.Controls
@ -13,7 +18,7 @@ namespace Bit.App.Controls
public CipherViewCell() public CipherViewCell()
{ {
InitializeComponent(); InitializeComponent();
_viewModel = _layout.BindingContext as CipherViewCellViewModel; _viewModel = _grid.BindingContext as CipherViewCellViewModel;
} }
public CipherView Cipher public CipherView Cipher
@ -30,5 +35,88 @@ namespace Bit.App.Controls
_viewModel.Cipher = Cipher; _viewModel.Cipher = Cipher;
} }
} }
protected override void OnBindingContextChanged()
{
string icon = null;
string image = null;
_image.Source = null;
if(BindingContext is GroupingsPageListItem groupingsPageListItem && groupingsPageListItem.Cipher != null)
{
switch(groupingsPageListItem.Cipher.Type)
{
case CipherType.Login:
var loginIconImage = GetLoginIconImage(groupingsPageListItem.Cipher);
icon = loginIconImage.Item1;
image = loginIconImage.Item2;
break;
case CipherType.SecureNote:
icon = "&#xf24a;";
break;
case CipherType.Card:
icon = "&#xf09d;";
break;
case CipherType.Identity:
icon = "&#xf2c3;";
break;
default:
break;
}
if(image != null)
{
_image.IsVisible = true;
_icon.IsVisible = false;
_image.Source = image;
_image.LoadingPlaceholder = "login.png";
}
else
{
_image.IsVisible = false;
_icon.IsVisible = true;
_icon.Text = icon;
}
}
base.OnBindingContextChanged();
}
private Tuple<string, string> GetLoginIconImage(CipherView cipher)
{
string icon = "&#xf0ac;";
string image = null;
var imageEnabled = true;
if(cipher.Login.Uri != null)
{
var hostnameUri = cipher.Login.Uri;
var isWebsite = false;
if(hostnameUri.StartsWith(Constants.AndroidAppProtocol))
{
icon = "&#xf17b;";
}
else if(hostnameUri.StartsWith(Constants.iOSAppProtocol))
{
icon = "&#xf179;";
}
else if(imageEnabled && !hostnameUri.Contains("://") && hostnameUri.Contains("."))
{
hostnameUri = string.Concat("http://", hostnameUri);
isWebsite = true;
}
else if(imageEnabled)
{
isWebsite = hostnameUri.StartsWith("http") && hostnameUri.Contains(".");
}
if(imageEnabled && isWebsite)
{
var hostname = CoreHelpers.GetHostname(hostnameUri);
var iconsUrl = "https://icons.bitwarden.net";
image = string.Format("{0}/{1}/icon.png", iconsUrl, hostname);
}
}
return new Tuple<string, string>(icon, image);
}
} }
} }

View file

@ -22,8 +22,8 @@
x:DataType="pages:GroupingsPageListItem"> x:DataType="pages:GroupingsPageListItem">
<ViewCell> <ViewCell>
<StackLayout Orientation="Horizontal" <StackLayout Orientation="Horizontal"
StyleClass="list-row"> StyleClass="list-row, list-row-platform">
<controls:FaLabel Text="&#xf07c;" <controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start" HorizontalOptions="Start"
VerticalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"
StyleClass="list-icon" /> StyleClass="list-icon" />
@ -40,8 +40,8 @@
x:DataType="pages:GroupingsPageListItem"> x:DataType="pages:GroupingsPageListItem">
<ViewCell> <ViewCell>
<StackLayout Orientation="Horizontal" <StackLayout Orientation="Horizontal"
StyleClass="list-row"> StyleClass="list-row, list-row-platform">
<controls:FaLabel Text="&#xf1b2;" <controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start" HorizontalOptions="Start"
VerticalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"
StyleClass="list-icon" /> StyleClass="list-icon" />
@ -72,13 +72,13 @@
CachingStrategy="RecycleElement" CachingStrategy="RecycleElement"
ItemTemplate="{StaticResource listItemDataTemplateSelector}" ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGroupingEnabled="True" IsGroupingEnabled="True"
StyleClass="list"> StyleClass="list, list-platform">
<ListView.GroupHeaderTemplate> <ListView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:GroupingsPageListGroup"> <DataTemplate x:DataType="pages:GroupingsPageListGroup">
<ViewCell> <ViewCell>
<StackLayout StyleClass="list-row-header"> <StackLayout StyleClass="list-row-header">
<Label Text="{Binding Name}" <Label Text="{Binding Name}"
StyleClass="list-header, list-header-themed, list-header-platform" /> StyleClass="list-header, list-header-platform" />
</StackLayout> </StackLayout>
</ViewCell> </ViewCell>
</DataTemplate> </DataTemplate>

View file

@ -4,8 +4,29 @@ namespace Bit.App.Pages
{ {
public class GroupingsPageListItem public class GroupingsPageListItem
{ {
private string _icon;
public FolderView Folder { get; set; } public FolderView Folder { get; set; }
public CollectionView Collection { get; set; } public CollectionView Collection { get; set; }
public CipherView Cipher { get; set; } public CipherView Cipher { get; set; }
public string Icon
{
get
{
if(_icon != null)
{
return _icon;
}
if(Folder != null)
{
_icon = Folder.Id == null ? "" : "";
}
else if(Collection != null)
{
_icon = "";
}
return _icon;
}
}
} }
} }

View file

@ -78,15 +78,18 @@ namespace Bit.App.Pages
var groupedItems = new List<GroupingsPageListGroup>(); var groupedItems = new List<GroupingsPageListGroup>();
if(favListItems?.Any() ?? false) if(favListItems?.Any() ?? false)
{ {
groupedItems.Add(new GroupingsPageListGroup(favListItems, AppResources.Favorites)); groupedItems.Add(new GroupingsPageListGroup(favListItems, AppResources.Favorites,
Device.RuntimePlatform == Device.iOS));
} }
if(folderListItems?.Any() ?? false) if(folderListItems?.Any() ?? false)
{ {
groupedItems.Add(new GroupingsPageListGroup(folderListItems, AppResources.Folders)); groupedItems.Add(new GroupingsPageListGroup(folderListItems, AppResources.Folders,
Device.RuntimePlatform == Device.iOS));
} }
if(collectionListItems?.Any() ?? false) if(collectionListItems?.Any() ?? false)
{ {
groupedItems.Add(new GroupingsPageListGroup(collectionListItems, AppResources.Collections)); groupedItems.Add(new GroupingsPageListGroup(collectionListItems, AppResources.Collections,
Device.RuntimePlatform == Device.iOS));
} }
GroupedItems.ResetWithRange(groupedItems); GroupedItems.ResetWithRange(groupedItems);
} }

View file

@ -2,9 +2,24 @@
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms" <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Styles.Android"> x:Class="Bit.App.Styles.Android">
<Style TargetType="ListView"
Class="list-platform">
<Setter Property="SeparatorColor"
Value="Transparent" />
</Style>
<Style TargetType="Label" <Style TargetType="Label"
Class="list-header-platform"> Class="list-header-platform">
<Setter Property="TextColor" <Setter Property="TextColor"
Value="{StaticResource ListHeaderTextColor}" /> Value="{StaticResource ListHeaderTextColor}" />
<Setter Property="FontSize"
Value="Small" />
<Setter Property="FontAttributes"
Value="Bold" />
</Style>
<Style TargetType="StackLayout"
Class="list-row-platform">
</Style>
<Style TargetType="Grid"
Class="list-row-platform">
</Style> </Style>
</ResourceDictionary> </ResourceDictionary>

View file

@ -2,40 +2,64 @@
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms" <ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Styles.Base"> x:Class="Bit.App.Styles.Base">
<!-- General -->
<Style TargetType="Label"
ApplyToDerivedTypes="True">
<Setter Property="FontSize"
Value="Medium" />
<Setter Property="TextColor"
Value="{StaticResource TextColor}" />
</Style>
<!-- List -->
<Style TargetType="ListView" <Style TargetType="ListView"
Class="list"> Class="list">
<Setter Property="SeparatorColor"
Value="Transparent" />
</Style> </Style>
<Style TargetType="StackLayout" <Style TargetType="StackLayout"
Class="list-row-header"> Class="list-row-header">
<Setter Property="Padding" <Setter Property="Padding"
Value="10" /> Value="10, 12" />
</Style> </Style>
<Style TargetType="Label" <Style TargetType="Label"
Class="list-header"> Class="list-header">
<Setter Property="FontSize"
Value="Medium" />
</Style> </Style>
<Style TargetType="StackLayout" <Style TargetType="StackLayout"
Class="list-row"> Class="list-row">
<Setter Property="Padding" <Setter Property="Padding"
Value="10" /> Value="12" />
</Style>
<Style TargetType="Grid"
Class="list-row">
<Setter Property="Padding"
Value="2, 5" />
</Style> </Style>
<Style TargetType="Label" <Style TargetType="Label"
Class="list-title"> Class="list-title">
</Style>
<Style TargetType="Label"
ApplyToDerivedTypes="True"
Class="list-title-icon">
<Setter Property="FontSize" <Setter Property="FontSize"
Value="Medium" /> Value="Small" />
<Setter Property="TextColor"
Value="{StaticResource MutedColor}" />
</Style> </Style>
<Style TargetType="Label" <Style TargetType="Label"
Class="list-subtitle"> Class="list-subtitle">
<Setter Property="FontSize" <Setter Property="FontSize"
Value="Small" /> Value="Small" />
<Setter Property="TextColor"
Value="{StaticResource MutedColor}" />
</Style> </Style>
<Style TargetType="Label" <Style TargetType="Label"
Class="list-icon" Class="list-icon"
ApplyToDerivedTypes="True"> ApplyToDerivedTypes="True">
<Setter Property="Margin"
Value="3, 3, 3, 0" />
<Setter Property="FontSize" <Setter Property="FontSize"
Value="Medium" /> Value="Medium" />
<Setter Property="TextColor"
Value="{StaticResource MutedColor}" />
</Style> </Style>
</ResourceDictionary> </ResourceDictionary>

View file

@ -8,4 +8,5 @@
<Color x:Key="SuccessColor">#00a65a</Color> <Color x:Key="SuccessColor">#00a65a</Color>
<Color x:Key="InfoColor">#555555</Color> <Color x:Key="InfoColor">#555555</Color>
<Color x:Key="WarningColor">#bf7e16</Color> <Color x:Key="WarningColor">#bf7e16</Color>
<Color x:Key="MutedColor">#777777</Color>
</ResourceDictionary> </ResourceDictionary>

View file

@ -8,6 +8,7 @@
<Color x:Key="SuccessColor">#00a65a</Color> <Color x:Key="SuccessColor">#00a65a</Color>
<Color x:Key="InfoColor">#555555</Color> <Color x:Key="InfoColor">#555555</Color>
<Color x:Key="WarningColor">#bf7e16</Color> <Color x:Key="WarningColor">#bf7e16</Color>
<Color x:Key="MutedColor">#777777</Color>
<Color x:Key="ListHeaderTextColor">#3c8dbc</Color> <Color x:Key="ListHeaderTextColor">#3c8dbc</Color>
</ResourceDictionary> </ResourceDictionary>

View file

@ -21,7 +21,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="LiteDB" Version="4.1.4" /> <PackageReference Include="LiteDB" Version="4.1.4" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="PCLCrypto" Version="2.0.147" /> <PackageReference Include="PCLCrypto" Version="2.0.147" />
</ItemGroup> </ItemGroup>

View file

@ -66,6 +66,7 @@ namespace Bit.Core.Models.View
} }
} }
public bool Shared => OrganizationId != null;
public bool HasPasswordHistory => PasswordHistory?.Any() ?? false; public bool HasPasswordHistory => PasswordHistory?.Any() ?? false;
public bool HasAttachments => Attachments?.Any() ?? false; public bool HasAttachments => Attachments?.Any() ?? false;
public bool HasOldAttachments public bool HasOldAttachments

View file

@ -35,7 +35,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.12.0.1\lib\netstandard2.0\Newtonsoft.Json.dll</HintPath> <HintPath>..\..\packages\Newtonsoft.Json.12.0.2\lib\netstandard2.0\Newtonsoft.Json.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Newtonsoft.Json" version="12.0.1" targetFramework="xamarinios10" /> <package id="Newtonsoft.Json" version="12.0.2" targetFramework="xamarinios10" />
</packages> </packages>

View file

@ -23,6 +23,9 @@ namespace Bit.iOS
public override bool FinishedLaunching(UIApplication app, NSDictionary options) public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{ {
Xamarin.Forms.Forms.Init(); Xamarin.Forms.Forms.Init();
FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
LoadApplication(new App.App()); LoadApplication(new App.App());
return base.FinishedLaunching(app, options); return base.FinishedLaunching(app, options);

View file

@ -153,7 +153,7 @@
<PackageReference Include="Xamarin.Essentials"> <PackageReference Include="Xamarin.Essentials">
<Version>1.1.0</Version> <Version>1.1.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms" Version="3.6.0.293080" /> <PackageReference Include="Xamarin.Forms" Version="3.6.0.344457" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<ItemGroup> <ItemGroup>