fixes edition cache

main
Paul Schneider 9 years ago
parent cd589a69a6
commit 18d0aba837
24 changed files with 269 additions and 102 deletions

@ -107,7 +107,7 @@ namespace BookAStar.Droid
LoadApplication(fapp); LoadApplication(fapp);
CheckSharing(); var componentName = StartService(new Intent(this, typeof(YavscChooserTargetService)));
// TabLayoutResource = Resource.Layout.Tabbar; // TabLayoutResource = Resource.Layout.Tabbar;
// ToolbarResource = Resource.Layout.Toolbar; // ToolbarResource = Resource.Layout.Toolbar;

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="fr.pschneider.bas" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="fr.pschneider.bas" android:installLocation="auto">
<uses-sdk android:minSdkVersion="15" /> <uses-sdk android:minSdkVersion="15" />
<application android:label="BookAStar" android:icon="@drawable/icon" android:theme="@style/MainTheme"> <application android:allowBackup="true" android:label="Booking Star" android:icon="@drawable/icon" android:theme="@style/MainTheme">
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBLSEDhZixwpHDsWmO2pKwgGDJReoTuQ7A" /> <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBLSEDhZixwpHDsWmO2pKwgGDJReoTuQ7A" />
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
<receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND"> <receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
@ -17,21 +17,19 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<service android:name="fr.pschneider.bas.YavscChooserTargetService"
android:label="@string/app_name"
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
<intent-filter>
<action android:name="android.service.chooser.ChooserTargetService" />
</intent-filter>
</service>
<activity android:name="fr.pschneider.bas.SendFilesActivity" android:label="@string/app_name"> <activity android:name="fr.pschneider.bas.SendFilesActivity" android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" /> <!-- <data android:mimeType="text/plain" /> -->
</intent-filter> </intent-filter>
<meta-data android:name="android.service.chooser.chooser_target_service" android:value="fr.pschneider.bas.YavscChooserTargetService" /> <meta-data android:name="android.service.chooser.chooser_target_service" android:value="fr.pschneider.bas.YavscChooserTargetService" />
</activity> </activity>
<service android:name="fr.pschneider.bas.YavscChooserTargetService" android:label="@string/app_name" android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
<intent-filter>
<action android:name="android.service.chooser.ChooserTargetService" />
</intent-filter>
</service>
</application> </application>
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAVE_LOCK" /> <uses-permission android:name="android.permission.WAVE_LOCK" />

@ -10,10 +10,19 @@ using Android.Runtime;
using Android.Views; using Android.Views;
using Android.Widget; using Android.Widget;
using Android.Service.Chooser; using Android.Service.Chooser;
using static Android.Manifest;
namespace BookAStar.Droid namespace BookAStar.Droid
{ {
[Service(Name = "fr.pschneider.bas.YavscChooserTargetService", Label = "Yavsc share service", Permission = "android.permission.BIND_CHOOSER_TARGET_SERVICE", Icon = "@drawable/icon", Exported = true)] [Service(
Name = "fr.pschneider.bas.YavscChooserTargetService",
Label = "Yavsc share service",
Permission = Permission.BindChooserTargetService,
Icon = "@drawable/icon",
Exported = true,
Enabled = true
)]
[IntentFilter(new String[] { "android.service.chooser.ChooserTargetService" })]
class YavscChooserTargetService : ChooserTargetService class YavscChooserTargetService : ChooserTargetService
{ {
public override IList<ChooserTarget> OnGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) public override IList<ChooserTarget> OnGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter)
@ -24,7 +33,7 @@ namespace BookAStar.Droid
ChooserTarget t = new ChooserTarget( ChooserTarget t = new ChooserTarget(
new Java.Lang.String( new Java.Lang.String(
"BookingStar"), i, "BookingStar"), i,
.5f, new ComponentName(this.BaseContext, ".SendFilesActivity"), .5f, new ComponentName(this, "BookAStar.SendFilesActivity"),
null); null);
var res = new List<ChooserTarget>(); var res = new List<ChooserTarget>();
res.Add(t); res.Add(t);
@ -35,10 +44,5 @@ namespace BookAStar.Droid
{ {
return base.OnBind(intent); return base.OnBind(intent);
} }
public override void OnCreate()
{
base.OnCreate();
}
} }
} }

@ -23,7 +23,7 @@
<OnPlatform x:TypeArguments="Font" Android="Large" iOS="Large" WinPhone="Large" x:Key="HeaderFont" /> <OnPlatform x:TypeArguments="Font" Android="Large" iOS="Large" WinPhone="Large" x:Key="HeaderFont" />
<OnPlatform x:TypeArguments="Color" Android="Red" iOS="Red" WinPhone="Red" x:Key="EmphasisTextColor" /> <OnPlatform x:TypeArguments="Color" Android="Red" iOS="Red" WinPhone="Red" x:Key="EmphasisTextColor" />
<OnPlatform x:TypeArguments="Font" Android="60" iOS="60" WinPhone="60" x:Key="LargeFontSize" /> <OnPlatform x:TypeArguments="Font" Android="90" iOS="90" WinPhone="90" x:Key="LargeFontSize" />
<OnPlatform x:TypeArguments="Font" Android="50" iOS="50" WinPhone="50" x:Key="MediumFontSize" /> <OnPlatform x:TypeArguments="Font" Android="50" iOS="50" WinPhone="50" x:Key="MediumFontSize" />
<OnPlatform x:TypeArguments="Font" Android="40" iOS="40" WinPhone="40" x:Key="SmallFontSize" /> <OnPlatform x:TypeArguments="Font" Android="40" iOS="40" WinPhone="40" x:Key="SmallFontSize" />
<OnPlatform x:TypeArguments="x:Double" Android="130" iOS="130" WinPhone="130" x:Key="BigUserAvatarSize" /> <OnPlatform x:TypeArguments="x:Double" Android="130" iOS="130" WinPhone="130" x:Key="BigUserAvatarSize" />

@ -85,6 +85,7 @@ namespace BookAStar
{ {
// TODO save the navigation stack // TODO save the navigation stack
int position = 0; int position = 0;
foreach (Page page in MainPage.Navigation.NavigationStack) foreach (Page page in MainPage.Navigation.NavigationStack)
{ {

@ -48,7 +48,9 @@
<Compile Include="Behaviors\PickerBehavior.cs" /> <Compile Include="Behaviors\PickerBehavior.cs" />
<Compile Include="Behaviors\StarBehavior.cs" /> <Compile Include="Behaviors\StarBehavior.cs" />
<Compile Include="Constants.cs" /> <Compile Include="Constants.cs" />
<Compile Include="Data\LocalState.cs" />
<Compile Include="Model\UI\PageState.cs" /> <Compile Include="Model\UI\PageState.cs" />
<Compile Include="ViewModels\EditingViewModel.cs" />
<Compile Include="Views\EnumPicker.cs" /> <Compile Include="Views\EnumPicker.cs" />
<Compile Include="Converters\BooleanToObjectConverter.cs" /> <Compile Include="Converters\BooleanToObjectConverter.cs" />
<Compile Include="Converters\EnumConverter.cs" /> <Compile Include="Converters\EnumConverter.cs" />

@ -1,11 +1,10 @@
using System.Threading.Tasks; namespace BookAStar.Data
namespace BookAStar.Data
{ {
using Model; using Model;
using Model.Blog; using Model.Blog;
using Model.Workflow; using Model.Workflow;
using Model.UI; using Model.UI;
using ViewModels;
public class DataManager public class DataManager
{ {
@ -15,11 +14,20 @@ namespace BookAStar.Data
public RemoteEntity<Blog, long> Blogspot { get; set; } public RemoteEntity<Blog, long> Blogspot { get; set; }
public LocalEntity<ClientProviderInfo,string> Contacts { get; set; } public LocalEntity<ClientProviderInfo,string> Contacts { get; set; }
internal LocalEntity<PageState, int> AppState { get; set; } internal LocalEntity<PageState, int> AppState { get; set; }
protected static DataManager current = new DataManager(); /// <summary>
/// They have no remote exisence ...
/// </summary>
internal LocalEntity<EditEstimateViewModel, long> EstimationCache { get; set; }
internal LocalEntity<BillingLine, string> EstimateLinesTemplates { get; set; }
protected static DataManager current ;
public static DataManager Current public static DataManager Current
{ {
get get
{ {
if (current == null)
current = new DataManager();
return current; return current;
} }
} }
@ -34,17 +42,17 @@ namespace BookAStar.Data
x=>x.Id); x=>x.Id);
Contacts = new LocalEntity<ClientProviderInfo, string>(c => c.UserId); Contacts = new LocalEntity<ClientProviderInfo, string>(c => c.UserId);
AppState = new LocalEntity<PageState, int>(s => s.Position); AppState = new LocalEntity<PageState, int>(s => s.Position);
EstimationCache = new LocalEntity<EditEstimateViewModel, long>(
e => e.Query.Id);
EstimateLinesTemplates = new LocalEntity<BillingLine, string>(
l => l.Description);
BookQueries.Load(); BookQueries.Load();
Estimates.Load(); Estimates.Load();
Blogspot.Load(); Blogspot.Load();
Contacts.Load(); Contacts.Load();
AppState.Load(); AppState.Load();
} EstimationCache.Load();
EstimateLinesTemplates.Load();
public async Task<BookQueryData> GetBookQuery(long bookQueryId)
{
return await BookQueries.Get(bookQueryId);
} }
} }
} }

@ -32,6 +32,8 @@ namespace BookAStar.Data
public V LocalGet(K key) public V LocalGet(K key)
{ {
if (!this.Any(x => GetKey(x).Equals(key)))
return default(V);
CurrentItem = this.Single(x => GetKey(x).Equals(key)); CurrentItem = this.Single(x => GetKey(x).Equals(key));
return CurrentItem; return CurrentItem;
} }

@ -0,0 +1,16 @@
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
}
}

@ -10,7 +10,7 @@ namespace BookAStar.Data
{ {
using Helpers; using Helpers;
public class RemoteEntity<V,K> : LocalEntity<V, K>, ICommand where K : IEquatable<K> public class RemoteEntity<V, K> : LocalEntity<V, K>, ICommand where K : IEquatable<K>
{ {
private string _controller; private string _controller;
public event EventHandler CanExecuteChanged; public event EventHandler CanExecuteChanged;
@ -22,7 +22,7 @@ namespace BookAStar.Data
return !IsExecuting && (MainSettings.CurrentUser != null); return !IsExecuting && (MainSettings.CurrentUser != null);
} }
public RemoteEntity(string controllerName, Func<V,K> getKey):base(getKey) public RemoteEntity(string controllerName, Func<V, K> getKey) : base(getKey)
{ {
if (string.IsNullOrWhiteSpace(controllerName)) if (string.IsNullOrWhiteSpace(controllerName))
throw new InvalidOperationException(); throw new InvalidOperationException();
@ -35,6 +35,7 @@ namespace BookAStar.Data
if (IsExecuting) if (IsExecuting)
throw new InvalidOperationException("Already executing"); throw new InvalidOperationException("Already executing");
IsExecuting = true; IsExecuting = true;
if (CanExecuteChanged != null)
CanExecuteChanged.Invoke(this, new EventArgs()); CanExecuteChanged.Invoke(this, new EventArgs());
} }
@ -65,7 +66,8 @@ namespace BookAStar.Data
} }
} }
} }
catch (WebException webex) { catch (WebException webex)
{
throw new ServiceNotAvailable("No remote entity", webex); throw new ServiceNotAvailable("No remote entity", webex);
} }
@ -76,13 +78,14 @@ namespace BookAStar.Data
private void AfterExecuting() private void AfterExecuting()
{ {
IsExecuting = false; IsExecuting = false;
if (CanExecuteChanged!=null)
CanExecuteChanged.Invoke(this, new EventArgs()); CanExecuteChanged.Invoke(this, new EventArgs());
} }
public async Task<V> Get(K key) public async Task<V> Get(K key)
{ {
var item = LocalGet(key); var item = LocalGet(key);
if (item==null) item = await RemoteGet(key); if (item == null) item = await RemoteGet(key);
CurrentItem = item; CurrentItem = item;
return CurrentItem; return CurrentItem;
} }
@ -92,9 +95,9 @@ namespace BookAStar.Data
V item = default(V); V item = default(V);
BeforeExecute(); BeforeExecute();
// Get the whole data // Get the whole data
var uri = new Uri(controllerUri.AbsolutePath+"/"+key.ToString()); var uri = new Uri(controllerUri.AbsoluteUri + "/" + key.ToString());
using (HttpClient client = new HttpClient()) using (HttpClient client = UserHelpers.CreateClient())
{ {
using (var response = await client.GetAsync(uri)) using (var response = await client.GetAsync(uri))
{ {
@ -112,5 +115,29 @@ namespace BookAStar.Data
return item; return item;
} }
public async void Create(V item)
{
BeforeExecute();
using (HttpClient client = UserHelpers.CreateClient())
{
HttpContent content = new StringContent(
JsonConvert.SerializeObject(item)
);
using (var response = await client.PostAsync(controllerUri, content))
{
if (!response.IsSuccessStatusCode)
// TODO throw custom exception, and catch to inform user
throw new Exception($"Create failed posting {item} @ {controllerUri.AbsolutePath}");
var recontent = await response.Content.ReadAsStringAsync();
JsonConvert.PopulateObject(recontent, item);
}
}
AfterExecuting();
CurrentItem = item;
}
} }
} }

@ -156,11 +156,13 @@ namespace BookAStar
if (olduserid != value.Id) if (olduserid != value.Id)
{ {
App.CurrentApp.PostDeviceInfo(); App.CurrentApp.PostDeviceInfo();
if (UserChanged!=null)
UserChanged.Invoke(App.CurrentApp, new EventArgs()); UserChanged.Invoke(App.CurrentApp, new EventArgs());
} }
} }
else if (olduserid != null) else if (olduserid != null)
{ {
if (UserChanged != null)
UserChanged.Invoke(App.CurrentApp, new EventArgs()); UserChanged.Invoke(App.CurrentApp, new EventArgs());
// TODO else Unregister this device // TODO else Unregister this device
} }
@ -267,7 +269,7 @@ namespace BookAStar
{ {
var key = $"{EntityDataSettingsPrefix}/{subKey}/{typeof(V).FullName}"; var key = $"{EntityDataSettingsPrefix}/{subKey}/{typeof(V).FullName}";
var data = AppSettings.GetValueOrDefault<string>(key, null); var data = AppSettings.GetValueOrDefault<string>(key, null);
if (data != null) if (!string.IsNullOrWhiteSpace(data))
{ {
var items = JsonConvert.DeserializeObject<IList<V>>(data); var items = JsonConvert.DeserializeObject<IList<V>>(data);
if (items != null) if (items != null)

@ -1,4 +1,6 @@
namespace BookAStar.Model.UI using XLabs.Forms.Mvvm;
namespace BookAStar.Model.UI
{ {
internal class PageState internal class PageState
{ {

@ -1,6 +1,7 @@
using BookAStar.Data; using BookAStar.Data;
using BookAStar.Helpers; using BookAStar.Helpers;
using BookAStar.Model.Interfaces; using BookAStar.Model.Interfaces;
using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -24,7 +25,7 @@ namespace BookAStar.Model.Workflow
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public IList<string> AttachedGraphics { get; set; } public IList<string> AttachedGraphics { get; set; }
[JsonIgnore]
public string AttachedGraphicsString public string AttachedGraphicsString
{ {
get { return AttachedGraphics==null?null:string.Join(":", AttachedGraphics); } get { return AttachedGraphics==null?null:string.Join(":", AttachedGraphics); }
@ -38,6 +39,7 @@ namespace BookAStar.Model.Workflow
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public IList<string> AttachedFiles { get; set; } public IList<string> AttachedFiles { get; set; }
[JsonIgnore]
public string AttachedFilesString public string AttachedFilesString
{ {
get { return AttachedFiles == null ? null : string.Join(":", AttachedFiles); } get { return AttachedFiles == null ? null : string.Join(":", AttachedFiles); }
@ -47,19 +49,20 @@ namespace BookAStar.Model.Workflow
public string OwnerId { get; set; } public string OwnerId { get; set; }
public string ClientId { get; set; } public string ClientId { get; set; }
[JsonIgnore]
public BookQueryData Query public BookQueryData Query
{ {
get get
{ {
if (CommandId.HasValue) if (CommandId.HasValue)
{ {
return DataManager.Current.BookQueries.LocalGet(CommandId.Value); var dm = DataManager.Current;
return dm.BookQueries.LocalGet(CommandId.Value);
} }
return null; return null;
} }
} }
[JsonIgnore]
public ClientProviderInfo Client public ClientProviderInfo Client
{ {
get get
@ -68,7 +71,7 @@ namespace BookAStar.Model.Workflow
} }
} }
[JsonIgnore]
public decimal Total { get public decimal Total { get
{ {
return Bill?.Aggregate((decimal)0, (t, l) => t + l.Count * l.UnitaryCost) ?? (decimal)0; return Bill?.Aggregate((decimal)0, (t, l) => t + l.Count * l.UnitaryCost) ?? (decimal)0;

@ -27,7 +27,8 @@
</StackLayout> </StackLayout>
<StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" > <StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<maps:Map x:Name="map" VerticalOptions="FillAndExpand"></maps:Map> <maps:Map x:Name="map" VerticalOptions="FillAndExpand"></maps:Map>
<Button Text="Faire un devis" Clicked="MakeAnEstimate" VerticalOptions="End" />
<Button Text="{Binding EditEstimateButtonText}" Clicked="OnEditEstimate" />
</StackLayout> </StackLayout>
</StackLayout> </StackLayout>
</ContentPage> </ContentPage>

@ -16,11 +16,7 @@ namespace BookAStar.Pages
{ {
get get
{ {
return BindingContext as BookQueryData; return (BindingContext as BookQueryViewModel).Data;
}
set
{
BindingContext = value;
} }
} }
protected override void OnBindingContextChanged() protected override void OnBindingContextChanged()
@ -56,11 +52,13 @@ namespace BookAStar.Pages
// Task.Run( async () => { bookQuery = await App.CurrentApp.DataManager.BookQueries.Get(bookQueryId); }); // Task.Run( async () => { bookQuery = await App.CurrentApp.DataManager.BookQueries.Get(bookQueryId); });
BookQuery = bookQuery; BindingContext = new BookQueryViewModel(bookQuery);
} }
private void MakeAnEstimate(object sender, EventArgs ev) private void OnEditEstimate(object sender, EventArgs ev)
{
var viewModel = ((BookQueryViewModel)BindingContext).DraftEstimate;
if (viewModel == null)
{ {
DataManager.Current.Contacts.Merge(BookQuery.Client); DataManager.Current.Contacts.Merge(BookQuery.Client);
var e = new Estimate() var e = new Estimate()
@ -71,8 +69,11 @@ namespace BookAStar.Pages
Id = 0, Id = 0,
Description = "# **Hello Estimate!**" Description = "# **Hello Estimate!**"
}; };
viewModel = new EditEstimateViewModel(e, LocalState.New);
DataManager.Current.EstimationCache.Add(viewModel);
}
App.NavigationService.NavigateTo<EditEstimatePage>(true, App.NavigationService.NavigateTo<EditEstimatePage>(true,
new EditEstimateViewModel(e)); viewModel);
} }
protected override void OnSizeAllocated(double width, double height) protected override void OnSizeAllocated(double width, double height)

@ -21,9 +21,14 @@
<ScrollView> <ScrollView>
<StackLayout Orientation="Vertical" > <StackLayout Orientation="Vertical" >
<StackLayout> <StackLayout>
<lc:GesturesContentView ExcludeChildren="false" VisualElement.HeightRequest="{StaticResource BigUserAvatarSize}">
<StackLayout> <StackLayout>
<Label Text="{Binding UserName}" Style="{StaticResource LabelPageHeadingStyle}"
HorizontalTextAlignment="Center"
LineBreakMode="WordWrap" XAlign="Center"
></Label>
<Frame VisualElement.HeightRequest="{StaticResource BigUserAvatarSize}"> <Frame VisualElement.HeightRequest="{StaticResource BigUserAvatarSize}">
<lc:GesturesContentView ExcludeChildren="false" VisualElement.HeightRequest="{StaticResource BigUserAvatarSize}">
<lb:Gestures.Interests> <lb:Gestures.Interests>
<lb:GestureCollection> <lb:GestureCollection>
@ -35,15 +40,13 @@
<Image Source="{Binding Avatar}" Aspect="AspectFit" <Image Source="{Binding Avatar}" Aspect="AspectFit"
VisualElement.HeightRequest="{StaticResource BigUserAvatarSize}" /> VisualElement.HeightRequest="{StaticResource BigUserAvatarSize}" />
</lc:GesturesContentView>
</Frame> </Frame>
</StackLayout> </StackLayout>
</lc:GesturesContentView>
<views:RatingView Rating="{Binding Rating, Mode=TwoWay}" x:Name="ratingView"/> <views:RatingView Rating="{Binding Rating, Mode=TwoWay}" x:Name="ratingView"/>
<Label Text="{Binding UserName}" Style="{StaticResource LabelPageHeadingStyle}"
HorizontalTextAlignment="Center"
LineBreakMode="WordWrap" XAlign="Center"
></Label>
</StackLayout> </StackLayout>
<Button Text="{Binding PerformerStatus}" Clicked="OnViewPerformerStatus" /> <Button Text="{Binding PerformerStatus}" Clicked="OnViewPerformerStatus" />

@ -1,4 +1,5 @@
using BookAStar.ViewModels; using BookAStar.Data;
using BookAStar.ViewModels;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Xamarin.Forms; using Xamarin.Forms;
@ -18,7 +19,6 @@ namespace BookAStar.Pages
public void OnValidateClicked (object sender, EventArgs e) public void OnValidateClicked (object sender, EventArgs e)
{ {
this.Navigation.PopAsync(); this.Navigation.PopAsync();
} }
} }

@ -31,13 +31,12 @@
<Label Grid.Row="0" Grid.Column="1" Text="{Binding Query.Location.Address}" ></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> <Label Grid.Row="0" Grid.Column="2" Text="{Binding Query.EventDate, StringFormat='{0:dddd d MMMM yyyy à hh:mm}'}" ></Label>
</Grid> </Grid>
<Entry Placeholder="Saisissez un titre pour ce devis" Text="{Binding Title, Mode=TwoWay}" />
<views:MarkdownView x:Name="mdview" <views:MarkdownView x:Name="mdview"
Editable="True" Editable="True"
HorizontalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
Markdown="{Binding Description, Mode=TwoWay}" Markdown="{Binding Description, Mode=TwoWay}"
VerticalOptions="Start" VerticalOptions="Start" />
/>
<StackLayout x:Name="biAnVaLayout"> <StackLayout x:Name="biAnVaLayout">
<ListView x:Name="BillListView" ItemsSource="{Binding Bill}" <ListView x:Name="BillListView" ItemsSource="{Binding Bill}"
MinimumHeightRequest="40" HasUnevenRows="true" VerticalOptions="FillAndExpand" MinimumHeightRequest="40" HasUnevenRows="true" VerticalOptions="FillAndExpand"

@ -3,6 +3,7 @@ using Xamarin.Forms;
namespace BookAStar.Pages namespace BookAStar.Pages
{ {
using Data;
using Model.Workflow; using Model.Workflow;
using ViewModels; using ViewModels;
public partial class EditEstimatePage : ContentPage public partial class EditEstimatePage : ContentPage
@ -13,6 +14,16 @@ namespace BookAStar.Pages
InitializeComponent(); InitializeComponent();
BindingContext = model; BindingContext = model;
} }
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
((EditEstimateViewModel)BindingContext).PropertyChanged += EditEstimatePage_PropertyChanged;
}
private void EditEstimatePage_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
DataManager.Current.EstimationCache.SaveCollection();
}
protected override void OnSizeAllocated(double width, double height) protected override void OnSizeAllocated(double width, double height)
{ {
@ -45,7 +56,16 @@ namespace BookAStar.Pages
protected void OnEstimateValidated(object sender, EventArgs e) protected void OnEstimateValidated(object sender, EventArgs e)
{ {
throw new NotImplementedException(); var evm = (EditEstimateViewModel)BindingContext;
if (evm.State == LocalState.New)
{
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);
evm.State = LocalState.UpToDate;
}
} }
} }
} }

@ -9,7 +9,7 @@ using XLabs.Forms.Mvvm;
namespace BookAStar.ViewModels namespace BookAStar.ViewModels
{ {
public class BillingLineViewModel : ViewModel, IBillingLine public class BillingLineViewModel : EditingViewModel, IBillingLine
{ {
BillingLine data; BillingLine data;

@ -1,4 +1,5 @@
using BookAStar.Interfaces; using BookAStar.Data;
using BookAStar.Interfaces;
using BookAStar.Model; using BookAStar.Model;
using BookAStar.Model.Social; using BookAStar.Model.Social;
using System; using System;
@ -23,11 +24,34 @@ namespace BookAStar.ViewModels
Location = data.Location; Location = data.Location;
EventDate = data.EventDate; EventDate = data.EventDate;
Previsionnal = data.Previsionnal; Previsionnal = data.Previsionnal;
Id = data.Id;
this.data = data;
}
private BookQueryData data;
public BookQueryData Data {
get
{
return data;
}
} }
public ClientProviderInfo Client { get; set; } public ClientProviderInfo Client { get; set; }
public Location Location { get; set; } public Location Location { get; set; }
public long Id { get; set; } public long Id { get; set; }
public DateTime EventDate { get; set; } public DateTime EventDate { get; set; }
public decimal? Previsionnal { get; set; } public decimal? Previsionnal { get; set; }
public EditEstimateViewModel DraftEstimate
{
get
{
return DataManager.Current.EstimationCache.LocalGet(this.Id);
}
}
public string EditEstimateButtonText
{
get
{
return DraftEstimate != null ? "Editer le devis" : "Faire un devis" ;
}
}
} }
} }

@ -1,24 +1,32 @@
using System.Collections.Generic; using System.Collections.Generic;
using XLabs.Forms.Mvvm;
using BookAStar.Model.Workflow; using BookAStar.Model.Workflow;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using BookAStar.Model; using BookAStar.Model;
using Xamarin.Forms; using Xamarin.Forms;
using BookAStar.Data;
using Newtonsoft.Json;
namespace BookAStar.ViewModels namespace BookAStar.ViewModels
{ {
public class EditEstimateViewModel : ViewModel public class EditEstimateViewModel : EditingViewModel
{ {
public EditEstimateViewModel(Estimate data) /// <summary>
/// For deserialization
/// </summary>
public EditEstimateViewModel()
{
}
/// <summary>
/// Builds a new view model on estimate,
/// sets <c>Data</c> with given value parameter
/// </summary>
/// <param name="data"></param>
/// <param name="localState"></param>
public EditEstimateViewModel(Estimate data, LocalState localState )
{ {
Data = data; Data = data;
if (data.AttachedFiles == null) data.AttachedFiles = new List<string>(); State = localState;
if (data.AttachedGraphics == null) data.AttachedGraphics = new List<string>();
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.CollectionChanged += Bill_CollectionChanged;
} }
private void Bill_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) private void Bill_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
@ -26,19 +34,31 @@ namespace BookAStar.ViewModels
Data.Bill = Bill; Data.Bill = Bill;
NotifyPropertyChanged("FormattedTotal"); NotifyPropertyChanged("FormattedTotal");
} }
private Estimate data;
public Estimate Data { get { return data; } set {
data = value;
if (data.AttachedFiles == null) data.AttachedFiles = new List<string>();
if (data.AttachedGraphics == null) data.AttachedGraphics = new List<string>();
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.CollectionChanged += Bill_CollectionChanged;
} }
public Estimate Data { get; protected set; } [JsonIgnore]
public ObservableCollection<string> AttachedFiles public ObservableCollection<string> AttachedFiles
{ {
get; protected set; get; protected set;
} }
[JsonIgnore]
public ObservableCollection<string> AttachedGraphicList public ObservableCollection<string> AttachedGraphicList
{ {
get; protected set; get; protected set;
} }
[JsonIgnore]
public ObservableCollection<BillingLine> Bill public ObservableCollection<BillingLine> Bill
{ {
get; protected set; get; protected set;
@ -46,6 +66,7 @@ namespace BookAStar.ViewModels
string newDesc; string newDesc;
[JsonIgnore]
public string Description public string Description
{ {
get get
@ -61,6 +82,7 @@ namespace BookAStar.ViewModels
} }
private int? status; private int? status;
[JsonIgnore]
public int? Status public int? Status
{ {
get get
@ -75,6 +97,7 @@ namespace BookAStar.ViewModels
} }
} }
private string title; private string title;
[JsonIgnore]
public string Title public string Title
{ {
get get
@ -89,10 +112,13 @@ namespace BookAStar.ViewModels
} }
} }
[JsonIgnore]
public ClientProviderInfo Client { get { return Data.Client; } } public ClientProviderInfo Client { get { return Data.Client; } }
[JsonIgnore]
public BookQueryData Query { get { return Data.Query; } } public BookQueryData Query { get { return Data.Query; } }
[JsonIgnore]
public FormattedString FormattedTotal public FormattedString FormattedTotal
{ {
get get

@ -0,0 +1,29 @@
using BookAStar.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XLabs.Forms.Mvvm;
namespace BookAStar.ViewModels
{
/// <summary>
/// Used to make the DataManager know how
/// to sync local and remote data
/// </summary>
public class EditingViewModel: ViewModel
{
private LocalState state;
public LocalState State {
get
{
return state;
}
set
{
base.SetProperty<LocalState>(ref state, value);
}
}
}
}

@ -33,12 +33,11 @@ namespace BookAStar.Views
if (Modified != null) if (Modified != null)
{ {
Modified.Invoke(this, new EventArgs()); Modified.Invoke(this, new EventArgs());
return;
} }
} }
} }
} }
private bool editable;
public bool Editable public bool Editable
{ {
get { get {

Loading…