Skip to content

Commit

Permalink
Merge pull request #17 from SuavePirate/feature/validation
Browse files Browse the repository at this point in the history
Feature/validation
  • Loading branch information
SuavePirate committed Jan 22, 2018
2 parents 52033d4 + caa3cd2 commit 9f10925
Show file tree
Hide file tree
Showing 7 changed files with 368 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@
<ScrollView>
<StackLayout Spacing="16" Margin="16">
<Label Text="Material Forms!" Margin="32" HorizontalOptions="Center" HorizontalTextAlignment="Center"/>
<suave:MaterialEntry Placeholder="Email" Keyboard="Email" AccentColor="Green"/>
<suave:MaterialEntry Placeholder="Regular Text" AccentColor="Orange"/>
<suave:MaterialEntry Placeholder="Number" Keyboard="Numeric" AccentColor="Red"/>
<suave:MaterialEntry IsPassword="True" Placeholder="Password" AccentColor="Blue"/>
<suave:MaterialDatePicker Placeholder="Date Picker" AccentColor="BlueViolet"/>
<suave:MaterialTimePicker Placeholder="Time Picker" AccentColor="HotPink" />
<suave:MaterialEntry Placeholder="Email" Keyboard="Email" AccentColor="Green" IsValid="{Binding IsValid}"/>
<suave:MaterialEntry Placeholder="Regular Text" AccentColor="Orange" IsValid="{Binding IsValid}"/>
<suave:MaterialEntry Placeholder="Number" Keyboard="Numeric" AccentColor="Red" IsValid="{Binding IsValid}"/>
<suave:MaterialEntry IsPassword="True" Placeholder="Password" AccentColor="Blue" IsValid="{Binding IsValid}" InvalidColor="Lime"/>
<suave:MaterialEntry Placeholder="Updated Default Color" DefaultColor="Aqua" AccentColor="Fuchsia"/>
<suave:MaterialDatePicker Placeholder="Date Picker" AccentColor="BlueViolet" IsValid="{Binding IsValid}"/>
<suave:MaterialTimePicker Placeholder="Time Picker" AccentColor="HotPink" IsValid="{Binding IsValid}"/>
<suave:MaterialPicker
Placeholder="Picker"
AccentColor="Maroon"
Items="{Binding PickerData}"
SelectedItem="{Binding PickerSelectedItem}"
SelectedIndexChangedCommand="{Binding PickerSelectedIndexChangedCmd}" />

SelectedIndexChangedCommand="{Binding PickerSelectedIndexChangedCmd}"
IsValid="{Binding IsValid}"/>
<Button Text="Switch IsValid" Command="{Binding SwitchValidCommand}"/>
</StackLayout>
</ScrollView>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,23 @@ namespace ExampleMaterialApp
{
public class MainViewModel : INotifyPropertyChanged
{

private bool _isValid = true;
public ObservableCollection<Fruit> PickerData { get; set; }
public Fruit PickerSelectedItem { get; set; }
public ICommand PickerSelectedIndexChangedCmd { get; }
public ICommand SwitchValidCommand { get; }
public bool IsValid
{
get
{
return _isValid;
}
set
{
_isValid = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsValid)));
}
}

public MainViewModel()
{
Expand All @@ -25,6 +38,7 @@ public MainViewModel()
PickerSelectedItem = PickerData[PickerData.Count - 1];

PickerSelectedIndexChangedCmd = new Command<Fruit>((selectedFruit) => Debug.WriteLine($"PickerSelectedIndexChangedCmd => {selectedFruit}"));
SwitchValidCommand = new Command(() => IsValid = !IsValid);
}

// Fody will take care of that
Expand Down
83 changes: 81 additions & 2 deletions src/SuaveControls.MaterialForms/MaterialDatePicker.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,56 @@ public string CustomDateFormat
matEntry.EntryField.Keyboard = (Keyboard)newVal;
});
public static BindableProperty AccentColorProperty = BindableProperty.Create(nameof(AccentColor), typeof(Color), typeof(MaterialDatePicker), defaultValue: Color.Accent);
public static BindableProperty InvalidColorProperty = BindableProperty.Create(nameof(InvalidColor), typeof(Color), typeof(MaterialEntry), Color.Red, propertyChanged: (bindable, oldVal, newVal) =>
{
var matEntry = (MaterialDatePicker)bindable;
matEntry.UpdateValidation();
});
public static BindableProperty DefaultColorProperty = BindableProperty.Create(nameof(DefaultColor), typeof(Color), typeof(MaterialEntry), Color.Gray, propertyChanged: (bindable, oldVal, newVal) =>
{
var matEntry = (MaterialDatePicker)bindable;
matEntry.UpdateValidation();
});
public static BindableProperty IsValidProperty = BindableProperty.Create(nameof(IsValid), typeof(bool), typeof(MaterialEntry), true, propertyChanged: (bindable, oldVal, newVal) =>
{
var matEntry = (MaterialDatePicker)bindable;
matEntry.UpdateValidation();
});

public bool IsValid
{
get
{
return (bool)GetValue(IsValidProperty);
}
set
{
SetValue(IsValidProperty, value);
}
}
public Color DefaultColor
{
get
{
return (Color)GetValue(DefaultColorProperty);
}
set
{
SetValue(DefaultColorProperty, value);
}
}
public Color InvalidColor
{
get
{
return (Color)GetValue(InvalidColorProperty);
}
set
{
SetValue(InvalidColorProperty, value);
}
}

public DateTime? Date
{
get
Expand Down Expand Up @@ -118,6 +168,7 @@ public MaterialDatePicker()
{
InitializeComponent();
EntryField.BindingContext = this;
BottomBorder.BackgroundColor = DefaultColor;
EntryField.Focused += (s, a) =>
{
Device.BeginInvokeOnMainThread(() => {
Expand Down Expand Up @@ -147,8 +198,8 @@ public MaterialDatePicker()
};
Picker.Unfocused += async (s, a) =>
{
HiddenLabel.TextColor = Color.Gray;
Picker_DateSelected(s, new DateChangedEventArgs(Picker.Date, Picker.Date));
HiddenLabel.TextColor = DefaultColor;
Picker_DateSelected(s, new DateChangedEventArgs(Picker.Date, Picker.Date));
if (string.IsNullOrEmpty(EntryField.Text))
{
// animate both at the same time
Expand All @@ -175,5 +226,33 @@ private void Picker_DateSelected(object sender, DateChangedEventArgs e)
EntryField.Text = e.NewDate.ToString(CustomDateFormat, CultureInfo.CurrentCulture);
Date = e.NewDate;
}


/// <summary>
/// Updates view based on validation state
/// </summary>
private void UpdateValidation()
{
if (IsValid)
{

BottomBorder.BackgroundColor = DefaultColor;
HiddenBottomBorder.BackgroundColor = AccentColor;
if (IsFocused)
{
HiddenLabel.TextColor = AccentColor;
}
else
{
HiddenLabel.TextColor = DefaultColor;
}
}
else
{
BottomBorder.BackgroundColor = InvalidColor;
HiddenBottomBorder.BackgroundColor = InvalidColor;
HiddenLabel.TextColor = InvalidColor;
}
}
}
}
6 changes: 3 additions & 3 deletions src/SuaveControls.MaterialForms/MaterialEntry.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:SuaveControls.MaterialForms"
Expand All @@ -11,8 +11,8 @@
</Grid.RowDefinitions>
<Label x:Name="HiddenLabel" FontSize="10" IsVisible="False" Margin="0"/>
<views:BorderlessEntry x:Name="EntryField" Text="{Binding Text, Mode=TwoWay}" Margin="0,12,0,0"/>
<BoxView x:Name="BottomBorder" BackgroundColor="Gray" Grid.Row="1" HeightRequest="1" Margin="0" HorizontalOptions="FillAndExpand"/>
<BoxView x:Name="HiddenBottomBorder" BackgroundColor="Gray" Grid.Row="1" HeightRequest="1" Margin="0" WidthRequest="0" HorizontalOptions="Center"/>
<BoxView x:Name="BottomBorder" Grid.Row="1" HeightRequest="1" Margin="0" HorizontalOptions="FillAndExpand"/>
<BoxView x:Name="HiddenBottomBorder" Grid.Row="1" HeightRequest="1" Margin="0" WidthRequest="0" HorizontalOptions="Center"/>
</Grid>
</ContentView.Content>
</ContentView>
100 changes: 98 additions & 2 deletions src/SuaveControls.MaterialForms/MaterialEntry.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ namespace SuaveControls.MaterialForms
{
public partial class MaterialEntry : ContentView
{
#region Events
public event EventHandler<FocusEventArgs> EntryFocused;
public event EventHandler<FocusEventArgs> EntryUnfocused;
public event EventHandler<TextChangedEventArgs> TextChanged;
#endregion

#region Bindable Properties
public static BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(MaterialEntry), defaultBindingMode: BindingMode.TwoWay);
public static BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(MaterialEntry), defaultBindingMode: BindingMode.TwoWay, propertyChanged: (bindable, oldVal, newval) =>
{
Expand All @@ -34,6 +37,59 @@ public partial class MaterialEntry : ContentView
matEntry.EntryField.Keyboard = (Keyboard)newVal;
});
public static BindableProperty AccentColorProperty = BindableProperty.Create(nameof(AccentColor), typeof(Color), typeof(MaterialEntry), defaultValue: Color.Accent);
public static BindableProperty InvalidColorProperty = BindableProperty.Create(nameof(InvalidColor), typeof(Color), typeof(MaterialEntry), Color.Red, propertyChanged: (bindable, oldVal, newVal) =>
{
var matEntry = (MaterialEntry)bindable;
matEntry.UpdateValidation();
});
public static BindableProperty DefaultColorProperty = BindableProperty.Create(nameof(DefaultColor), typeof(Color), typeof(MaterialEntry), Color.Gray, propertyChanged: (bindable, oldVal, newVal) =>
{
var matEntry = (MaterialEntry)bindable;
matEntry.UpdateValidation();
});
public static BindableProperty IsValidProperty = BindableProperty.Create(nameof(IsValid), typeof(bool), typeof(MaterialEntry), true, propertyChanged: (bindable, oldVal, newVal) =>
{
var matEntry = (MaterialEntry)bindable;
matEntry.UpdateValidation();
});
#endregion

#region Public Properties

public bool IsValid
{
get
{
return (bool)GetValue(IsValidProperty);
}
set
{
SetValue(IsValidProperty, value);
}
}
public Color DefaultColor
{
get
{
return (Color)GetValue(DefaultColorProperty);
}
set
{
SetValue(DefaultColorProperty, value);
}
}
public Color InvalidColor
{
get
{
return (Color)GetValue(InvalidColorProperty);
}
set
{
SetValue(InvalidColorProperty, value);
}
}

public Color AccentColor
{
get
Expand Down Expand Up @@ -91,11 +147,15 @@ public string Placeholder
SetValue(PlaceholderProperty, value);
}
}

#endregion

public MaterialEntry()
{
InitializeComponent();
EntryField.BindingContext = this;
EntryField.TextChanged += async (s, a) =>
BottomBorder.BackgroundColor = DefaultColor;
EntryField.TextChanged += (s, a) =>
{
TextChanged?.Invoke(s, a);
};
Expand All @@ -118,11 +178,18 @@ public MaterialEntry()
await CalculateLayoutUnfocused();
}
};

UpdateValidation();
}

/// <summary>
/// Calculates the layout when unfocused. Includes running the animation to update the bottom border color and the floating label
/// </summary>
/// <returns>The layout unfocused.</returns>
private async Task CalculateLayoutUnfocused()
{
HiddenLabel.TextColor = Color.Gray;
HiddenLabel.TextColor = DefaultColor;
BottomBorder.BackgroundColor = DefaultColor;
if (string.IsNullOrEmpty(EntryField.Text))
{
// animate both at the same time
Expand All @@ -140,6 +207,9 @@ private async Task CalculateLayoutUnfocused()
}
}

/// <summary>
/// Calculates the layout when focused. Includes running the animation to update the bottom border color and the floating label
/// </summary>
private async Task CalculateLayoutFocused()
{
HiddenLabel.IsVisible = true;
Expand All @@ -161,5 +231,31 @@ private async Task CalculateLayoutFocused()
}
}

/// <summary>
/// Updates view based on validation state
/// </summary>
private void UpdateValidation()
{
if(IsValid)
{

BottomBorder.BackgroundColor = DefaultColor;
HiddenBottomBorder.BackgroundColor = AccentColor;
if(IsFocused)
{
HiddenLabel.TextColor = AccentColor;
}
else
{
HiddenLabel.TextColor = DefaultColor;
}
}
else
{
BottomBorder.BackgroundColor = InvalidColor;
HiddenBottomBorder.BackgroundColor = InvalidColor;
HiddenLabel.TextColor = InvalidColor;
}
}
}
}
Loading

0 comments on commit 9f10925

Please sign in to comment.