uris, fields, etc to view page

This commit is contained in:
Kyle Spearrin 2019-04-26 16:58:20 -04:00
parent c2a168c6b7
commit d7312e2977
7 changed files with 295 additions and 135 deletions

View File

@ -42,6 +42,7 @@ namespace Bit.App.Pages
protected async override void OnAppearing()
{
base.OnAppearing();
// await _syncService.FullSyncAsync(true);
_broadcasterService.Subscribe(nameof(GroupingsPage), async (message) =>
{
if(message.Command == "syncCompleted")

View File

@ -6,7 +6,9 @@
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:views="clr-namespace:Bit.Core.Models.View;assembly=BitwardenCore"
x:DataType="pages:ViewPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:ViewPageViewModel />
@ -17,130 +19,241 @@
Text="{u:I18n Edit}" />
</ContentPage.ToolbarItems>
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row-header">
<Label Text="{u:I18n ItemInformation}"
StyleClass="box-header, box-header-platform" />
<ScrollView>
<StackLayout Spacing="20">
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row-header">
<Label Text="{u:I18n ItemInformation}"
StyleClass="box-header, box-header-platform" />
</StackLayout>
<StackLayout StyleClass="box-row">
<Label
Text="{u:I18n Name}"
StyleClass="box-label" />
<Label
Text="{Binding Cipher.Name, Mode=OneWay}"
StyleClass="box-value" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
<StackLayout IsVisible="{Binding IsLogin}"
Spacing="0"
Padding="0">
<Grid StyleClass="box-row">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{u:I18n Username}"
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<Label
Text="{Binding Cipher.Login.Username, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf0ea;"
Command="{Binding CopyCommand}"
CommandParameter="LoginUsername"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2" />
</Grid>
<BoxView StyleClass="box-row-separator" />
<Grid StyleClass="box-row">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{u:I18n Password}"
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<Label
Text="{Binding Cipher.Login.MaskedPassword, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf0ea;"
Command="{Binding CopyCommand}"
CommandParameter="LoginPassword"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2" />
</Grid>
<BoxView StyleClass="box-row-separator" />
<Grid StyleClass="box-row" IsVisible="{Binding ShowTotp}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{u:I18n VerificationCodeTotp}"
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<Label
Text="{Binding TotpCodeFormatted, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0" />
<Label
Text="{Binding TotpSec, Mode=OneWay}"
Style="{DynamicResource textTotp}"
Margin="0, 0, 10, 0"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
HorizontalOptions="End"
HorizontalTextAlignment="End"
VerticalOptions="CenterAndExpand"/>
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf0ea;"
Command="{Binding CopyCommand}"
CommandParameter="LoginTotp"
Grid.Row="0"
Grid.Column="2"
Grid.RowSpan="2" />
</Grid>
<BoxView StyleClass="box-row-separator" IsVisible="{Binding ShowTotp}" />
</StackLayout>
<StackLayout IsVisible="{Binding IsCard}">
</StackLayout>
<StackLayout IsVisible="{Binding IsIdentity}">
</StackLayout>
</StackLayout>
<StackLayout StyleClass="box" IsVisible="{Binding ShowUris}">
<StackLayout StyleClass="box-row-header">
<Label Text="{u:I18n URIs}"
StyleClass="box-header, box-header-platform" />
</StackLayout>
<controls:RepeaterView ItemsSource="{Binding Cipher.Login.Uris}">
<controls:RepeaterView.ItemTemplate>
<DataTemplate x:DataType="views:LoginUriView">
<StackLayout Spacing="0" Padding="0">
<Grid StyleClass="box-row">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{u:I18n URI}"
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<Label
Text="{Binding HostnameOrUri, Mode=OneWay}"
StyleClass="box-value"
LineBreakMode="CharacterWrap"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf064;"
Command="{Binding BindingContext.LaunchUriCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2" />
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf0ea;"
Command="{Binding BindingContext.CopyUriCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"
Grid.Column="2"
Grid.RowSpan="2" />
</Grid>
<BoxView StyleClass="box-row-separator" />
</StackLayout>
</DataTemplate>
</controls:RepeaterView.ItemTemplate>
</controls:RepeaterView>
</StackLayout>
<StackLayout StyleClass="box" IsVisible="{Binding ShowNotes}">
<StackLayout StyleClass="box-row-header">
<Label Text="{u:I18n Notes}"
StyleClass="box-header, box-header-platform" />
</StackLayout>
<StackLayout StyleClass="box-row">
<Label
Text="{Binding Cipher.Notes, Mode=OneWay}"
StyleClass="box-value"
LineBreakMode="WordWrap" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
</StackLayout>
<StackLayout StyleClass="box" IsVisible="{Binding ShowFields}">
<StackLayout StyleClass="box-row-header">
<Label Text="{u:I18n CustomFields}"
StyleClass="box-header, box-header-platform" />
</StackLayout>
<controls:RepeaterView ItemsSource="{Binding Cipher.Fields}">
<controls:RepeaterView.ItemTemplate>
<DataTemplate x:DataType="views:FieldView">
<StackLayout Spacing="0" Padding="0">
<Grid StyleClass="box-row">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{Binding Name, Mode=OneWay}"
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<Label
Text="{Binding Value, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf0ea;"
Command="{Binding BindingContext.CopyFieldCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2" />
</Grid>
<BoxView StyleClass="box-row-separator" />
</StackLayout>
</DataTemplate>
</controls:RepeaterView.ItemTemplate>
</controls:RepeaterView>
</StackLayout>
</StackLayout>
<StackLayout StyleClass="box-row">
<Label
Text="{u:I18n Name}"
StyleClass="box-label" />
<Label
Text="{Binding Cipher.Name, Mode=OneWay}"
StyleClass="box-value" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
<StackLayout IsVisible="{Binding IsLogin}">
<Grid StyleClass="box-row">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{u:I18n Username}"
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<Label
Text="{Binding Cipher.Login.Username, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton StyleClass="box-row-button, box-row-button-platform"
Text="&#xf0ea;"
Command="{Binding CopyCommand}"
CommandParameter="LoginUsername"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2" />
</Grid>
<BoxView StyleClass="box-row-separator" />
<Grid StyleClass="box-row">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{u:I18n Password}"
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<Label
Text="{Binding Cipher.Login.MaskedPassword, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton StyleClass="box-row-button, box-row-button-platform"
Text="&#xf0ea;"
Command="{Binding CopyCommand}"
CommandParameter="LoginPassword"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2" />
</Grid>
<BoxView StyleClass="box-row-separator" />
<Grid StyleClass="box-row">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{u:I18n VerificationCodeTotp}"
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<Label
Text="{Binding TotpCodeFormatted, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0" />
<Label
Text="{Binding TotpSec, Mode=OneWay}"
Style="{DynamicResource textTotp}"
Margin="0, 0, 10, 0"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
HorizontalOptions="End"
HorizontalTextAlignment="End"
VerticalOptions="CenterAndExpand"/>
<controls:FaButton StyleClass="box-row-button, box-row-button-platform"
Text="&#xf0ea;"
Command="{Binding CopyCommand}"
CommandParameter="LoginTotp"
Grid.Row="0"
Grid.Column="2"
Grid.RowSpan="2" />
</Grid>
</StackLayout>
<StackLayout IsVisible="{Binding IsCard}">
</StackLayout>
<StackLayout IsVisible="{Binding IsIdentity}">
</StackLayout>
<StackLayout StyleClass="box-row">
<Label
Text="{u:I18n Notes}"
StyleClass="box-label" />
<Label
Text="{Binding Cipher.Notes, Mode=OneWay}"
StyleClass="box-value" />
</StackLayout>
</StackLayout>
</ScrollView>
</ContentPage>

View File

@ -31,12 +31,16 @@ namespace Bit.App.Pages
_userService = ServiceContainer.Resolve<IUserService>("userService");
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
CopyCommand = new Command<string>(CopyAsync);
CopyCommand = new Command<string>((id) => CopyAsync(id, null));
CopyUriCommand = new Command<LoginUriView>(CopyUriAsync);
LaunchUriCommand = new Command<LoginUriView>(LaunchUriAsync);
PageTitle = AppResources.ViewItem;
}
public Command CopyCommand { get; set; }
public Command CopyUriCommand { get; set; }
public Command LaunchUriCommand { get; set; }
public string CipherId { get; set; }
public CipherView Cipher
{
@ -47,7 +51,11 @@ namespace Bit.App.Pages
nameof(IsLogin),
nameof(IsIdentity),
nameof(IsCard),
nameof(IsSecureNote)
nameof(IsSecureNote),
nameof(ShowUris),
nameof(ShowFields),
nameof(ShowNotes),
nameof(ShowTotp)
});
}
public bool CanAccessPremium
@ -59,10 +67,19 @@ namespace Bit.App.Pages
public bool IsIdentity => _cipher?.Type == Core.Enums.CipherType.Identity;
public bool IsCard => _cipher?.Type == Core.Enums.CipherType.Card;
public bool IsSecureNote => _cipher?.Type == Core.Enums.CipherType.SecureNote;
public bool ShowUris => IsLogin && _cipher.Login.HasUris;
public bool ShowNotes => !string.IsNullOrWhiteSpace(_cipher.Notes);
public bool ShowFields => _cipher.HasFields;
public bool ShowTotp => !string.IsNullOrWhiteSpace(_cipher.Login.Totp) &&
!string.IsNullOrWhiteSpace(TotpCodeFormatted);
public string TotpCodeFormatted
{
get => _totpCodeFormatted;
set => SetProperty(ref _totpCodeFormatted, value);
set => SetProperty(ref _totpCodeFormatted, value,
additionalPropertyNames: new string[]
{
nameof(ShowTotp)
});
}
public string TotpSec
{
@ -151,9 +168,8 @@ namespace Bit.App.Pages
}
}
private async void CopyAsync(string id)
private async void CopyAsync(string id, string text = null)
{
string text = null;
string name = null;
if(id == "LoginUsername")
{
@ -170,6 +186,10 @@ namespace Bit.App.Pages
text = _totpCode;
name = AppResources.VerificationCodeTotp;
}
else if(id == "LoginUri")
{
name = AppResources.URI;
}
if(text != null)
{
@ -180,5 +200,18 @@ namespace Bit.App.Pages
}
}
}
private void CopyUriAsync(LoginUriView uri)
{
CopyAsync("LoginUri", uri.Uri);
}
private void LaunchUriAsync(LoginUriView uri)
{
if(uri.CanLaunch)
{
_platformUtilsService.LaunchUri(uri.LaunchUri);
}
}
}
}

View File

@ -3246,6 +3246,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to URIs.
/// </summary>
internal static string URIs {
get {
return ResourceManager.GetString("URIs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use another two-step login method.
/// </summary>

View File

@ -1364,4 +1364,8 @@
<data name="AllItems" xml:space="preserve">
<value>All Items</value>
</data>
<data name="URIs" xml:space="preserve">
<value>URIs</value>
<comment>Plural form of a URI</comment>
</data>
</root>

View File

@ -40,8 +40,8 @@
ApplyToDerivedTypes="True"
Class="box-row-button-platform">
<Setter Property="WidthRequest"
Value="40" />
Value="37" />
<Setter Property="FontSize"
Value="28" />
Value="25" />
</Style>
</ResourceDictionary>

View File

@ -19,11 +19,11 @@ namespace Bit.Core.Models.View
public DateTime? PasswordRevisionDate { get; set; }
public string Totp { get; set; }
public List<LoginUriView> Uris { get; set; }
public string Uri => HashUris ? Uris[0].Uri : null;
public string Uri => HasUris ? Uris[0].Uri : null;
public string MaskedPassword => Password != null ? "••••••••" : null;
public string SubTitle => Username;
public bool CanLaunch => HashUris && Uris.Any(u => u.CanLaunch);
public string LaunchUri => HashUris ? Uris.FirstOrDefault(u => u.CanLaunch)?.LaunchUri : null;
public bool HashUris => (Uris?.Count ?? 0) > 0;
public bool CanLaunch => HasUris && Uris.Any(u => u.CanLaunch);
public string LaunchUri => HasUris ? Uris.FirstOrDefault(u => u.CanLaunch)?.LaunchUri : null;
public bool HasUris => (Uris?.Count ?? 0) > 0;
}
}