une signature coté serveur
This commit is contained in:
parent
e22356f7ab
commit
7e7619db99
33 changed files with 698 additions and 211 deletions
|
|
@ -17,7 +17,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorTemplatePreprocessor", "4.2.0.703")]
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorTemplatePreprocessor", "4.2.1.62")]
|
||||
public partial class MarkdownEditor : MarkdownEditorBase
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Android.OS;
|
|||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.Graphics;
|
||||
|
||||
namespace BookAStar.Droid.Markdown
|
||||
{
|
||||
|
|
@ -17,6 +18,7 @@ namespace BookAStar.Droid.Markdown
|
|||
protected static MarkdownDeep.Markdown markdown = new MarkdownDeep.Markdown();
|
||||
public string Content { get; set; }
|
||||
public bool Editable { get; set; }
|
||||
|
||||
public string GetHtml()
|
||||
{
|
||||
return markdown.Transform(Content);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ namespace BookAStar
|
|||
using ViewModels.UserProfile;
|
||||
using Pages.UserProfile;
|
||||
using ViewModels.EstimateAndBilling;
|
||||
using Pages.EstimatePages;
|
||||
|
||||
public partial class App : Application // superclass new in 1.3
|
||||
{
|
||||
|
|
@ -150,6 +151,7 @@ namespace BookAStar
|
|||
ViewFactory.Register<EditEstimatePage, EditEstimateViewModel>();
|
||||
ViewFactory.Register<UserFiles, DirectoryInfoViewModel>();
|
||||
ViewFactory.Register<UserProfilePage, UserProfileViewModel>();
|
||||
ViewFactory.Register<EstimateSigningPage, EditEstimateViewModel>();
|
||||
ConfigManager = new GenericConfigSettingsMgr(s =>
|
||||
MainSettings.AppSettings.GetValueOrDefault<string>(s, MainSettings.SettingsDefault), null);
|
||||
}
|
||||
|
|
|
|||
42
BookAStar/BookAStar/Behaviors/EditorMaxLengthValidator.cs
Normal file
42
BookAStar/BookAStar/Behaviors/EditorMaxLengthValidator.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace BookAStar.Behaviors
|
||||
{
|
||||
public class EditorMaxLengthValidator : Behavior<Editor>
|
||||
{
|
||||
public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create("MaxLength", typeof(int), typeof(EditorMaxLengthValidator), 0);
|
||||
public static readonly BindableProperty MinLengthProperty = BindableProperty.Create("MinLength", typeof(int), typeof(EditorMaxLengthValidator), 0);
|
||||
|
||||
public int MaxLength
|
||||
{
|
||||
get { return (int)GetValue(MaxLengthProperty); }
|
||||
set { SetValue(MaxLengthProperty, value); }
|
||||
}
|
||||
public int MinLength
|
||||
{
|
||||
get { return (int)GetValue(MinLengthProperty); }
|
||||
set { SetValue(MinLengthProperty, value); }
|
||||
}
|
||||
|
||||
protected override void OnAttachedTo(Editor bindable)
|
||||
{
|
||||
bindable.TextChanged += bindable_TextChanged;
|
||||
}
|
||||
|
||||
public bool IsValid { get; set; }
|
||||
|
||||
private void bindable_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
IsValid = e.NewTextValue == null? false : ( e.NewTextValue.Length >= MinLength && e.NewTextValue.Length <= MaxLength ) ;
|
||||
if (!IsValid) if (e.NewTextValue!=null) if (e.NewTextValue.Length > MaxLength)
|
||||
((Editor)sender).Text = e.NewTextValue.Substring(0, MaxLength);
|
||||
}
|
||||
|
||||
protected override void OnDetachingFrom(Editor bindable)
|
||||
{
|
||||
bindable.TextChanged -= bindable_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -8,39 +8,14 @@ using Xamarin.Forms;
|
|||
|
||||
namespace BookAStar.Behaviors
|
||||
{
|
||||
public class EmailValidatorBehavior : Behavior<Entry>
|
||||
public class EmailValidatorBehavior : RegexValidatorBehavior
|
||||
{
|
||||
const string emailRegex = @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
|
||||
@"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$";
|
||||
|
||||
// Creating BindableProperties with Limited write access: http://iosapi.xamarin.com/index.aspx?link=M%3AXamarin.Forms.BindableObject.SetValue(Xamarin.Forms.BindablePropertyKey%2CSystem.Object)
|
||||
|
||||
static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(EmailValidatorBehavior), false);
|
||||
|
||||
public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;
|
||||
|
||||
public bool IsValid
|
||||
public EmailValidatorBehavior()
|
||||
{
|
||||
get { return (bool)base.GetValue(IsValidProperty); }
|
||||
private set { base.SetValue(IsValidPropertyKey, value); }
|
||||
}
|
||||
|
||||
protected override void OnAttachedTo(Entry bindable)
|
||||
{
|
||||
bindable.TextChanged += HandleTextChanged;
|
||||
}
|
||||
|
||||
|
||||
void HandleTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
IsValid = (Regex.IsMatch(e.NewTextValue, emailRegex, RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)));
|
||||
((Entry)sender).TextColor = IsValid ? Color.Default : Color.Red;
|
||||
}
|
||||
|
||||
protected override void OnDetachingFrom(Entry bindable)
|
||||
{
|
||||
bindable.TextChanged -= HandleTextChanged;
|
||||
|
||||
Regexp = emailRegex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
39
BookAStar/BookAStar/Behaviors/MarkdownViewLengthValidator.Cs
Normal file
39
BookAStar/BookAStar/Behaviors/MarkdownViewLengthValidator.Cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
using BookAStar.Views;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace BookAStar.Behaviors
|
||||
{
|
||||
public class MarkdownViewLengthValidator : Behavior<MarkdownView>
|
||||
{
|
||||
public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create("MaxLength", typeof(int), typeof(MarkdownViewLengthValidator), 0);
|
||||
public static readonly BindableProperty MinLengthProperty = BindableProperty.Create("MinLength", typeof(int), typeof(MarkdownViewLengthValidator), 0);
|
||||
public int MaxLength
|
||||
{
|
||||
get { return (int)GetValue(MaxLengthProperty); }
|
||||
set { SetValue(MaxLengthProperty, value); }
|
||||
}
|
||||
public int MinLength
|
||||
{
|
||||
get { return (int)GetValue(MinLengthProperty); }
|
||||
set { SetValue(MinLengthProperty, value); }
|
||||
}
|
||||
protected override void OnAttachedTo(MarkdownView bindable)
|
||||
{
|
||||
bindable.Modified += bindable_TextChanged;
|
||||
}
|
||||
|
||||
public bool IsValid { get; set; }
|
||||
|
||||
private void bindable_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
IsValid = e.NewTextValue == null ? false : (e.NewTextValue.Length >= MinLength && e.NewTextValue.Length <= MaxLength);
|
||||
if (!IsValid) if (e.NewTextValue != null) if (e.NewTextValue.Length > MaxLength)
|
||||
((Editor)sender).Text = e.NewTextValue.Substring(0, MaxLength);
|
||||
}
|
||||
|
||||
protected override void OnDetachingFrom(MarkdownView bindable)
|
||||
{
|
||||
bindable.Modified -= bindable_TextChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
using Xamarin.Forms;
|
||||
|
||||
namespace BookAStar.Behaviors
|
||||
{
|
||||
public class EditorMaxLengthValidator : Behavior<Editor>
|
||||
{
|
||||
public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create("MaxLength", typeof(int), typeof(MaxLengthValidator), 0);
|
||||
|
||||
public int MaxLength
|
||||
{
|
||||
get { return (int)GetValue(MaxLengthProperty); }
|
||||
set { SetValue(MaxLengthProperty, value); }
|
||||
}
|
||||
|
||||
protected override void OnAttachedTo(Editor bindable)
|
||||
{
|
||||
bindable.TextChanged += bindable_TextChanged;
|
||||
}
|
||||
|
||||
public bool IsValid { get; set; }
|
||||
|
||||
private void bindable_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
IsValid = e.NewTextValue == null? false : ( e.NewTextValue.Length > 0 && e.NewTextValue.Length <= MaxLength ) ;
|
||||
if (!IsValid) if (e.NewTextValue!=null) if (e.NewTextValue.Length > MaxLength)
|
||||
((Editor)sender).Text = e.NewTextValue.Substring(0, MaxLength);
|
||||
}
|
||||
|
||||
protected override void OnDetachingFrom(Editor bindable)
|
||||
{
|
||||
bindable.TextChanged -= bindable_TextChanged;
|
||||
}
|
||||
}
|
||||
public class MaxLengthValidator : Behavior<Entry>
|
||||
{
|
||||
public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create("MaxLength", typeof(int), typeof(MaxLengthValidator), 0);
|
||||
|
||||
public int MaxLength
|
||||
{
|
||||
get { return (int)GetValue(MaxLengthProperty); }
|
||||
set { SetValue(MaxLengthProperty, value); }
|
||||
}
|
||||
|
||||
protected override void OnAttachedTo(Entry bindable)
|
||||
{
|
||||
bindable.TextChanged += bindable_TextChanged;
|
||||
}
|
||||
|
||||
private void bindable_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
//if (MaxLength != null && MaxLength.HasValue)
|
||||
if (e.NewTextValue.Length > MaxLength)
|
||||
((Entry)sender).Text = e.NewTextValue.Substring(0, MaxLength);
|
||||
}
|
||||
|
||||
protected override void OnDetachingFrom(Entry bindable)
|
||||
{
|
||||
bindable.TextChanged -= bindable_TextChanged;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
53
BookAStar/BookAStar/Behaviors/RegexValidatorBehavior.cs
Normal file
53
BookAStar/BookAStar/Behaviors/RegexValidatorBehavior.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace BookAStar.Behaviors
|
||||
{
|
||||
public class RegexValidatorBehavior : Behavior<Entry>
|
||||
{
|
||||
private string regexp = @"^([\d\w]+)$";
|
||||
// Creating BindableProperties with Limited write access: http://iosapi.xamarin.com/index.aspx?link=M%3AXamarin.Forms.BindableObject.SetValue(Xamarin.Forms.BindablePropertyKey%2CSystem.Object)
|
||||
|
||||
static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(RegexValidatorBehavior), false);
|
||||
|
||||
public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get { return (bool)base.GetValue(IsValidProperty); }
|
||||
private set { base.SetValue(IsValidPropertyKey, value); }
|
||||
}
|
||||
|
||||
protected string Regexp
|
||||
{
|
||||
get
|
||||
{
|
||||
return regexp;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
regexp = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAttachedTo(Entry bindable)
|
||||
{
|
||||
bindable.TextChanged += HandleTextChanged;
|
||||
}
|
||||
|
||||
|
||||
void HandleTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
IsValid = (Regex.IsMatch(e.NewTextValue, regexp, RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)));
|
||||
((Entry)sender).TextColor = IsValid ? Color.Default : Color.Red;
|
||||
}
|
||||
|
||||
protected override void OnDetachingFrom(Entry bindable)
|
||||
{
|
||||
bindable.TextChanged -= HandleTextChanged;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,14 +44,17 @@
|
|||
<Compile Include="Attributes\DisplayAttribute.cs" />
|
||||
<Compile Include="Behaviors\EmailValidatorBehavior.cs" />
|
||||
<Compile Include="Behaviors\IntegerEntryBehavior.cs" />
|
||||
<Compile Include="Behaviors\MaxLengthValidator.cs" />
|
||||
<Compile Include="Behaviors\EditorMaxLengthValidator.cs" />
|
||||
<Compile Include="Behaviors\DecimalValidatorBehavior.cs" />
|
||||
<Compile Include="Behaviors\MarkdownViewLengthValidator.cs" />
|
||||
<Compile Include="Behaviors\PickerBehavior.cs" />
|
||||
<Compile Include="Behaviors\RegexValidatorBehavior.cs" />
|
||||
<Compile Include="Behaviors\StarBehavior.cs" />
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="Converters\NotValueConverter.cs" />
|
||||
<Compile Include="Converters\SignalRConnectionStateToObject.cs" />
|
||||
<Compile Include="Data\LocalState.cs" />
|
||||
<Compile Include="Data\ApiCallFailedException.cs" />
|
||||
<Compile Include="Data\EstimateEntity.cs" />
|
||||
<Compile Include="Data\NonCrUD\RemoteFiles.cs" />
|
||||
<Compile Include="Model\FileSystem\UserDirectoryInfo.cs" />
|
||||
<Compile Include="Model\FileSystem\UserFileInfo.cs" />
|
||||
|
|
@ -59,6 +62,9 @@
|
|||
<Compile Include="Model\Social\Messaging\ChatStatus.cs" />
|
||||
<Compile Include="Model\Social\Messaging\PrivateMessage.cs" />
|
||||
<Compile Include="Model\UI\PageState.cs" />
|
||||
<Compile Include="Pages\EstimatePages\EstimateSigningPage.xaml.cs">
|
||||
<DependentUpon>EstimateSigningPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\EstimatePages\EstimatesClientPage.xaml.cs">
|
||||
<DependentUpon>EstimatesClientPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
|
@ -89,7 +95,7 @@
|
|||
<Compile Include="Pages\DocSigning.xaml.cs">
|
||||
<DependentUpon>DocSigning.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ViewModels\Signing\DocSigningViewModel.cs" />
|
||||
<Compile Include="ViewModels\Signing\EstimateSigningViewModel.cs" />
|
||||
<Compile Include="ViewModels\Signing\SignaturePadConfigViewModel.cs" />
|
||||
<Compile Include="ViewModels\UserProfile\UserProfileViewModel.cs" />
|
||||
<Compile Include="ViewModels\UserProfile\DirectoryInfoViewModel.cs" />
|
||||
|
|
@ -272,6 +278,12 @@
|
|||
<Reference Include="Plugin.Connectivity.Abstractions">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Media">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Media.2.3.0\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Plugin.Media.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Media.Abstractions">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Media.2.3.0\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Plugin.Media.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Settings, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.1.0\lib\portable-net45+wp80+win8+wpa81\Plugin.Settings.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
|
@ -478,6 +490,12 @@
|
|||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Pages\EstimatePages\EstimateSigningPage.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<Import Project="..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
|
|
|||
21
BookAStar/BookAStar/Data/ApiCallFailedException.cs
Normal file
21
BookAStar/BookAStar/Data/ApiCallFailedException.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BookAStar.Data
|
||||
{
|
||||
class ApiCallFailedException : Exception
|
||||
{
|
||||
public ApiCallFailedException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ApiCallFailedException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
{
|
||||
// TODO estimatetemplate rating service product tag
|
||||
public RemoteEntityRO<BookQueryData, long> BookQueries { get; set; }
|
||||
public RemoteEntity<Estimate, long> Estimates { get; set; }
|
||||
public EstimateEntity Estimates { get; set; }
|
||||
public RemoteEntity<Blog, long> Blogspot { get; set; }
|
||||
internal RemoteFilesEntity RemoteFiles { get; set; }
|
||||
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
public DataManager()
|
||||
{
|
||||
BookQueries = new RemoteEntityRO<BookQueryData, long>("bookquery", q => q.Id);
|
||||
Estimates = new RemoteEntity<Estimate, long>("estimate", x => x.Id);
|
||||
Estimates = new EstimateEntity();
|
||||
Blogspot = new RemoteEntity<Blog, long>("blog", x=>x.Id);
|
||||
|
||||
Contacts = new LocalEntity<ClientProviderInfo, string>(c => c.UserId);
|
||||
|
|
|
|||
62
BookAStar/BookAStar/Data/EstimateEntity.cs
Normal file
62
BookAStar/BookAStar/Data/EstimateEntity.cs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
namespace BookAStar.Data
|
||||
{
|
||||
using Helpers;
|
||||
using Model.Workflow;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
|
||||
public class EstimateEntity : RemoteEntity<Estimate, long>
|
||||
{
|
||||
public EstimateEntity() : base("estimate", e => e.Id)
|
||||
{
|
||||
}
|
||||
|
||||
public async void SignAsProvider(Estimate estimate, Stream pngStream)
|
||||
{
|
||||
|
||||
if (estimate.Id == 0)
|
||||
{
|
||||
var ok = await this.Create(estimate);
|
||||
if (!ok)
|
||||
{
|
||||
await App.DisplayAlert("Erreur d'accès au serveur", "Echec de l'envoi de l'estimation");
|
||||
return;
|
||||
}
|
||||
this.Add(estimate);
|
||||
}
|
||||
using (HttpClient client = UserHelpers.CreateClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
var requestContent = new MultipartFormDataContent();
|
||||
var content = new StreamContent(pngStream);
|
||||
var filename = $"prosign-{estimate.Id}.png";
|
||||
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
|
||||
content.Headers.Add("Content-Disposition", $"form-data; name=\"file\"; filename=\"{filename}\"");
|
||||
requestContent.Add(content, "file", filename);
|
||||
using (var response = await client.PostAsync(
|
||||
Constants.YavscApiUrl + $"/pdfestimate/prosign/{estimate.Id}", requestContent))
|
||||
{
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var errContent = await response.Content.ReadAsStringAsync();
|
||||
throw new ApiCallFailedException($"SignAsProvider: {response.StatusCode} / {errContent}");
|
||||
}
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
JsonConvert.PopulateObject(json, estimate);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
this.SaveEntity();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BookAStar.Data
|
||||
{
|
||||
public enum LocalState
|
||||
{
|
||||
UpToDate = 0,
|
||||
New,
|
||||
Edited,
|
||||
Removed
|
||||
}
|
||||
}
|
||||
|
|
@ -6,13 +6,6 @@ namespace BookAStar.Data.NonCrUD
|
|||
{
|
||||
using Helpers;
|
||||
using Model.FileSystem;
|
||||
using System.Linq;
|
||||
/*
|
||||
public class DirectoryEntryChangingEvent : EventArgs
|
||||
{
|
||||
public UserDirectoryInfo OldItem { get; set; }
|
||||
public UserDirectoryInfo NewItem { get; set; }
|
||||
}*/
|
||||
|
||||
public class RemoteFilesEntity : RemoteEntity<UserDirectoryInfo, FileAddress>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace BookAStar.Data
|
|||
|
||||
public bool CanExecute(object parameter)
|
||||
{
|
||||
return !IsExecuting && (MainSettings.CurrentUser != null);
|
||||
return !IsExecuting;
|
||||
}
|
||||
|
||||
public RemoteEntity(string controllerName, Func<V, K> getKey) : base(getKey)
|
||||
|
|
@ -36,7 +36,7 @@ namespace BookAStar.Data
|
|||
protected void BeforeExecute()
|
||||
{
|
||||
if (IsExecuting)
|
||||
throw new InvalidOperationException("Already executing");
|
||||
throw new InvalidOperationException(Strings.AlreadyExecuting);
|
||||
IsExecuting = true;
|
||||
if (CanExecuteChanged != null)
|
||||
CanExecuteChanged.Invoke(this, new EventArgs());
|
||||
|
|
@ -71,7 +71,7 @@ namespace BookAStar.Data
|
|||
}
|
||||
catch (WebException webex)
|
||||
{
|
||||
throw new ServiceNotAvailable("No remote entity", webex);
|
||||
throw new ServiceNotAvailable(Strings.ENoRemoteEntity, webex);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -123,23 +123,27 @@ namespace BookAStar.Data
|
|||
return item;
|
||||
}
|
||||
|
||||
public virtual async void Create(V item)
|
||||
public virtual async Task<bool> Create(V item)
|
||||
{
|
||||
bool created = false;
|
||||
BeforeExecute();
|
||||
|
||||
using (HttpClient client = UserHelpers.CreateClient())
|
||||
{
|
||||
var stringContent = JsonConvert.SerializeObject(item);
|
||||
|
||||
HttpContent content = new StringContent(
|
||||
stringContent, Encoding.UTF8, "application/json"
|
||||
);
|
||||
using (var response = await client.PostAsync(ControllerUri, content))
|
||||
{
|
||||
if (!response.IsSuccessStatusCode)
|
||||
created = response.IsSuccessStatusCode;
|
||||
if (!created)
|
||||
{
|
||||
// TODO throw custom exception, and catch to inform user
|
||||
var errcontent = await response.Content.ReadAsStringAsync();
|
||||
Debug.WriteLine($"Create failed posting {stringContent} @ {ControllerUri.AbsoluteUri}: {errcontent}");
|
||||
Debug.WriteLine(string.Format(Strings.CreationFailed));
|
||||
Debug.WriteLine(errcontent);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -148,14 +152,15 @@ namespace BookAStar.Data
|
|||
JsonConvert.PopulateObject(recontent, item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CurrentItem = item;
|
||||
AfterExecuting();
|
||||
return created;
|
||||
}
|
||||
public virtual async void Update(V item)
|
||||
public virtual async Task<bool> Update(V item)
|
||||
{
|
||||
var updated = false;
|
||||
BeforeExecute();
|
||||
|
||||
var uri = GetUri(GetKey(item));
|
||||
|
|
@ -166,13 +171,16 @@ namespace BookAStar.Data
|
|||
);
|
||||
using (var response = await client.PutAsync(uri, content))
|
||||
{
|
||||
if (!response.IsSuccessStatusCode)
|
||||
updated = response.IsSuccessStatusCode;
|
||||
if (!updated)
|
||||
{// TODO throw custom exception, and catch to inform user
|
||||
if (response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
var recontent = await response.Content.ReadAsStringAsync();
|
||||
var errorcontent = await response.Content.ReadAsStringAsync();
|
||||
Debug.WriteLine(string.Format(Strings.UpdateFailed));
|
||||
Debug.WriteLine(errorcontent);
|
||||
|
||||
}
|
||||
|
||||
else Debug.WriteLine($"Update failed ({item} @ {uri.AbsolutePath} )");
|
||||
|
||||
}
|
||||
|
|
@ -188,6 +196,7 @@ namespace BookAStar.Data
|
|||
|
||||
CurrentItem = item;
|
||||
AfterExecuting();
|
||||
return updated;
|
||||
}
|
||||
|
||||
public virtual async void Delete(K key)
|
||||
|
|
|
|||
|
|
@ -77,9 +77,14 @@ namespace BookAStar.Model.Workflow
|
|||
return Bill?.Aggregate((decimal)0, (t, l) => t + l.Count * l.UnitaryCost) ?? (decimal)0;
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime LatestValidationDate { get; set; }
|
||||
/// <summary>
|
||||
/// This validation comes from the provider.
|
||||
/// As long as it's an estimate, no client validation
|
||||
/// is formaly needed
|
||||
/// </summary>
|
||||
public DateTime ProviderValidationDate { get; set; }
|
||||
|
||||
public DateTime ClientApprouvalDate { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:signature="clr-namespace:SignaturePad.Forms;assembly=SignaturePad.Forms"
|
||||
xmlns:views="clr-namespace:BookAStar.Views;assembly=BookAStar"
|
||||
x:Class="BookAStar.ViewModels.Signing.DocSigning">
|
||||
x:Class="BookAStar.ViewModels.Signing.Signing">
|
||||
<StackLayout>
|
||||
<views:MarkdownView x:Name="mdView"
|
||||
Editable="False"
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ using Xamarin.Forms;
|
|||
|
||||
namespace BookAStar.ViewModels.Signing
|
||||
{
|
||||
public partial class DocSigning : ContentPage
|
||||
public partial class Signing : ContentPage
|
||||
{
|
||||
public DocSigning()
|
||||
public Signing()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,9 +45,9 @@
|
|||
<Label Text="Description de la ligne de facture"
|
||||
Style="{StaticResource InputLabelStyle}"></Label>
|
||||
<StackLayout Orientation="Horizontal" VerticalOptions="FillAndExpand">
|
||||
<Editor HorizontalOptions="FillAndExpand" Text="{Binding Description, Mode=TwoWay}">
|
||||
<Editor HorizontalOptions="FillAndExpand" Text="{Binding Description, Mode=TwoWay}">
|
||||
<Editor.Behaviors>
|
||||
<behaviors:EditorMaxLengthValidator x:Name="descriptionValidator" MaxLength="512" />
|
||||
<behaviors:EditorMaxLengthValidator x:Name="descriptionLenValidator" MaxLength="512" MinLength="3" />
|
||||
</Editor.Behaviors>
|
||||
</Editor>
|
||||
</StackLayout>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
x:Class="BookAStar.Pages.EditEstimatePage"
|
||||
xmlns:views="clr-namespace:BookAStar.Views;assembly=BookAStar"
|
||||
xmlns:local="clr-namespace:BookAStar;assembly=BookAStar"
|
||||
xmlns:behaviors="clr-namespace:BookAStar.Behaviors;assembly=BookAStar"
|
||||
Style="{StaticResource PageStyle}">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
|
|
@ -36,7 +37,12 @@
|
|||
Editable="True"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
Markdown="{Binding Description, Mode=TwoWay}"
|
||||
VerticalOptions="Start" />
|
||||
VerticalOptions="Start" >
|
||||
<views:MarkdownView.Behaviors>
|
||||
<behaviors:MarkdownViewLengthValidator x:Name="descriptionLenValidator" MaxLength="512" MinLength="3" />
|
||||
|
||||
</views:MarkdownView.Behaviors>
|
||||
</views:MarkdownView>
|
||||
<StackLayout x:Name="biAnVaLayout">
|
||||
<ListView x:Name="BillListView" ItemsSource="{Binding Bill}"
|
||||
MinimumHeightRequest="40" HasUnevenRows="true" VerticalOptions="FillAndExpand"
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ using Xamarin.Forms;
|
|||
namespace BookAStar.Pages
|
||||
{
|
||||
using Data;
|
||||
using EstimatePages;
|
||||
using Model.Workflow;
|
||||
using ViewModels.EstimateAndBilling;
|
||||
using ViewModels.Signing;
|
||||
|
||||
public partial class EditEstimatePage : ContentPage
|
||||
{
|
||||
|
|
@ -46,54 +48,46 @@ namespace BookAStar.Pages
|
|||
var bill = ((EditEstimateViewModel)BindingContext).Bill;
|
||||
var lineView = new BillingLineViewModel(com)
|
||||
{ ValidateCommand = new Command(() => {
|
||||
bill.Add(com);
|
||||
bill.Add(new BillingLineViewModel(com));
|
||||
DataManager.Current.EstimationCache.SaveEntity();
|
||||
})};
|
||||
lineView.PropertyChanged += LineView_PropertyChanged;
|
||||
App.NavigationService.NavigateTo<EditBillingLinePage>(
|
||||
true, lineView );
|
||||
}
|
||||
protected void OnEditLine(object sender, ItemTappedEventArgs e)
|
||||
{
|
||||
var line = (BillingLine)e.Item;
|
||||
var bill = ((EditEstimateViewModel)BindingContext).Bill;
|
||||
var lineView = new BillingLineViewModel(line)
|
||||
var line = (BillingLineViewModel)e.Item;
|
||||
line.ValidateCommand = new Command(() =>
|
||||
{
|
||||
ValidateCommand = new Command(() => {
|
||||
DataManager.Current.EstimationCache.SaveEntity();
|
||||
})
|
||||
};
|
||||
lineView.PropertyChanged += LineView_PropertyChanged;
|
||||
DataManager.Current.EstimationCache.SaveEntity();
|
||||
});
|
||||
|
||||
lineView.PropertyChanged += LineView_PropertyChanged;
|
||||
App.NavigationService.NavigateTo<EditBillingLinePage>(
|
||||
true, lineView );
|
||||
true, line );
|
||||
}
|
||||
|
||||
|
||||
private void LineView_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
protected async void OnEstimateValidated(object sender, EventArgs e)
|
||||
{
|
||||
DataManager.Current.EstimationCache.SaveEntity();
|
||||
}
|
||||
|
||||
protected void OnEstimateValidated(object sender, EventArgs e)
|
||||
{
|
||||
var evm = (EditEstimateViewModel)BindingContext;
|
||||
if (evm.Data.Id == 0)
|
||||
var thisPage = this;
|
||||
var evm = (EditEstimateViewModel) BindingContext;
|
||||
var cmd = new Command<bool>( async (validated) =>
|
||||
{
|
||||
DataManager.Current.Estimates.Create(evm.Data);
|
||||
// we have to manually add this item in our local collection,
|
||||
// since we could prefer to update the whole collection
|
||||
// from server, or whatever other scenario
|
||||
DataManager.Current.Estimates.Add(evm.Data);
|
||||
} else
|
||||
if (validated) {
|
||||
DataManager.Current.EstimationCache.Remove(evm);
|
||||
DataManager.Current.EstimationCache.SaveEntity();
|
||||
}
|
||||
await thisPage.Navigation.PopAsync();
|
||||
});
|
||||
var response = await App.DisplayActionSheet(Strings.SignOrNot, Strings.DonotsignEstimate, Strings.CancelValidation, new string[] { Strings.Sign });
|
||||
if (response == Strings.Sign)
|
||||
{
|
||||
DataManager.Current.Estimates.Update(evm.Data);
|
||||
App.NavigationService.NavigateTo<EstimateSigningPage>(true,
|
||||
new EstimateSigningViewModel(evm.Data) { ValidationCommand = cmd });
|
||||
}
|
||||
DataManager.Current.Estimates.SaveEntity();
|
||||
DataManager.Current.EstimationCache.Remove(evm);
|
||||
DataManager.Current.EstimationCache.SaveEntity();
|
||||
Navigation.PopAsync();
|
||||
else if (response == Strings.CancelValidation)
|
||||
return;
|
||||
else cmd.Execute(true);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:signature="clr-namespace:SignaturePad.Forms;assembly=SignaturePad.Forms"
|
||||
xmlns:views="clr-namespace:BookAStar.Views;assembly=BookAStar"
|
||||
x:Class="BookAStar.Pages.EstimatePages.EstimateSigningPage">
|
||||
|
||||
|
||||
<ContentPage.Content>
|
||||
<StackLayout Padding="10,10,10,10" x:Name="mainLayout">
|
||||
<ScrollView>
|
||||
<StackLayout>
|
||||
<Grid MinimumHeightRequest="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="2*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Row="0" Grid.Column="0" Text="{Binding Client.UserName}" ></Label>
|
||||
<Label Grid.Row="0" Grid.Column="1" Text="{Binding Query.Location.Address}" ></Label>
|
||||
<Label Grid.Row="0" Grid.Column="2" Text="{Binding Query.EventDate, StringFormat='{0:dddd d MMMM yyyy à hh:mm}'}" ></Label>
|
||||
</Grid>
|
||||
|
||||
<Label Text="{Binding Title}" />
|
||||
|
||||
<views:MarkdownView x:Name="mdview"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
Markdown="{Binding Description}"
|
||||
/>
|
||||
<ListView x:Name="billListView" ItemsSource="{Binding Bill}"
|
||||
MinimumHeightRequest="40" HasUnevenRows="true" VerticalOptions="FillAndExpand"
|
||||
HeightRequest="40" >
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate >
|
||||
<ViewCell>
|
||||
<ViewCell.View>
|
||||
<Grid MinimumHeightRequest="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width="90" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Text="{Binding Description}"
|
||||
Grid.Row="0" Grid.Column="0" ></Label>
|
||||
<Label Text="{Binding Duration, StringFormat=\{0\}}"
|
||||
Grid.Row="0" Grid.Column="1" ></Label>
|
||||
<Label Text="{Binding Count}"
|
||||
Grid.Row="0" Grid.Column="2" ></Label>
|
||||
<Label Text="{Binding UnitaryCost}"
|
||||
Grid.Row="0" Grid.Column="3"
|
||||
FontFamily="Monospace"></Label>
|
||||
</Grid>
|
||||
</ViewCell.View>
|
||||
</ViewCell>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<Label FormattedText="{Binding FormattedTotal}"/>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
<signature:SignaturePadView x:Name="padView"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
BackgroundColor="White"
|
||||
CaptionText="Caption This" CaptionTextColor="Black"
|
||||
ClearText="Clear Me!" ClearTextColor="Red"
|
||||
PromptText="Prompt Here" PromptTextColor="Red"
|
||||
SignatureLineColor="Aqua" StrokeColor="Black" StrokeWidth="2" />
|
||||
<Button Clicked="OnValidate" Text="Valider cette signature" x:Name="btnValidate" />
|
||||
|
||||
</StackLayout>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
using SignaturePad.Forms;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace BookAStar.Pages.EstimatePages
|
||||
{
|
||||
using Data;
|
||||
using ViewModels.EstimateAndBilling;
|
||||
using ViewModels.Signing;
|
||||
|
||||
public partial class EstimateSigningPage : ContentPage
|
||||
{
|
||||
|
||||
public EstimateSigningPage(EstimateSigningViewModel model)
|
||||
{
|
||||
InitializeComponent();
|
||||
BindingContext = model;
|
||||
}
|
||||
|
||||
private async void OnValidate (object sender, EventArgs ev)
|
||||
{
|
||||
btnValidate.IsEnabled = false;
|
||||
if (DataManager.Current.Estimates.IsExecuting)
|
||||
{
|
||||
await App.DisplayAlert(Strings.OperationPending, Strings.oups);
|
||||
return;
|
||||
}
|
||||
|
||||
var evm = (EditEstimateViewModel)BindingContext;
|
||||
var estimate = evm.Data;
|
||||
var pngStream = await padView.GetImageStreamAsync(SignatureImageFormat.Png);
|
||||
pngStream.Seek(0, SeekOrigin.Begin);
|
||||
DataManager.Current.Estimates.SignAsProvider(estimate, pngStream);
|
||||
DataManager.Current.Estimates.SaveEntity();
|
||||
await Navigation.PopAsync();
|
||||
|
||||
var ParentValidationCommand = ((EstimateSigningViewModel)BindingContext).ValidationCommand;
|
||||
if (ParentValidationCommand != null)
|
||||
ParentValidationCommand.Execute(true);
|
||||
}
|
||||
|
||||
private async void OnGetStats(object sender, EventArgs e)
|
||||
{
|
||||
var points = padView.Points.ToArray();
|
||||
using (var image = await padView.GetImageStreamAsync(SignatureImageFormat.Png))
|
||||
{
|
||||
var pointCount = points.Count();
|
||||
var imageSize = image.Length / 1000;
|
||||
var linesCount = points.Count(p => p == Point.Zero) + (points.Length > 0 ? 1 : 0);
|
||||
await DisplayAlert("Stats", $"The signature has {linesCount} lines or {pointCount} points, and is {imageSize:#,###.0}KB (in memory) when saved as a PNG.", "Cool");
|
||||
}
|
||||
}
|
||||
private async void OnChangeTheme(object sender, EventArgs e)
|
||||
{
|
||||
var action = await DisplayActionSheet("Change Theme", "Cancel", null, "White", "Black", "Aqua");
|
||||
switch (action)
|
||||
{
|
||||
case "White":
|
||||
padView.BackgroundColor = Color.White;
|
||||
padView.StrokeColor = Color.Black;
|
||||
padView.ClearTextColor = Color.Black;
|
||||
padView.ClearText = "Clear Markers";
|
||||
break;
|
||||
|
||||
case "Black":
|
||||
padView.BackgroundColor = Color.Black;
|
||||
padView.StrokeColor = Color.White;
|
||||
padView.ClearTextColor = Color.White;
|
||||
padView.ClearText = "Clear Chalk";
|
||||
break;
|
||||
|
||||
case "Aqua":
|
||||
padView.BackgroundColor = Color.Aqua;
|
||||
padView.StrokeColor = Color.Red;
|
||||
padView.ClearTextColor = Color.Black;
|
||||
padView.ClearText = "Clear The Aqua";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,9 +33,6 @@
|
|||
</Grid>
|
||||
|
||||
<Label Text="{Binding Title}" />
|
||||
|
||||
<Label Text="{Binding Description}" />
|
||||
|
||||
<views:MarkdownView x:Name="mdview"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
Markdown="{Binding Description}"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
|
||||
using BookAStar.ViewModels.UserProfile;
|
||||
using Plugin.Media;
|
||||
using Plugin.Media.Abstractions;
|
||||
using System;
|
||||
|
||||
using Xamarin.Forms;
|
||||
|
|
@ -14,9 +16,31 @@ namespace BookAStar.Pages.UserProfile
|
|||
AvatarButton.Clicked += AvatarButton_Clicked;
|
||||
}
|
||||
|
||||
private void AvatarButton_Clicked (object sender, EventArgs e)
|
||||
private async void AvatarButton_Clicked (object sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
|
||||
{
|
||||
DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
|
||||
{
|
||||
Directory = "Sample",
|
||||
Name = "test.jpg"
|
||||
});
|
||||
|
||||
if (file == null)
|
||||
return;
|
||||
|
||||
await DisplayAlert("File Location", file.Path, "OK");
|
||||
AvatarButton.Image.File = file.Path;
|
||||
/* ImageSource.FromStream(() =>
|
||||
{
|
||||
var stream = file.GetStream();
|
||||
file.Dispose();
|
||||
return stream;
|
||||
}); */
|
||||
}
|
||||
|
||||
public void OnManageFiles(object sender, EventArgs e)
|
||||
|
|
|
|||
92
BookAStar/BookAStar/Strings.Designer.cs
generated
92
BookAStar/BookAStar/Strings.Designer.cs
generated
|
|
@ -61,6 +61,33 @@ namespace BookAStar {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Une execution est déjà en cours.
|
||||
/// </summary>
|
||||
public static string AlreadyExecuting {
|
||||
get {
|
||||
return ResourceManager.GetString("AlreadyExecuting", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Annuler la validation.
|
||||
/// </summary>
|
||||
public static string CancelValidation {
|
||||
get {
|
||||
return ResourceManager.GetString("CancelValidation", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à La création a échoué, contenu envoyé: {stringContent} @ Uri: {ControllerUri.AbsoluteUri}: Erreur : {errcontent}.
|
||||
/// </summary>
|
||||
public static string CreationFailed {
|
||||
get {
|
||||
return ResourceManager.GetString("CreationFailed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Faire un devis.
|
||||
/// </summary>
|
||||
|
|
@ -70,6 +97,15 @@ namespace BookAStar {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Valider le devis sans signer.
|
||||
/// </summary>
|
||||
public static string DonotsignEstimate {
|
||||
get {
|
||||
return ResourceManager.GetString("DonotsignEstimate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Editer le devis.
|
||||
/// </summary>
|
||||
|
|
@ -79,6 +115,15 @@ namespace BookAStar {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Erreur d'accès aux données distantes.
|
||||
/// </summary>
|
||||
public static string ENoRemoteEntity {
|
||||
get {
|
||||
return ResourceManager.GetString("ENoRemoteEntity", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Star.
|
||||
/// </summary>
|
||||
|
|
@ -115,6 +160,42 @@ namespace BookAStar {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Opération en cours.
|
||||
/// </summary>
|
||||
public static string OperationPending {
|
||||
get {
|
||||
return ResourceManager.GetString("OperationPending", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à oups..
|
||||
/// </summary>
|
||||
public static string oups {
|
||||
get {
|
||||
return ResourceManager.GetString("oups", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Signer.
|
||||
/// </summary>
|
||||
public static string Sign {
|
||||
get {
|
||||
return ResourceManager.GetString("Sign", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Signer le devis?.
|
||||
/// </summary>
|
||||
public static string SignOrNot {
|
||||
get {
|
||||
return ResourceManager.GetString("SignOrNot", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Incontournable.
|
||||
/// </summary>
|
||||
|
|
@ -134,7 +215,16 @@ namespace BookAStar {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Voir le devis.
|
||||
/// Recherche une chaîne localisée semblable à La mise à jour a échoué..
|
||||
/// </summary>
|
||||
public static string UpdateFailed {
|
||||
get {
|
||||
return ResourceManager.GetString("UpdateFailed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Voir les devis validés.
|
||||
/// </summary>
|
||||
public static string ViewEstimate {
|
||||
get {
|
||||
|
|
|
|||
|
|
@ -117,9 +117,15 @@
|
|||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="AlreadyExecuting" xml:space="preserve">
|
||||
<value>Une execution est déjà en cours</value>
|
||||
</data>
|
||||
<data name="CancelValidation" xml:space="preserve">
|
||||
<value>Annuler la validation</value>
|
||||
</data>
|
||||
<data name="CreationFailed" xml:space="preserve">
|
||||
<value>La création a échoué, contenu envoyé: {stringContent} @ Uri: {ControllerUri.AbsoluteUri}: Erreur : {errcontent}</value>
|
||||
</data>
|
||||
<data name="DoEstimate" xml:space="preserve">
|
||||
<value>Faire un devis</value>
|
||||
</data>
|
||||
|
|
@ -129,6 +135,9 @@
|
|||
<data name="EditEstimate" xml:space="preserve">
|
||||
<value>Editer le devis</value>
|
||||
</data>
|
||||
<data name="ENoRemoteEntity" xml:space="preserve">
|
||||
<value>Erreur d'accès aux données distantes</value>
|
||||
</data>
|
||||
<data name="FiveStars" xml:space="preserve">
|
||||
<value>Star</value>
|
||||
<comment>Da star, da one</comment>
|
||||
|
|
@ -143,6 +152,12 @@
|
|||
<data name="OneStar" xml:space="preserve">
|
||||
<value>Étoile montante</value>
|
||||
</data>
|
||||
<data name="OperationPending" xml:space="preserve">
|
||||
<value>Opération en cours</value>
|
||||
</data>
|
||||
<data name="oups" xml:space="preserve">
|
||||
<value>oups.</value>
|
||||
</data>
|
||||
<data name="Sign" xml:space="preserve">
|
||||
<value>Signer</value>
|
||||
</data>
|
||||
|
|
@ -158,4 +173,7 @@
|
|||
<data name="ViewEstimate" xml:space="preserve">
|
||||
<value>Voir les devis validés</value>
|
||||
</data>
|
||||
<data name="UpdateFailed" xml:space="preserve">
|
||||
<value>La mise à jour a échoué.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -14,16 +14,43 @@ namespace BookAStar.ViewModels
|
|||
/// </summary>
|
||||
public class EditingViewModel: ViewModel
|
||||
{
|
||||
private LocalState state;
|
||||
public LocalState State {
|
||||
bool existsRemotely;
|
||||
public bool ExistsRemotely
|
||||
{
|
||||
get
|
||||
{
|
||||
return state;
|
||||
return existsRemotely;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetProperty<LocalState>(ref state, value);
|
||||
base.SetProperty<bool>(ref existsRemotely, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isValid;
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
return isValid;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetProperty<bool>(ref isValid, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool isDirty;
|
||||
public bool IsDirty
|
||||
{
|
||||
get
|
||||
{
|
||||
return isDirty;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetProperty<bool>(ref isDirty, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,7 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
|
||||
public BillingLineViewModel(BillingLine data)
|
||||
{
|
||||
this.data = data ?? new BillingLine();
|
||||
// sets durationValue & durationUnit
|
||||
count = data.Count;
|
||||
description = data.Description;
|
||||
|
||||
Duration = data.Duration;
|
||||
unitaryCostText = data.UnitaryCost.ToString("G", CultureInfo.InvariantCulture);
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
private int count;
|
||||
|
|
@ -48,6 +42,7 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
{
|
||||
SetProperty<string>(ref description, value);
|
||||
data.Description = description;
|
||||
IsValid = !string.IsNullOrWhiteSpace(description);
|
||||
}
|
||||
}
|
||||
decimal unitaryCost;
|
||||
|
|
@ -166,5 +161,26 @@ pour décrire la quantité de travail associée à ce type de service")]
|
|||
}
|
||||
}
|
||||
|
||||
public BillingLine Data
|
||||
{
|
||||
get
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
SetProperty<BillingLine>(ref data, value);
|
||||
if (data != null)
|
||||
{
|
||||
// sets durationValue & durationUnit
|
||||
count = data.Count;
|
||||
description = data.Description;
|
||||
|
||||
Duration = data.Duration;
|
||||
unitaryCostText = data.UnitaryCost.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using BookAStar.Model;
|
|||
using Xamarin.Forms;
|
||||
using BookAStar.Data;
|
||||
using Newtonsoft.Json;
|
||||
using System.Linq;
|
||||
|
||||
namespace BookAStar.ViewModels.EstimateAndBilling
|
||||
{
|
||||
|
|
@ -17,6 +18,7 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a new view model on estimate,
|
||||
/// sets <c>Data</c> with given value parameter
|
||||
|
|
@ -28,12 +30,18 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
Data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void Bill_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
Data.Bill = new List<BillingLine>( Bill );
|
||||
Data.Bill = Bill.Select(l => l.Data).ToList();
|
||||
NotifyPropertyChanged("FormattedTotal");
|
||||
NotifyPropertyChanged("Bill");
|
||||
}
|
||||
|
||||
private Estimate data;
|
||||
public Estimate Data { get { return data; } set {
|
||||
SetProperty<Estimate>(ref data, value);
|
||||
|
|
@ -42,7 +50,9 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
if (data.Bill == null) data.Bill = new List<BillingLine>();
|
||||
AttachedFiles = new ObservableCollection<string>(data.AttachedFiles);
|
||||
AttachedGraphicList = new ObservableCollection<string>(data.AttachedGraphics);
|
||||
Bill = new ObservableCollection<BillingLine>(data.Bill);
|
||||
Bill = new ObservableCollection<BillingLineViewModel>(data.Bill.Select(
|
||||
l => new BillingLineViewModel(l)
|
||||
));
|
||||
Bill.CollectionChanged += Bill_CollectionChanged;
|
||||
Title = Data.Title;
|
||||
Description = Data.Description;
|
||||
|
|
@ -64,7 +74,7 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public ObservableCollection<BillingLine> Bill
|
||||
public ObservableCollection<BillingLineViewModel> Bill
|
||||
{
|
||||
get; protected set;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using XLabs.Forms.Mvvm;
|
||||
|
||||
namespace BookAStar.ViewModels.Signing
|
||||
{
|
||||
class DocSigningViewModel: ViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The doc to sign, in Markdown format
|
||||
/// </summary>
|
||||
public string Document { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using BookAStar.Model.Workflow;
|
||||
using BookAStar.ViewModels.EstimateAndBilling;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace BookAStar.ViewModels.Signing
|
||||
{
|
||||
public class EstimateSigningViewModel: EditEstimateViewModel
|
||||
{
|
||||
public EstimateSigningViewModel(Estimate document)
|
||||
{
|
||||
Data = document;
|
||||
}
|
||||
public Command<bool> ValidationCommand { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -26,13 +26,14 @@ namespace BookAStar.Views
|
|||
}
|
||||
set
|
||||
{
|
||||
var oldValue = Markdown;
|
||||
if (Markdown != value)
|
||||
{
|
||||
SetValue(MarkdownProperty, value);
|
||||
|
||||
if (Modified != null)
|
||||
{
|
||||
Modified.Invoke(this, new EventArgs());
|
||||
Modified.Invoke(this, new TextChangedEventArgs(oldValue, Markdown));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +47,7 @@ namespace BookAStar.Views
|
|||
set { SetValue (EditableProperty, value); }
|
||||
}
|
||||
|
||||
public event EventHandler<EventArgs> Modified;
|
||||
public event EventHandler<TextChangedEventArgs> Modified;
|
||||
|
||||
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue