changement de candidat à l'investissement

This commit is contained in:
Paul Schneider 2017-01-26 11:04:03 +01:00
commit be3087fff6
351 changed files with 359 additions and 497 deletions

108
ZicMoove/ZicMoove/App.xaml Normal file
View file

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BookAStar.App"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Application.Resources>
<ResourceDictionary>
<Color x:Key="PageBackgroundColor">#FFAAAAFF</Color>
<Color x:Key="DashboardPageBackgroundColor">#FFCCCCFF</Color>
<Color x:Key="ContentBackgroundColor">#80FFFFFF</Color>
<Color x:Key="BackgroundColor">#FFFFFFFF</Color>
<Color x:Key="LabelBackgroundColor">#FFFFFFFF</Color>
<Color x:Key="PageForegroundColor">#000000</Color>
<Color x:Key="TextColor">#000000</Color>
<Color x:Key="LabelColor">#000000</Color>
<Color x:Key="ErrorTextColor">#500000</Color>
<Color x:Key="HeadingTextColor">Black</Color>
<Color x:Key="NormalTextColor">Blue</Color>
<Color x:Key="GroupingTextColor">#5050ff</Color>
<Color x:Key="OddColor">#207AFAFA</Color>
<Color x:Key="EmphasisTextColor">#800080</Color>
<Color x:Key="QuietTextColor">#404040</Color>
<Color x:Key="DisconnectedUserBgColor">#909090</Color>
<Color x:Key="ConnectedUserBgColor">#ffffff</Color>
<OnPlatform x:TypeArguments="Font" Android="Large" iOS="Large" WinPhone="Large" x:Key="HeaderFont" />
<OnPlatform x:TypeArguments="x:Double" Android="22" iOS="22" WinPhone="22" x:Key="LargeFontSize" />
<OnPlatform x:TypeArguments="x:Double" Android="16" iOS="16" WinPhone="16" x:Key="MediumFontSize" />
<OnPlatform x:TypeArguments="x:Double" Android="14" iOS="14" WinPhone="14" x:Key="SmallFontSize" />
<OnPlatform x:TypeArguments="x:Double" Android="130" iOS="130" WinPhone="130" x:Key="BigUserAvatarSize" />
<Style x:Key="LabelPageHeadingStyle" TargetType="Label">
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
<Setter Property="FontSize" Value="{StaticResource LargeFontSize}" />
</Style>
<Style x:Key="InputLabelStyle" TargetType="Label">
<Setter Property="FontSize" Value="{StaticResource SmallFontSize}" />
<Setter Property="FontAttributes" Value="Italic" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="TextColor" Value="{StaticResource GroupingTextColor}" />
<Setter Property="VerticalOptions" Value="Start" />
</Style>
<Style x:Key="ErrorLabelStyle" BasedOn="{StaticResource InputLabelStyle}" TargetType="Label">
<Setter Property="FontSize" Value="Large" />
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="TextColor" Value="{StaticResource ErrorTextColor}" />
</Style>
<Style x:Key="LabelStyle" TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource LabelColor}" />
<Setter Property="LineBreakMode" Value="WordWrap" />
<Setter Property="HorizontalOptions" Value="FillAndExpand" />
</Style>
<Style x:Key="BigLabelStyle" BasedOn="{StaticResource LabelStyle}" TargetType="Label">
<Setter Property="FontSize" Value="Large" />
</Style>
<Style x:Key="ContentLabelStyle" BasedOn="{StaticResource LabelStyle}" TargetType="Label">
<Setter Property="FontSize" Value="{StaticResource MediumFontSize}" />
<Setter Property="HorizontalOptions" Value="CenterAndExpand" />
</Style>
<Style x:Key="EntryStyle" TargetType="Entry">
<Setter Property="HorizontalOptions" Value="CenterAndExpand"/>
</Style>
<Style x:Key="PickerStyle" TargetType="Picker">
<Setter Property="HorizontalOptions" Value="FillAndExpand"/>
</Style>
<Style x:Key="BigEntry" TargetType="Entry" BasedOn="{StaticResource EntryStyle}">
<Setter Property="FontSize" Value="{StaticResource LargeFontSize}" />
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="HorizontalOptions" Value="FillAndExpand"/>
<Setter Property="HorizontalTextAlignment" Value="Center"/>
</Style>
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BorderColor" Value="Lime" />
<Setter Property="BorderRadius" Value="15" />
<Setter Property="BorderWidth" Value="10" />
<Setter Property="WidthRequest" Value="200" />
<Setter Property="TextColor" Value="Teal" />
</Style>
<Style x:Key="PageStyle" TargetType="ContentPage">
<Setter Property="Padding" Value="15,15,15,15" />
<Setter Property="BackgroundColor" Value="{StaticResource PageBackgroundColor}" />
</Style>
<Style x:Key="DashboardPageStyle" TargetType="ContentPage">
<Setter Property="Padding" Value="10,10,10,10" />
<Setter Property="BackgroundColor" Value="{StaticResource DashboardPageBackgroundColor}" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

View file

@ -0,0 +1,454 @@
using System;
using Microsoft.AspNet.SignalR.Client;
using System.Net;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using XLabs.Forms.Mvvm;
using XLabs.Forms.Pages;
using XLabs.Forms.Services;
using XLabs.Ioc;
using XLabs.Platform.Mvvm;
using XLabs.Platform.Services;
using XLabs.Settings;
using XLabs;
using XLabs.Enums;
namespace BookAStar
{
using Data;
using Interfaces;
using Model;
using Pages;
using Plugin.Connectivity;
using Model.Social.Messaging;
using ViewModels.Messaging;
using ViewModels.UserProfile;
using Pages.UserProfile;
using ViewModels.EstimateAndBilling;
using Pages.EstimatePages;
using ViewModels;
using Pages.Chat;
using System.Collections.Generic;
using Model.Social;
public partial class App : Application // superclass new in 1.3
{
public static IPlatform PlatformSpecificInstance { get; set; }
public static string AppName { get; set; }
[Obsolete("Instead using this, use new static properties.")]
public static App CurrentApp { get { return Current as App; } }
private static ExtendedMasterDetailPage masterDetail;
public static bool MasterPresented
{
get
{ return App.masterDetail.IsPresented; }
internal set
{ masterDetail.IsPresented = value; }
}
public void Init()
{
var app = Resolver.Resolve<IXFormsApp>();
if (app == null)
{
return;
}
Configure(app);
app.Closing += OnClosing;
app.Error += OnError;
app.Initialize += OnInitialize;
app.Resumed += OnAppResumed;
app.Rotation += OnRotation;
app.Startup += OnStartup;
app.Suspended += OnSuspended;
MainSettings.UserChanged += MainSettings_UserChanged;
CrossConnectivity.Current.ConnectivityChanged += (conSender, args) =>
{ App.IsConnected = args.IsConnected; };
SetupHubConnection();
MainSettings_UserChanged(this, null);
StartConnexion();
}
// omg
private void OnError(object sender, EventArgs e)
{
}
// Called on rotation after OnSuspended
private void OnClosing(object sender, EventArgs e)
{
}
// FIXME Never called.
private void OnInitialize(object sender, EventArgs e)
{
}
// called on app startup, not on rotation
private void OnStartup(object sender, EventArgs e)
{
// TODO special startup pages as
// notification details or wizard setup page
}
private static INavigation Navigation
{
get
{
return masterDetail.Detail.Navigation;
}
}
// Called on rotation
private void OnSuspended(object sender, EventArgs e)
{
StopConnection();
int position = 0;
DataManager.Instance.AppState.Clear();
foreach (Page page in Navigation.NavigationStack)
{
DataManager.Instance.AppState.Add(
new PageState
{
Position = position++,
PageType = page.GetType().FullName,
BindingContext = page.BindingContext
});
}
DataManager.Instance.AppState.SaveEntity();
}
// called on app startup, after OnStartup, not on rotation
private void OnAppResumed(object sender, EventArgs e)
{
StartConnexion();
// TODO restore the navigation stack
base.OnResume();
foreach (var pageState in DataManager.Instance.AppState)
{
if (pageState.PageType != null)
{
var pageType = Type.GetType(pageState.PageType);
if (pageState.BindingContext != null)
NavigationService.NavigateTo(
pageType, false, pageState.BindingContext);
else NavigationService.NavigateTo(
pageType, false);
}
}
DataManager.Instance.AppState.Clear();
DataManager.Instance.AppState.SaveEntity();
}
// FIXME Not called?
private void OnRotation(object sender, EventArgs<Orientation> e)
{
}
public static GenericConfigSettingsMgr ConfigManager { protected set; get; }
private void Configure(IXFormsApp app)
{
ViewFactory.EnableCache = true;
ViewFactory.Register<DashboardPage, DashboardViewModel>(
resolver => new DashboardViewModel());
ViewFactory.Register<BookQueryPage, BookQueryViewModel>();
ViewFactory.Register<BookQueriesPage, BookQueriesViewModel>();
ViewFactory.Register<EditBillingLinePage, BillingLineViewModel>();
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);
}
public App(IPlatform instance)
{
// This declaration became obsolete by introduction
// of the XLabs App that
// refers this instance with
// its application context property
// and is obtained using the `Resolver`
PlatformSpecificInstance = instance;
// Xaml
InitializeComponent();
// Static properties construction
Init();
// Builds the Main page
BuildMainPage();
}
BookQueriesPage bQueriesPage;
AccountChooserPage accChooserPage;
HomePage homePage;
private static UserProfilePage userProfilePage;
public static UserProfilePage UserProfilePage
{ get { return userProfilePage; } }
ChatPage chatPage;
public static void ShowPage(Page page)
{
if (Navigation.NavigationStack.Contains(page))
{
if (Navigation.NavigationStack.Last() == page) return;
Navigation.RemovePage(page);
page.Parent = null;
}
Navigation.PushAsync(page);
}
private void BuildMainPage()
{
// TODO
// in case of App resume,
// do not create new BindingContext's,
// but use those from the AppState property
accChooserPage = new AccountChooserPage();
var bookQueries = new BookQueriesViewModel();
var userprofile = new UserProfileViewModel();
bQueriesPage = new BookQueriesPage
{
Title = "Demandes",
Icon = "icon.png",
BindingContext = bookQueries
};
homePage = new HomePage() {
Title = "Accueil",
Icon = "icon.png" };
homePage.BindingContext = new HomeViewModel {
BookQueries = bookQueries,
UserProfile = userprofile };
userProfilePage = new UserProfilePage {
Title = "Profile utilisateur",
Icon = "ic_corp_icon.png",
BindingContext = userprofile
};
chatPage = new ChatPage
{
Title = "Chat",
Icon = "",
BindingContext = new ChatViewModel()
};
// var mainPage = new NavigationPage(bQueriesPage);
masterDetail = new ExtendedMasterDetailPage()
{
Title = "MainPage"
};
masterDetail.Master = new DashboardPage
{
Title = "Bookingstar",
BindingContext = new DashboardViewModel()
};
masterDetail.Detail = new NavigationPage(homePage);
ToolbarItem tiSetts = new ToolbarItem()
{
// FIXME what for? Priority = 0,
Text = "Paramètres",
Icon = "ic_corp_icon.png",
Command = new Command(
() =>
{
ShowPage(userProfilePage);
} )
};
ToolbarItem tiHome = new ToolbarItem()
{
Text = "Accueil",
Icon = "icon.png",
Command = new Command(
() => {
ShowPage(homePage);
})
};
ToolbarItem tiPubChat= new ToolbarItem()
{
Text = "Chat",
Icon = "chat_icon_s.png",
Command = new Command(
() => { ShowPage(chatPage); }
)
};
masterDetail.ToolbarItems.Add(tiHome);
masterDetail.ToolbarItems.Add(tiSetts);
masterDetail.ToolbarItems.Add(tiPubChat);
this.MainPage = masterDetail;
NavigationService = new NavigationService(Navigation);
}
public static Task<string> DisplayActionSheet(string title, string cancel, string destruction, string [] buttons)
{
var currentPage = Navigation.NavigationStack.Last();
return currentPage.DisplayActionSheet(title, cancel, destruction, buttons);
}
public static Task<bool> DisplayAlert(string title, string message, string yes = "OK", string no = null)
{
var currentPage = ((NavigationPage)Current.MainPage).CurrentPage;
if (no == null)
{
return currentPage.DisplayAlert(title, message, yes).ContinueWith(task => true);
}
else
{
return currentPage.DisplayAlert(title, message, yes, no);
}
}
public static INavigationService NavigationService { protected set; get; }
public static bool isConnected;
public static bool IsConnected { get { return isConnected; }
private set
{
if (isConnected != value)
{
isConnected = value;
if (isConnected)
{
// TODO Start all cloud related stuff
StartConnexion();
}
}
}
}
private static HubConnection chatHubConnection = null;
public static HubConnection ChatHubConnection
{
get
{
return chatHubConnection;
}
}
// Start the Hub connection
public static async void StartConnexion ()
{
if (CrossConnectivity.Current.IsConnected)
try
{
if (chatHubConnection.State == ConnectionState.Disconnected)
await chatHubConnection.Start();
}
catch (WebException )
{
// TODO use webex, set this cx down status somewhere,
// & display it & maybe try again later.
}
catch (Exception )
{
// TODO use ex
}
}
public void SetupHubConnection()
{
if (chatHubConnection != null)
chatHubConnection.Dispose();
chatHubConnection = new HubConnection(Constants.SignalRHubsUrl);
chatHubConnection.Error += ChatHubConnection_Error;
chatHubProxy = chatHubConnection.CreateHubProxy("ChatHub");
chatHubProxy.On<string, string>("addPV", (n, m) => {
var msg = new ChatMessage
{
Message = m,
SenderId = n,
Date = DateTime.Now
};
DataManager.Instance.PrivateMessages.Add(
msg
);
DataManager.Instance.ChatUsers.OnPrivateMessage(msg);
});
}
public static void StopConnection()
{
try
{
if (chatHubConnection.State != ConnectionState.Disconnected)
chatHubConnection.Stop();
}
catch (WebException)
{
// TODO use webex, set this cx down status somewhere,
// & display it & maybe try again later.
}
catch (Exception)
{
// TODO use ex
}
}
private void MainSettings_UserChanged(object sender, EventArgs e)
{
StopConnection();
if (MainSettings.CurrentUser != null)
{
var token = MainSettings.CurrentUser.YavscTokens.AccessToken;
if (chatHubConnection.Headers.ContainsKey("Authorization"))
chatHubConnection.Headers.Remove("Authorization");
chatHubConnection.Headers.Add("Authorization", $"Bearer {token}");
}
StartConnexion();
}
private void ChatHubConnection_Error(Exception obj)
{
// TODO log in debug binaries
}
private static IHubProxy chatHubProxy = null;
public static IHubProxy ChatHubProxy
{
get
{
return chatHubProxy;
}
}
public static Task<bool> HasSomeCloud {
get
{
return CrossConnectivity.Current.IsReachable(Constants.YavscHomeUrl, Constants.CloudTimeout);
}
}
public static void PostDeviceInfo()
{
var info = PlatformSpecificInstance.GetDeviceInfo();
if (!string.IsNullOrWhiteSpace(info.GCMRegistrationId))
PlatformSpecificInstance.InvokeApi("gcm/register", info);
}
public static void ShowBookQuery (BookQuery query)
{
var page = new BookQueryPage
{ BindingContext = new BookQueryViewModel(query) };
ShowPage(page);
}
}
}

View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BookAStar.Attributes
{
class CurrencyAttribute: Attribute
{
}
}

View file

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BookAStar.Attributes
{
class DisplayAttribute : Attribute
{
public string Name { get; set; }
public string Description { get; set; }
public DisplayAttribute()
{
}
public DisplayAttribute(string name)
{
Name = name;
}
}
}

View file

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar
{
public static class Constants
{
#if DEV
public const string ApplicationName = "yadev";
public const string YavscHomeUrl = "http://dev.pschneider.fr";
#else
#if WDEV
public const string ApplicationName = "yawindev";
public const string YavscHomeUrl = "http://192.168.0.29:5000";
#else
#if YAVSC
public const string ApplicationName = "yavsc";
public const string YavscHomeUrl = "https://yavsc.pschneider.fr";
#else
#if LUA
public const string ApplicationName = "Luap";
public const string YavscHomeUrl = "https://lua.pschneider.fr";
#else
public const string YavscHomeUrl = "https://booking.pschneider.fr";
#endif
#endif
#endif
#endif
public static readonly string AuthorizeUrl = YavscHomeUrl + "/authorize";
public static readonly string RedirectUrl = YavscHomeUrl + "/oauth/success";
public static readonly string AccessTokenUrl = YavscHomeUrl + "/token";
public static readonly string YavscApiUrl = YavscHomeUrl + "/api";
public static readonly string MobileRegistrationUrl = YavscApiUrl + "/gcm/register";
public static readonly string UserInfoUrl = YavscApiUrl + "/me";
public static readonly string BlogUrl = YavscApiUrl + "/blogs";
public static readonly string FsUrl = YavscApiUrl + "/fs";
public static readonly string SignalRHubsUrl = YavscHomeUrl + "/api/signalr/hubs";
public static int AllowBeATarget = 1;
public static int CloudTimeout = 400;
}
}

View file

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Behaviors
{
public class DecimalValidatorBehavior : Behavior<Entry>
{
// 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(DecimalValidatorBehavior), false);
public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;
public bool IsValid
{
get { return (bool)base.GetValue(IsValidProperty); }
private set { base.SetValue(IsValidPropertyKey, value); }
}
protected override void OnAttachedTo(Entry bindable)
{
bindable.TextChanged += bindable_TextChanged;
}
private void bindable_TextChanged(object sender, TextChangedEventArgs e)
{
decimal result;
IsValid = decimal.TryParse(e.NewTextValue, NumberStyles.Currency,CultureInfo.InvariantCulture, out result);
((Entry)sender).TextColor = IsValid ? Color.Default : Color.Red;
}
protected override void OnDetachingFrom(Entry bindable)
{
bindable.TextChanged -= bindable_TextChanged;
}
}
}

View file

@ -0,0 +1,80 @@
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), int.MaxValue);
public static readonly BindableProperty MinLengthProperty =
BindableProperty.Create("MinLength", typeof(int), typeof(EditorMaxLengthValidator), 0);
public static readonly BindableProperty IsValidProperty =
BindableProperty.Create("IsValid", typeof(bool), typeof(EditorMaxLengthValidator), false);
public static readonly BindableProperty ErrorProperty =
BindableProperty.Create("Error", typeof(string), typeof(EditorMaxLengthValidator), null);
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 { return (bool) GetValue(IsValidProperty); }
set { SetValue(IsValidProperty, value);
}
}
public string Error
{
get
{
return (string) GetValue(ErrorProperty);
}
set
{
SetValue(ErrorProperty, value);
}
}
private void bindable_TextChanged(object sender, TextChangedEventArgs e)
{
if (e.NewTextValue != null && e.NewTextValue.Length >= MinLength)
{
if (e.NewTextValue.Length > MaxLength)
{
((Editor)sender).Text = e.NewTextValue.Substring(0, MaxLength);
Error = Strings.YourTextWasTooLong;
}
else Error = "";
IsValid = true;
}
else
{
Error = string.Format(Strings.MinMaxStringValidationError,
MinLength, MaxLength);
IsValid = false;
}
}
protected override void OnDetachingFrom(Editor bindable)
{
bindable.TextChanged -= bindable_TextChanged;
}
}
}

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Behaviors
{
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]))$";
public EmailValidatorBehavior()
{
Regexp = emailRegex;
}
}
}

View file

@ -0,0 +1,72 @@
using Xamarin.Forms;
namespace BookAStar.Behaviors
{
public class IntegerEntryBehavior : Behavior<Entry>
{
public static readonly BindableProperty MinProperty = BindableProperty.Create("Min", typeof(int), typeof(IntegerEntryBehavior), 0);
public static readonly BindableProperty MaxProperty = BindableProperty.Create("Max", typeof(int), typeof(IntegerEntryBehavior), 0);
public static readonly BindableProperty IsValidProperty =
BindableProperty.Create("IsValid", typeof(bool), typeof(IntegerEntryBehavior), false);
public static readonly BindableProperty ErrorProperty =
BindableProperty.Create("Error", typeof(string), typeof(IntegerEntryBehavior), null);
public int Min
{
get { return (int)GetValue(MinProperty); }
set { SetValue(MinProperty, value); }
}
public int Max
{
get { return (int)GetValue(MaxProperty); }
set { SetValue(MaxProperty, value); }
}
protected override void OnAttachedTo(Entry bindable)
{
bindable.TextChanged += bindable_TextChanged;
}
private void bindable_TextChanged(object sender, TextChangedEventArgs e)
{
int val;
if (int.TryParse(e.NewTextValue, out val))
{
IsValid = (Min > Max) || (Max >= val && val >= Min);
Error = string.Format(Strings.MinMaxIntError, Min, Max);
}
else
{
IsValid = false;
Error = "";
}
}
protected override void OnDetachingFrom(Entry bindable)
{
bindable.TextChanged -= bindable_TextChanged;
}
public bool IsValid
{
get {
return (bool) GetValue(IsValidProperty);
}
set
{
SetValue(IsValidProperty, value);
}
}
public string Error
{
get
{
return (string) GetValue(ErrorProperty);
}
set
{
SetValue(ErrorProperty, value);
}
}
}
}

View 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;
}
}
}

View file

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Behaviors
{
public class PickerBehavior : Behavior<Picker>
{
// Creating BindableProperties with Limited write access: http://iosapi.xamarin.com/index.aspx?link=M%3AXamarin.Forms.BindableObject.SetValue(Xamarin.Forms.BindablePropertyKey%2CSystem.Object)
public static readonly BindablePropertyKey SelectedItemPropertyKey = BindableProperty.CreateReadOnly("SelectedItem", typeof(string), typeof(PickerBehavior), default(string));
public static readonly BindableProperty SelectedItemProperty = SelectedItemPropertyKey.BindableProperty;
public string SelectedItem
{
get { return (string)base.GetValue(SelectedItemProperty); }
private set { base.SetValue(SelectedItemPropertyKey, value); }
}
protected override void OnAttachedTo(Picker bindable)
{
bindable.SelectedIndexChanged += bindable_SelectedIndexChanged;
}
void bindable_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
if (picker.SelectedIndex <= 0 || picker.SelectedIndex > picker.Items.Count - 1)
SelectedItem = null;
else
SelectedItem=picker.Items[picker.SelectedIndex];
}
protected override void OnDetachingFrom(Picker bindable)
{
bindable.SelectedIndexChanged -= bindable_SelectedIndexChanged;
}
}
}

View 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;
}
}
}

View file

@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Behaviors
{
public class StarBehavior : Behavior<View>
{
TapGestureRecognizer tapRecognizer;
static List<StarBehavior> defaultBehaviors = new List<StarBehavior>();
static Dictionary<string, List<StarBehavior>> starGroups = new Dictionary<string, List<StarBehavior>>();
public static readonly BindableProperty GroupNameProperty =
BindableProperty.Create("GroupName",
typeof(string),
typeof(StarBehavior),
null,
propertyChanged: OnGroupNameChanged);
public string GroupName
{
set { SetValue(GroupNameProperty, value); }
get { return (string)GetValue(GroupNameProperty); }
}
public static readonly BindableProperty RatingProperty =
BindableProperty.Create("Rating",
typeof(int),
typeof(StarBehavior), default(int),
BindingMode.TwoWay);
public static event EventHandler<EventArgs> StarTapped;
public int Rating
{
set { SetValue(RatingProperty, value); }
get { return (int)GetValue(RatingProperty); }
}
static void OnGroupNameChanged(BindableObject bindable, object oldValue, object newValue)
{
StarBehavior behavior = (StarBehavior)bindable;
string oldGroupName = (string)oldValue;
string newGroupName = (string)newValue;
// Remove existing behavior from Group
if (String.IsNullOrEmpty(oldGroupName))
{
defaultBehaviors.Remove(behavior);
}
else
{
List<StarBehavior> behaviors = starGroups[oldGroupName];
behaviors.Remove(behavior);
if (behaviors.Count == 0)
{
starGroups.Remove(oldGroupName);
}
}
// Add New Behavior to the group
if (String.IsNullOrEmpty(newGroupName))
{
defaultBehaviors.Add(behavior);
}
else
{
List<StarBehavior> behaviors = null;
if (starGroups.ContainsKey(newGroupName))
{
behaviors = starGroups[newGroupName];
}
else
{
behaviors = new List<StarBehavior>();
starGroups.Add(newGroupName, behaviors);
}
behaviors.Add(behavior);
}
}
public static readonly BindableProperty IsStarredProperty =
BindableProperty.Create("IsStarred",
typeof(bool),
typeof(StarBehavior),
false,
propertyChanged: OnIsStarredChanged);
public bool IsStarred
{
set { SetValue(IsStarredProperty, value); }
get { return (bool)GetValue(IsStarredProperty); }
}
static void OnIsStarredChanged(BindableObject bindable, object oldValue, object newValue)
{
StarBehavior behavior = (StarBehavior)bindable;
string groupName = behavior.GroupName;
List<StarBehavior> behaviors = null;
if (string.IsNullOrEmpty(groupName))
{
behaviors = defaultBehaviors;
}
else
{
behaviors = starGroups[groupName];
}
bool itemReached = false;
int count = 0, position = 0;
// all positions to left IsStarred = true and all position to the right is false
foreach (var item in behaviors)
{
count++;
if (item != behavior && !itemReached)
{
item.IsStarred = true;
}
if (item == behavior)
{
itemReached = true;
// whould try to call this method again
// Assert item.IsStarred == newValue;
// There are **6** positions, from 0 to five stars.
if ((bool)newValue)
position = count;
else position = count - 1;
}
if (item != behavior && itemReached)
item.IsStarred = false;
item.Rating = position;
}
// Assert count > 0
behaviors[count - 1].Rating = position;
}
public StarBehavior()
{
defaultBehaviors.Add(this);
}
protected override void OnAttachedTo(View view)
{
tapRecognizer = new TapGestureRecognizer();
tapRecognizer.Tapped += OnTapRecognizerTapped;
view.GestureRecognizers.Add(tapRecognizer);
}
protected override void OnDetachingFrom(View view)
{
view.GestureRecognizers.Remove(tapRecognizer);
tapRecognizer.Tapped -= OnTapRecognizerTapped;
}
void OnTapRecognizerTapped(object sender, EventArgs args)
{
// Assert sender is mine
bool currentIsStarred = (bool) GetValue(IsStarredProperty);
IsStarred = !currentIsStarred;
if (StarTapped!=null)
StarTapped.Invoke(this, new EventArgs());
}
}
}

View file

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Converters
{
public class BooleanToObjectConverter<T> : IValueConverter
{
public T FalseObject { set; get; }
public T TrueObject { set; get; }
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return (bool)value ? this.TrueObject : this.FalseObject;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return ((T)value).Equals(this.TrueObject);
}
}
}

View file

@ -0,0 +1,22 @@
using System;
using System.Globalization;
using Xamarin.Forms;
namespace BookAStar.Converters
{
/// <summary>
/// When EnumType:int
/// </summary>
class EnumConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int) value;
}
}
}

View file

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Converters
{
class GenderConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return string.Empty;
var gender = value.ToString();
if (gender == "Mâle")
return "Vous etes sédisant!";
else if (gender == "Femelle")
return "Vous etes une beauté!";
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Globalization;
using Xamarin.Forms;
namespace BookAStar.Converters
{
public class NotValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return object.Equals(value, false);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return object.Equals(value, false);
}
}
}

View file

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Converters
{
class RatingText : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var rating = (int)value;
if (rating == 0)
return Strings.NoStar;
if (rating == 1)
return Strings.OneStar;
if (rating == 2)
return Strings.TwoStars;
if (rating == 3)
return Strings.ThreeStars;
if (rating == 4)
return Strings.ForStars;
if (rating == 5)
return Strings.FiveStars;
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,42 @@
using Microsoft.AspNet.SignalR.Client;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Converters
{
public class SignalRConnectionStateToObject<T> : IValueConverter
{
public T ConnectedObject { set; get; }
public T ConnectingObject { set; get; }
public T DisconnectedObject { set; get; }
public T ReconnectingObject { set; get; }
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
switch ((ConnectionState)value) {
case ConnectionState.Connected: return ConnectedObject;
case ConnectionState.Connecting: return ConnectingObject;
case ConnectionState.Disconnected: return DisconnectedObject;
case ConnectionState.Reconnecting: return ReconnectingObject;
}
Debug.Assert(false);
return null;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View 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)
{
}
}
}

View file

@ -0,0 +1,72 @@
namespace BookAStar.Data
{
using Model;
using Model.Blog;
using Model.Workflow;
using Model.Social.Messaging;
using ViewModels.EstimateAndBilling;
using NonCrUD;
using ViewModels;
using Model.Access;
using ViewModels.Messaging;
using Model.Social;
public class DataManager
{
// TODO estimatetemplate rating service product tag
public RemoteEntityRO<BookQuery, long> BookQueries { get; set; }
public ChatUserCollection ChatUsers { get; set; }
public EstimateEntity Estimates { get; set; }
public RemoteEntity<Blog, long> Blogspot { get; set; }
internal RemoteFilesEntity RemoteFiles { get; set; }
public LocalEntity<ClientProviderInfo, string> Contacts { get; set; }
internal RemoteEntity<BlackListed, long> BlackList { get; set; }
/// <summary>
/// They've got no remote existence ...
/// </summary>
internal LocalEntity<EditEstimateViewModel, long> EstimationCache { get; set; }
internal LocalEntity<BillingLine, string> EstimateLinesTemplates { get; set; }
internal LocalEntity<ChatMessage, int> PrivateMessages { get; set; }
internal LocalEntity<PageState, int> AppState { get; set; }
internal LocalEntity<string,string> ClientSignatures { get; set; }
internal LocalEntity<string, string> ProviderSignatures { get; set; }
protected static DataManager instance = new DataManager();
public static DataManager Instance
{
get
{
return instance;
}
}
public DataManager()
{
BookQueries = new RemoteEntityRO<BookQuery, long>("bookquery", q => q.Id);
Estimates = new EstimateEntity();
Blogspot = new RemoteEntity<Blog, long>("blog", x=>x.Id);
Contacts = new LocalEntity<ClientProviderInfo, string>(c => c.UserId);
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);
PrivateMessages = new LocalEntity<ChatMessage, int>(m=> m.GetHashCode());
RemoteFiles = new RemoteFilesEntity ();
BlackList = new RemoteEntity<BlackListed, long>("blacklist",u => u.Id);
ChatUsers = new ChatUserCollection();
PrivateMessages.Load();
BookQueries.Load();
Estimates.Load();
Blogspot.Load();
Contacts.Load();
AppState.Load();
EstimationCache.Load();
EstimateLinesTemplates.Load();
RemoteFiles.Load();
BlackList.Load();
ChatUsers.Load();
}
}
}

View file

@ -0,0 +1,75 @@

namespace BookAStar.Data
{
using Helpers;
using Model.Workflow;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
public class EstimateEntity : RemoteEntity<Estimate, long>
{
public EstimateEntity() : base("estimate", e => e.Id)
{
}
public async void SignAsProvider(Estimate estimate, Stream stream)
{
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.CreateJsonClient())
{
try
{
var requestContent = new MultipartFormDataContent();
var content = new StreamContent(stream);
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();
}
// TODO Check we don't loose nothing here
public override void Merge(Estimate item)
{
var key = GetKey(item);
if (this.Any(x => GetKey(x).Equals(key)))
{
Remove(LocalGet(key));
}
Add(item);
CurrentItem = item;
}
}
}

View file

@ -0,0 +1,64 @@

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace BookAStar.Data
{
public class LocalEntity<V, K> : ObservableCollection<V>, ILocalEntity<V, K> where K : IEquatable<K>
{
public V CurrentItem { get; protected set; }
public Func<V, K> GetKey { get; set; }
public LocalEntity(Func<V, K> getKey) : base()
{
if (getKey == null)
// choose please, because of the genesis
throw new InvalidOperationException ("A key must be defined");
GetKey = getKey;
IList<V> l = this;
}
public virtual void Merge(V item)
{
var key = GetKey(item);
if (this.Any(x => GetKey(x).Equals(key)))
{
Remove(LocalGet(key));
}
Add(item);
CurrentItem = item;
}
public V LocalGet(K key)
{
if (!this.Any(x => GetKey(x).Equals(key)))
return default(V);
CurrentItem = this.Single(x => GetKey(x).Equals(key));
return CurrentItem;
}
public virtual bool Load()
{
return this.Populate<V,K>();
}
public virtual bool Load(string subKey)
{
return (this.Populate<V,K>(subKey));
}
public virtual bool Seek(int index)
{
if (this.Count>index && index >=0)
{
CurrentItem = this[index];
return true;
}
return false;
}
}
}

View file

@ -0,0 +1,75 @@

using Newtonsoft.Json;
using System;
namespace BookAStar.Data.NonCrUD
{
using Helpers;
using Model.FileSystem;
public class RemoteFilesEntity : RemoteEntity<UserDirectoryInfo, FileAddress>
{
public RemoteFilesEntity() : base("fs", d => d)
{
}
public override async void Execute(object parameter)
{
BeforeExecute();
using (var client = UserHelpers.CreateJsonClient())
{
// Get the whole data
try
{
var subpath = parameter as string;
string path = ControllerUri.AbsoluteUri + ((subpath != null) ? "/" + subpath : null);
using (var response = await client.GetAsync(path))
{
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var di = JsonConvert.DeserializeObject<UserDirectoryInfo>(content);
this.Merge(di);
this.SaveEntity();
}
else if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
throw new Exception("Bad request");
else
throw new Exception("Remote call failed");
}
}
catch (Exception ex)
{
throw new Exception("Remote call failed", ex);
}
}
AfterExecuting();
}
/*
public override void Merge(UserDirectoryInfo item)
{
var key = GetKey(item);
DirectoryEntryChangingEvent itemChanged = null;
if (this.Any(x => GetKey(x).Equals(key)))
{
var old = LocalGet(key);
itemChanged = new DirectoryEntryChangingEvent
{
OldItem = old,
NewItem = item
};
Remove(old);
}
Add(item);
CurrentItem = item;
if (DirectoryEntryChanged != null && itemChanged != null)
DirectoryEntryChanged.Invoke(this, itemChanged);
}
public event EventHandler<DirectoryEntryChangingEvent> DirectoryEntryChanged;
*/
}
}

View file

@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using System.Windows.Input;
using System.Net.Http;
using Newtonsoft.Json;
using System.Threading.Tasks;
using System.Net;
namespace BookAStar.Data
{
using Helpers;
using System.Diagnostics;
using System.Text;
using System.Web;
public class RemoteEntity<V, K> : LocalEntity<V, K>, ICommand where K : IEquatable<K>
{
public string ControllerName { protected set; get; }
public event EventHandler CanExecuteChanged;
public bool IsExecuting { get; private set; }
public Uri ControllerUri { get; protected set; }
public bool CanExecute(object parameter)
{
return !IsExecuting;
}
public RemoteEntity(string controllerName, Func<V, K> getKey) : base(getKey)
{
if (string.IsNullOrWhiteSpace(controllerName))
throw new InvalidOperationException();
ControllerName = controllerName;
ControllerUri = new Uri(Constants.YavscApiUrl + "/" + ControllerName);
}
protected void BeforeExecute()
{
if (IsExecuting)
throw new InvalidOperationException(Strings.AlreadyExecuting);
IsExecuting = true;
if (CanExecuteChanged != null)
CanExecuteChanged.Invoke(this, new EventArgs());
}
/// <summary>
/// Refresh the collection
/// </summary>
/// <param name="parameter"></param>
public virtual async void Execute(object parameter)
{
BeforeExecute();
using (HttpClient client = UserHelpers.CreateJsonClient())
{
// Get the whole data
try
{
using (var response = await client.GetAsync(ControllerUri))
{
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
List<V> col = JsonConvert.DeserializeObject<List<V>>(content);
// LocalData.Clear();
foreach (var item in col)
{
Merge(item);
}
this.SaveEntity();
}
}
}
catch (WebException webex)
{
throw new ServiceNotAvailable(Strings.ENoRemoteEntity, webex);
}
}
AfterExecuting();
}
protected void AfterExecuting()
{
IsExecuting = false;
if (CanExecuteChanged != null)
CanExecuteChanged.Invoke(this, new EventArgs());
}
public virtual async Task<V> Get(K key)
{
var item = LocalGet(key);
if (item == null) item = await RemoteGet(key);
CurrentItem = item;
return CurrentItem;
}
protected Uri GetUri(K key)
{
return new Uri(ControllerUri.AbsoluteUri + "/" + HttpUtility.UrlEncode(key.ToString()));
}
public virtual async Task<V> RemoteGet(K key)
{
V item = default(V);
BeforeExecute();
// Get the whole data
var uri = GetUri(key);
using (HttpClient client = UserHelpers.CreateJsonClient())
{
using (var response = await client.GetAsync(uri))
{
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
item = JsonConvert.DeserializeObject<V>(content);
Merge(item);
}
}
}
CurrentItem = item;
AfterExecuting();
return item;
}
public virtual async Task<bool> Create(V item)
{
bool created = false;
BeforeExecute();
using (HttpClient client = UserHelpers.CreateJsonClient())
{
var stringContent = JsonConvert.SerializeObject(item);
HttpContent content = new StringContent(
stringContent, Encoding.UTF8, "application/json"
);
using (var response = await client.PostAsync(ControllerUri, content))
{
created = response.IsSuccessStatusCode;
if (!created)
{
// TODO throw custom exception, and catch to inform user
var errcontent = await response.Content.ReadAsStringAsync();
Debug.WriteLine(string.Format(Strings.CreationFailed));
Debug.WriteLine(errcontent);
}
else
{
var recontent = await response.Content.ReadAsStringAsync();
JsonSerializerSettings sett = new JsonSerializerSettings();
JsonConvert.PopulateObject(recontent, item);
}
}
}
CurrentItem = item;
AfterExecuting();
return created;
}
public virtual async Task<bool> Update(V item)
{
var updated = false;
BeforeExecute();
var uri = GetUri(GetKey(item));
using (HttpClient client = UserHelpers.CreateJsonClient())
{
HttpContent content = new StringContent(
JsonConvert.SerializeObject(item), Encoding.UTF8, "application/json"
);
using (var response = await client.PutAsync(uri, content))
{
updated = response.IsSuccessStatusCode;
if (!updated)
{// TODO throw custom exception, and catch to inform user
if (response.StatusCode == HttpStatusCode.BadRequest)
{
var errorcontent = await response.Content.ReadAsStringAsync();
Debug.WriteLine(string.Format(Strings.UpdateFailed));
Debug.WriteLine(errorcontent);
}
else Debug.WriteLine($"Update failed ({item} @ {uri.AbsolutePath} )");
}
else
{
// TODO implement an handler of string content (json)
// in most of cases, nothing to do
var recontent = await response.Content.ReadAsStringAsync();
JsonConvert.PopulateObject(recontent, item);
}
}
}
CurrentItem = item;
AfterExecuting();
return updated;
}
public virtual async void Delete(K key)
{
BeforeExecute();
var uri = GetUri(key);
using (HttpClient client = UserHelpers.CreateJsonClient())
{
using (var response = await client.DeleteAsync(uri))
{
if (!response.IsSuccessStatusCode)
// TODO throw custom exception, and catch to inform user
throw new Exception($"Delete failed @ {uri.AbsolutePath}");
}
}
CurrentItem = default(V);
AfterExecuting();
}
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Linq;
namespace BookAStar.Data
{
public class RemoteEntityRO<V,K>: RemoteEntity<V,K> where K: IEquatable<K>
{
public RemoteEntityRO (string controllerName,
Func<V,K> getKey) : base(controllerName,getKey)
{
}
public override void Merge(V item)
{
var key = GetKey(item);
if (this.Any(x => GetKey(x).Equals(key))) { return; }
Add(item);
}
}
}

View file

@ -0,0 +1,43 @@
using BookAStar.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace BookAStar.Extensions
{
public static class EnumExtensions
{
public static string GetDescription(this Enum value)
{
var type = value.GetType();
var typeInfo = type.GetTypeInfo();
var declaredMember = typeInfo.DeclaredMembers.FirstOrDefault(i => i.Name == value.ToString());
var attribute = declaredMember?.GetCustomAttribute<DisplayAttribute>();
return attribute == null ? value.ToString() : attribute.Description;
}
public static IEnumerable<string> GetDescriptions(Type type)
{
var values = Enum.GetValues(type).Cast<Enum>();
var descriptions = new List<string>();
foreach (var value in values)
{
descriptions.Add(value.GetDescription());
}
return descriptions;
}
public static Enum GetEnumFromDescription(string description, Type enumType)
{
var enumValues = Enum.GetValues(enumType).Cast<Enum>();
var descriptionToEnum = enumValues.ToDictionary(k => k.GetDescription(), v => v);
return descriptionToEnum[description];
}
}
}

View file

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace BookAStar.Extensions
{
[ContentProperty("Source")]
public class ImageResourceExtension : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Source == null)
return null;
var imageSource = ImageSource.FromResource(Source);
return imageSource;
}
}
}

View file

@ -0,0 +1,58 @@
using BookAStar.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Factories
{
public class ViewFactory : IViewFactory
{
private readonly IDictionary<Type, Type> _map = new Dictionary<Type, Type>();
private readonly IComponentContext _componentContext;
public ViewFactory(IComponentContext componentContext)
{
_componentContext = componentContext;
}
public void Register<TViewModel, TView>()
where TViewModel : class, IModelViewModel
where TView : Page
{
_map[typeof(TViewModel)] = typeof(TView);
}
public Page Resolve<TViewModel>(Action<TViewModel> setStateAction = null) where TViewModel : class, IModelViewModel
{
TViewModel viewModel;
return Resolve<TViewModel>(out viewModel, setStateAction) ;
}
public Page Resolve<TViewModel>(out TViewModel viewModel, Action<TViewModel> setStateAction = null)
where TViewModel : class, IModelViewModel
{
viewModel = _componentContext.Resolve<TViewModel>();
var viewType = _map[typeof(TViewModel)];
var view = _componentContext.Resolve(viewType) as Page;
if (setStateAction != null)
viewModel.SetState(setStateAction);
view.BindingContext = viewModel;
return view;
}
public Page Resolve<TViewModel>(TViewModel viewModel)
where TViewModel : class, IModelViewModel
{
var viewType = _map[typeof(TViewModel)];
var view = _componentContext.Resolve(viewType) as Page;
view.BindingContext = viewModel;
return view;
}
}
}

View file

@ -0,0 +1,44 @@
using System;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
namespace NightFlash
{
public class GeocoderPage : ContentPage
{
Geocoder geoCoder;
Label l = new Label ();
public GeocoderPage ()
{
geoCoder = new Geocoder ();
var b1 = new Button { Text = "Reverse geocode '37.808, -122.432'" };
b1.Clicked += async (sender, e) => {
var fortMasonPosition = new Position (37.8044866, -122.4324132);
var possibleAddresses = await geoCoder.GetAddressesForPositionAsync (fortMasonPosition);
foreach (var a in possibleAddresses){
l.Text += a + "\n";
}
};
var b2 = new Button { Text = "Geocode '394 Pacific Ave'" };
b2.Clicked += async (sender, e) => {
var xamarinAddress = "394 Pacific Ave, San Francisco, California";
var approximateLocation = await geoCoder.GetPositionsForAddressAsync (xamarinAddress);
foreach (var p in approximateLocation) {
l.Text += p.Latitude + ", " + p.Longitude + "\n";
}
};
Content = new StackLayout {
Padding = new Thickness (0, 20, 0, 0),
Children = {
b2,
b1,
l
}
};
}
}
}

View file

@ -0,0 +1,24 @@
Connectivity Readme
Find the most up to date information at: https://github.com/jamesmontemagno/Xamarin.Plugins
**IMPORTANT**
Android:
You must request ACCESS_COARSE_LOCATION & ACCESS_FINE_LOCATION permission
iOS:
In iOS 8 you now have to call either RequestWhenInUseAuthorization or RequestAlwaysAuthorization on the location manager. Additionally you need to add either the concisely named NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription to your Info.plist.
See: http://motzcod.es/post/97662738237/scanning-for-ibeacons-in-ios-8
Windows Phone:
You must set the ID_CAP_LOCATION permission.
Getting Started:
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = 50;
var position = await locator.GetPositionAsync (timeout: 10000);
Console.WriteLine ("Position Status: {0}", position.Timestamp);
Console.WriteLine ("Position Latitude: {0}", position.Latitude);
Console.WriteLine ("Position Longitude: {0}", position.Longitude);

View file

@ -0,0 +1,4 @@
<GettingStarted>
<LocalContent>GS\XF\CS\App\GettingStarted.html</LocalContent>
<EmbeddedNavigation>false</EmbeddedNavigation>
</GettingStarted>

View file

@ -0,0 +1,10 @@
using System;
namespace BookAStar
{
public class NotIdentifiedException : Exception
{
public NotIdentifiedException(string message) : base(message) { }
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Helpers
{
public static class PageHelpers
{
public static async Task<bool> Confirm(this Page page, string title, string procedure)
{
string yes = "Oui", no = "Non";
var answer = await page.DisplayAlert(title,
procedure, yes, no);
return answer;
}
}
}

View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace BookAStar.Helpers
{
public static class PropertySupport
{
public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression == null)
{
throw new ArgumentException("Invalide Expression", "propertyExpression");
}
return memberExpression.Member.Name;
}
}
}

View file

@ -0,0 +1,10 @@
using System;
namespace BookAStar
{
public class ServiceNotAvailable : Exception
{
public ServiceNotAvailable(string message, Exception innerException) : base(message, innerException) { }
}
}

View file

@ -0,0 +1,43 @@
// Helpers/Settings.cs
#if USELESS_but_makes_the_component_removable // this file must exist ^^
namespace BookAStar.Helpers
{
/// <summary>
/// This is the Settings static class that can be used in your Core solution or in any
/// of your client applications. All settings are laid out the same exact way with getters
/// and setters.
/// </summary>
public static class Settings
{
public static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
#region Setting Constants
private const string SettingsKey = "settings_key";
public static readonly string SettingsDefault = string.Empty;
#endregion
public static string GeneralSettings
{
get
{
return AppSettings.GetValueOrDefault<string>(SettingsKey, SettingsDefault);
}
set
{
AppSettings.AddOrUpdateValue<string>(SettingsKey, value);
}
}
}
}
#endif

View file

@ -0,0 +1,80 @@

using System;
using System.Globalization;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Helpers
{
using Data.NonCrUD;
using Model.FileSystem;
public static class UserHelpers
{
public static ImageSource Avatar(string avatarPath)
{
var result = avatarPath == null ?
ImageSource.FromResource( "BookAStar.Images.Users.icon_user.png") :
ImageSource.FromUri(new Uri(Constants.YavscHomeUrl+"/Avatars/"+avatarPath)) ;
return result;
}
public static ImageSource SmallAvatar(string avatarPath, string username)
{
return avatarPath == null ?
ImageSource.FromResource("BookAStar.Images.Users.icon_user.png") :
ImageSource.FromUri(new Uri($"{Constants.YavscHomeUrl}/Avatars/{username}.s.png"));
}
public static ImageSource ExtraSmallAvatar(string avatarPath, string username)
{
return avatarPath == null ?
ImageSource.FromResource("BookAStar.Images.Users.icon_user.png") :
ImageSource.FromUri(new Uri($"{Constants.YavscHomeUrl}/Avatars/{username}.xs.png"));
}
public static HttpClient CreateJsonClient()
{
return CreateJsonClient(MainSettings.CurrentUser.YavscTokens.AccessToken);
}
public static HttpClient CreateJsonClient(string accessToken)
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue(
"Bearer", accessToken);
client.DefaultRequestHeaders.Add("Accept", "application/json");
return client;
}
/// <summary>
/// Uploads the given stream to
/// /api/fs, in order to be saved under the given file name
/// </summary>
/// <param name="inputStream"></param>
/// <param name="fileName"></param>
/// <returns></returns>
public static async Task<bool> Upload(Stream inputStream, string fileName)
{
using (var client = CreateJsonClient())
{
using (var content =
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
content.Add(new StreamContent(inputStream), "Files", fileName);
using (
var message =
await client.PostAsync(Constants.FsUrl, content))
{
return (message.IsSuccessStatusCode);
}
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,12 @@
using System;
namespace BookAStar.Interfaces
{
public interface IBillingLine
{
int Count { get; set; }
string Description { get; set; }
TimeSpan Duration { get; set; }
decimal UnitaryCost { get; set; }
}
}

View file

@ -0,0 +1,15 @@
using System;
using BookAStar.Model.Social;
using BookAStar.Model;
namespace BookAStar.Interfaces
{
public interface IBookQueryData
{
ClientProviderInfo Client { get; set; }
DateTime EventDate { get; set; }
long Id { get; set; }
Location Location { get; set; }
decimal? Previsionnal { get; set; }
}
}

View file

@ -0,0 +1,11 @@

using System;
namespace BookAStar.Interfaces
{
public interface IComponentContext
{
T Resolve<T>() ;
object Resolve(Type t);
}
}

View file

@ -0,0 +1,19 @@
using BookAStar.Model.Workflow;
using System.Collections.Generic;
namespace BookAStar.Model.Interfaces
{
public interface IEstimate
{
List<string> AttachedFiles { get; set; }
List<string> AttachedGraphics { get; }
List<BillingLine> Bill { get; set; }
string ClientId { get; set; }
long? CommandId { get; set; }
string CommandType { get; set; }
string Description { get; set; }
long Id { get; set; }
string OwnerId { get; set; }
string Title { get; set; }
}
}

View file

@ -0,0 +1,28 @@
using System;
using System.Collections;
namespace BookAStar
{
public interface ILoadable
{
bool Load();
}
public interface IPersistentOnDemand : ILoadable
{
void Save();
}
public interface ILocalEntity<V, K> : IList, ILoadable where K : IEquatable<K>
{
V CurrentItem { get; }
Func<V, K> GetKey { get; set; }
V LocalGet(K key);
void Merge(V item);
bool Seek(int index);
}
}

View file

@ -0,0 +1,13 @@
using System;
using Xamarin.Forms;
namespace BookAStar.Interfaces
{
public interface IMDEditor
{
View EditorView { get; }
string Text { get; set; }
bool Editable { get; set; }
Action<string> Edited { get; set; }
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BookAStar.Interfaces
{
public interface IModelViewModel : INotifyPropertyChanged
{
string Title { get; set; }
void SetState<T>(Action<T> action) where T : class, IModelViewModel;
}
}

View file

@ -0,0 +1,28 @@
using BookAStar.Model.Auth.Account;
using System;
using Xamarin.Forms;
using Yavsc.Models.Identity;
namespace BookAStar.Interfaces
{
public interface IPlatform
{
void OpenWeb (string Uri);
// TODO Better
string GCMStatusMessage { get; }
bool EnablePushNotifications (bool enable);
void AddAccount();
void RevokeAccount(string userName);
IGCMDeclaration GetDeviceInfo();
TAnswer InvokeApi<TAnswer>(string method, object arg);
object InvokeApi(string method, object arg);
}
}

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Interfaces
{
public interface IViewFactory
{
void Register<TViewModel, TView>()
where TViewModel : class, IModelViewModel
where TView : Page;
Page Resolve<TViewModel>(Action<TViewModel> setStateAction = null)
where TViewModel : class, IModelViewModel;
Page Resolve<TViewModel>(out TViewModel viewModel, Action<TViewModel> setStateAction = null)
where TViewModel : class, IModelViewModel;
Page Resolve<TViewModel>(TViewModel viewModel)
where TViewModel : class, IModelViewModel;
}
}

View file

@ -0,0 +1,64 @@
using System;
using Xamarin.Forms;
namespace NightFlash
{
public class MapAppPage : ContentPage
{
// WARNING: when adding latitude/longitude values be careful of localization.
// European (and other countries) use a comma as the separator, which will break the request
public MapAppPage ()
{
var l = new Label {
Text = "These buttons leave the current app and open the built-in Maps app for the platform"
};
var openLocation = new Button {
Text = "Open location using built-in Maps app"
};
openLocation.Clicked += (sender, e) => {
if (Device.OS == TargetPlatform.iOS) {
//https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html
Device.OpenUri(new Uri("http://maps.apple.com/?q=394+Pacific+Ave+San+Francisco+CA"));
} else if (Device.OS == TargetPlatform.Android) {
// opens the Maps app directly
Device.OpenUri(new Uri("geo:0,0?q=394+Pacific+Ave+San+Francisco+CA"));
} else if (Device.OS == TargetPlatform.WinPhone) {
DisplayAlert("To Do", "Not yet implemented", "OK");
}
};
var openDirections = new Button {
Text = "Get directions using built-in Maps app"
};
openDirections.Clicked += (sender, e) => {
if (Device.OS == TargetPlatform.iOS) {
//https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html
Device.OpenUri(new Uri("http://maps.apple.com/?daddr=San+Francisco,+CA&saddr=cupertino"));
} else if (Device.OS == TargetPlatform.Android) {
// opens the 'task chooser' so the user can pick Maps, Chrome or other mapping app
Device.OpenUri(new Uri("http://maps.google.com/?daddr=San+Francisco,+CA&saddr=Mountain+View"));
} else if (Device.OS == TargetPlatform.WinPhone) {
DisplayAlert("To Do", "Not yet implemented", "OK");
}
};
Content = new StackLayout{
Padding = new Thickness (5, 20, 5, 0),
HorizontalOptions = LayoutOptions.Fill,
Children = {
l,
openLocation,
openDirections
}
};
}
}
}

View file

@ -0,0 +1,113 @@
using System;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using System.Diagnostics;
namespace NightFlash
{
public class MapPage : ContentPage
{
Map map;
public MapPage ()
{
map = new Map {
IsShowingUser = true,
HeightRequest = 100,
WidthRequest = 960,
VerticalOptions = LayoutOptions.FillAndExpand
};
// You can use MapSpan.FromCenterAndRadius
// map.MoveToRegion (MapSpan.FromCenterAndRadius (
// new Position (37, -122), Distance.FromMiles (0.3)));
// or create a new MapSpan object directly
map.MoveToRegion (new MapSpan (new Position (0,0), 360, 360) );
// add the slider
var slider = new Slider (1, 18, 1);
slider.ValueChanged += (sender, e) => {
var zoomLevel = e.NewValue; // between 1 and 18
var latlongdegrees = 360 / (Math.Pow(2, zoomLevel));
Debug.WriteLine(zoomLevel + " -> " + latlongdegrees);
if (map.VisibleRegion != null)
map.MoveToRegion(new MapSpan (map.VisibleRegion.Center, latlongdegrees, latlongdegrees));
};
// create map style buttons
var street = new Button { Text = "Street" };
var hybrid = new Button { Text = "Hybrid" };
var satellite = new Button { Text = "Satellite" };
street.Clicked += HandleClicked;
hybrid.Clicked += HandleClicked;
satellite.Clicked += HandleClicked;
var segments = new StackLayout { Spacing = 30,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Orientation = StackOrientation.Horizontal,
Children = {street, hybrid, satellite}
};
// put the page together
var stack = new StackLayout { Spacing = 0 };
stack.Children.Add(map);
stack.Children.Add (slider);
stack.Children.Add (segments);
Content = stack;
// for debugging output only
map.PropertyChanged += (sender, e) => {
Debug.WriteLine(e.PropertyName + " just changed!");
if (e.PropertyName == "VisibleRegion" && map.VisibleRegion != null)
CalculateBoundingCoordinates (map.VisibleRegion);
};
}
void HandleClicked (object sender, EventArgs e)
{
var b = sender as Button;
switch (b.Text) {
case "Street":
map.MapType = MapType.Street;
break;
case "Hybrid":
map.MapType = MapType.Hybrid;
break;
case "Satellite":
map.MapType = MapType.Satellite;
break;
}
}
/// <summary>
/// In response to this forum question http://forums.xamarin.com/discussion/22493/maps-visibleregion-bounds
/// Useful if you need to send the bounds to a web service or otherwise calculate what
/// pins might need to be drawn inside the currently visible viewport.
/// </summary>
static void CalculateBoundingCoordinates (MapSpan region)
{
// WARNING: I haven't tested the correctness of this exhaustively!
var center = region.Center;
var halfheightDegrees = region.LatitudeDegrees / 2;
var halfwidthDegrees = region.LongitudeDegrees / 2;
var left = center.Longitude - halfwidthDegrees;
var right = center.Longitude + halfwidthDegrees;
var top = center.Latitude + halfheightDegrees;
var bottom = center.Latitude - halfheightDegrees;
// Adjust for Internation Date Line (+/- 180 degrees longitude)
if (left < -180) left = 180 + (180 + left);
if (right > 180) right = (right - 180) - 180;
// I don't wrap around north or south; I don't think the map control allows this anyway
Debug.WriteLine ("Bounding box:");
Debug.WriteLine (" " + top);
Debug.WriteLine (" " + left + " " + right);
Debug.WriteLine (" " + bottom);
}
}
}

View file

@ -0,0 +1,28 @@
using BookAStar.Model.Access;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yavsc.Models;
namespace BookAStar.Model.Access
{
public class BlackListed : IBlackListed
{
public long Id
{
get; set;
}
public string OwnerId
{
get; set;
}
public string UserId
{
get; set;
}
}
}

View file

@ -0,0 +1,36 @@
using System;
namespace BookAStar.Model.Auth.Account
{
using Yavsc.Models;
public class GoogleCloudMobileDeclaration
{
public string GCMRegistrationId { get; set; }
public string DeviceId { get; set; }
public string Model { get; set; }
public string Platform { get; set; }
public string Version { get; set; }
public IApplicationUser DeviceOwner
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public string DeviceOwnerId
{
get;
set;
}
}
}

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BookAStar.Model.Auth.Account
{
public class Tokens
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
public int ExpiresIn { set; get; }
public DateTime Received { get; set; }
public string TokenType { get; set; }
}
}

View file

@ -0,0 +1,126 @@
using BookAStar.Helpers;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.ComponentModel;
using Xamarin.Forms;
namespace BookAStar.Model.Auth.Account
{
public class User : INotifyPropertyChanged
{
private string id;
public string Id {
get {
return id;
}
set
{
id = value;
OnPropertyChanged("Id");
}
}
private string userName;
public string UserName {
get
{
return userName;
}
set
{
userName = value;
OnPropertyChanged("UserName");
}
}
private IEnumerable<string> eMails;
public IEnumerable<string> EMails
{
get { return eMails; }
set
{
eMails = value;
OnPropertyChanged("EMails");
}
}
private IEnumerable<string> roles;
public IEnumerable<string> Roles
{
get
{
return roles;
}
set
{
roles = value;
OnPropertyChanged("Roles");
}
}
private string avatar;
public string Avatar
{
get
{
return avatar;
}
set
{
avatar = value;
OnPropertyChanged("Avatar");
}
}
private string address;
public string Address
{
get
{
return address;
}
set
{
address = value;
OnPropertyChanged("Address");
}
}
[JsonIgnore]
public ImageSource AvatarSource
{
get
{
return UserHelpers.Avatar(avatar);
}
}
private Tokens yavscTokens;
public Tokens YavscTokens
{
get
{
return yavscTokens;
}
set
{
yavscTokens = value;
OnPropertyChanged("YavscTokens");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View file

@ -0,0 +1,11 @@
using System;
namespace BookAStar.Model.Auth.Account
{
public partial class passwrecovery
{
public string pkid { get; set; }
public DateTime creation { get; set; }
public string one_time_pass { get; set; }
}
}

View file

@ -0,0 +1,57 @@
using System;
using Yavsc.Models;
namespace BookAStar.Model.Blog
{
public partial class Blog : IBlog
{
public string AuthorId
{
get; set;
}
public string Content
{
get; set;
}
public long Id
{
get; set;
}
public DateTime DateModified
{
get; set;
}
public string UserCreated { get; set; }
public string UserModified { get; set; }
public string Photo
{
get; set;
}
public DateTime DateCreated
{
get; set;
}
public int Rate
{
get; set;
}
public string Title
{
get; set;
}
public bool Visible
{
get; set;
}
}
}

View file

@ -0,0 +1,11 @@
namespace BookAStar.Model.Blog
{
public partial class BlogTag
{
public long postid { get; set; }
public long TagId { get; set; }
}
}

View file

@ -0,0 +1,42 @@

using System;
namespace BookAStar.Model.Social
{
public class BookQuery
{
/// <summary>
/// Client having made this book query.
/// </summary>
public ClientProviderInfo Client { get; set; }
/// <summary>
/// Location of the client event
/// </summary>
public Location Location { get; set; }
/// <summary>
/// Unique identifier
/// </summary>
public long Id { get; set; }
/// <summary>
/// Date of the client event
/// </summary>
public DateTime EventDate { get; set; }
/// <summary>
/// Amount of money already available, from the site bank, for this event project.
/// </summary>
public decimal? Previsionnal { get; set; }
/// <summary>
/// Given reason from the client
/// </summary>
public string Reason { get; set; }
/// <summary>
/// True when the query has been read.
/// </summary>
public bool Read { get; set; }
/// <summary>
/// Unique identifier of the activity concerned,
/// the context of this query.
/// </summary>
public string ActivityCode { get; set; }
}
}

View file

@ -0,0 +1,12 @@
namespace BookAStar.Model.Social
{
public class MusicalPreference : MusicalTendency {
public long OwnerId { get; set; }
public int Rate { get; set; }
}
}

View file

@ -0,0 +1,13 @@
namespace BookAStar.Model.Social
{
public class MusicalTendency {
public long Id {get; set; }
public string Name { get ; set; }
}
}

View file

@ -0,0 +1,29 @@
using BookAStar.Helpers;
using BookAStar.Model.Social;
using Newtonsoft.Json;
using Xamarin.Forms;
namespace BookAStar.Model
{
public class ClientProviderInfo
{
public string UserName { get; set; }
public string Avatar { get; set; }
public string UserId { get; set; }
// TODO Get User Professional status existence as a boolean
// And hack the avatar with
public int Rate { get; set; }
public string EMail { get; set; }
public string Phone { get; set; }
public Location BillingAddress { get; set; }
public override string ToString()
{
return UserName;
}
}
}

View file

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BookAStar.Model.FileSystem
{
public class FileAddress : IEquatable<FileAddress>
{
public string SubPath { get; set; }
public string UserName { get; set; }
public bool Equals(FileAddress other)
{
if (other == null) return false;
if (other.UserName != UserName) return false;
if (other.SubPath != SubPath) return false;
return true;
}
}
public class UserDirectoryInfo : FileAddress
{
public UserFileInfo[] Files
{
get; set;
}
public string[] SubDirectories
{
get; set;
}
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BookAStar.Model.FileSystem
{
public class UserFileInfo
{
public string Name { get; set; }
public long Size { get; set; }
public DateTime CreationTime { get; set; }
public DateTime LastModified { get; set; }
}
}

View file

@ -0,0 +1,63 @@
using BookAStar.Model.Social;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace BookAStar
{
[Obsolete("Use Helpers.DataManager")]
public static class Manager
{
static Manager ()
{
}
public static ICommand RefreshBookQueries;
// TODO WIP TEST rop this
private static Location[] _places = new Location[] {
new Location { Latitude = 48.8626458, Longitude = 2.2065559, Address = "2 bd Aristide Briand - Suresnes" },
new Location{ Latitude =48.8632757, Longitude =2.2023099, Address ="Théatre Jean Villard - Suresnes" },
new Location{ Latitude =48.8647120, Longitude =2.2054588,Address = "Place de la Paix - Suresnes" },
new Location{ Latitude =48.8640133, Longitude =2.2056573, Address ="Restaurant" },
new Location{ Latitude =48.8634839, Longitude =2.2064137,Address = "Square" },
new Location{ Latitude =48.8653649, Longitude =2.2014945,Address = "Stade de foot" },
};
// TODO WIP TEST rop this
private static ObservableCollection<LocalizedEvent> _your_events = new ObservableCollection<LocalizedEvent> {
new LocalizedEvent {
Title = "Yavsc Party",
Description = "Lancement en fanfare de la version 1.0 de BookAStar, l'appli des fétards",
ProviderId = "paul",
ProviderName = "Yavsc Fondation",
EventWebPage = "http://lua.pschneider.fr/",
Location = _places[0]
},
new LocalizedEvent {
Title = "Evenement de test",
Description = "Blah bli lo qui est errare, ma no. Blou test allo 3!",
ProviderId = "provid3",
ProviderName = "Prov Entreprise 3",
EventWebPage = "http://lua.pschneider.fr/events/test3",
Location = _places[1]
},
new LocalizedEvent {
Title = "DjFx feat XamCoder, en Concert gratuit",
Description = "Hip Hop à Suresnes",
ProviderId = "brahim",
ProviderName = "Totem Production",
EventWebPage = "http://lua.pschneider.fr/events/totem",
Location = _places[2]
}
};
// TODO WIP TEST rop this
public static ObservableCollection<LocalizedEvent> Events {
get {
return _your_events;
}
}
}
}

View file

@ -0,0 +1,26 @@

namespace BookAStar.Model.Workflow
{
public partial class BaseProduct
{
/// <summary>
/// An unique product identifier.
/// </summary>
/// <returns></returns>
public long Id { get; set; }
public string Name { get; set; }
/// <summary>
/// A contractual description for this product.
/// </summary>
/// <returns></returns>
public string Description { get; set; }
/// <summary>
/// Controls wether this product or service
/// may be offered to clients, or simply
/// are internal workflow entry point.
/// </summary>
/// <returns>true when this product belongs to the public catalog.</returns>
public bool Public { get; set; }
}
}

View file

@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Linq;
using Xamarin.Forms;
namespace BookAStar.Model.Settings
{
class SignatureSettings
{
public static readonly Dictionary<string, Color> ColorPairs = new Dictionary<string, Color>
{
{ "<Accent Color>", Color.Accent },
{ "Aqua", Color.Aqua },
{ "Black", Color.Black },
{ "Blue", Color.Blue },
{ "Fuchsia", Color.Fuchsia },
{ "Gray", Color.Gray },
{ "Green", Color.Green },
{ "Lime", Color.Lime },
{ "Maroon", Color.Maroon },
{ "Navy", Color.Navy },
{ "Olive", Color.Olive },
{ "Pink", Color.Pink },
{ "Purple", Color.Purple },
{ "Red", Color.Red },
{ "Silver", Color.Silver },
{ "Teal", Color.Teal },
{ "White", Color.White },
{ "Yellow", Color.Yellow },
};
public static List<Color> Colors => ColorPairs.Values.ToList();
public static List<string> ColorNames => ColorPairs.Keys.ToList();
}
}

View file

@ -0,0 +1,56 @@
//
// OpenDay.cs
//
// Author:
// Paul Schneider <paulschneider@free.fr>
//
// Copyright (c) 2015 Paul Schneider
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace BookAStar.Model.Workflow.Calendar
{
/// <summary>
/// Open day.
/// </summary>
public class OpenDay {
/// <summary>
/// The day.
/// </summary>
public WeekDay Day;
/// <summary>
/// Gets or sets the s.
/// </summary>
/// <value>The s.</value>
public TimeSpan S { get; set; }
// ASSERT Start <= End
/// <summary>
/// Gets or sets the start hour.
/// </summary>
/// <value>The start.</value>
public TimeSpan Start { get; set; }
/// <summary>
/// Gets or sets the end hour
/// (from the next day if lower than the Start).
/// </summary>
/// <value>The end.</value>
public TimeSpan End { get; set; }
}
}

View file

@ -0,0 +1,42 @@
//
// Period.cs
//
// Author:
// Paul Schneider <paulschneider@free.fr>
//
// Copyright (c) 2015 Paul Schneider
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace BookAStar.Model.Workflow.Calendar
{
/// <summary>
/// Hollydays.
/// </summary>
public class Period {
/// <summary>
/// Gets or sets the start.
/// </summary>
/// <value>The start.</value>
public DateTime Start { get; set; }
/// <summary>
/// Gets or sets the end.
/// </summary>
/// <value>The end.</value>
public DateTime End { get; set; }
}
}

View file

@ -0,0 +1,54 @@
//
// Periodicity.cs
//
// Author:
// Paul Schneider <paulschneider@free.fr>
//
// Copyright (c) 2015 Paul Schneider
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace BookAStar.Model.Workflow.Calendar
{
/// <summary>
/// Periodicity.
/// </summary>
public enum Periodicity {
/// <summary>
/// The daily.
/// </summary>
Daily,
/// <summary>
/// The weekly.
/// </summary>
Weekly,
/// <summary>
/// The monthly.
/// </summary>
Monthly,
/// <summary>
/// The three m.
/// </summary>
ThreeM,
/// <summary>
/// The six m.
/// </summary>
SixM,
/// <summary>
/// The yearly.
/// </summary>
Yearly
}
}

View file

@ -0,0 +1,34 @@
using BookAStar.Model.Social;
using BookAStar.Model.Workflow.Marketing;
using System;
namespace BookAStar.Model.Workflow.Calendar
{
/// <summary>
/// A date, between two persons
/// </summary>
public class RendezVous: Service {
// Haut les mains.
/// <summary>
/// Event date
/// </summary>
/// <returns></returns>
public DateTime EventDate { get; set; }
/// <summary>
/// Location identifier
/// </summary>
/// <returns></returns>
public long LocationId { get; set; }
/// <summary>
/// A Location for this event
/// </summary>
/// <returns></returns>
public Location Location { get; set; }
}
}

View file

@ -0,0 +1,48 @@
//
// Schedule.cs
//
// Author:
// Paul Schneider <paulschneider@free.fr>
//
// Copyright (c) 2015 Paul Schneider
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace BookAStar.Model.Workflow.Calendar
{
/// <summary>
/// Schedule.
/// </summary>
public class Schedule {
/// <summary>
/// Gets or sets the period.
/// </summary>
/// <value>The period.</value>
public Periodicity Period { get; set; }
/// <summary>
/// Gets or sets the schedule of an open week.
/// One item by bay in the week,
/// </summary>
/// <value>The weekly workdays.</value>
public OpenDay [] WeekDays { get; set; }
/// <summary>
/// Gets or sets the hollydays.
/// </summary>
/// <value>The hollydays.</value>
public Period [] Validity { get; set; }
}
}

View file

@ -0,0 +1,58 @@
//
// WeekDay.cs
//
// Author:
// Paul Schneider <paulschneider@free.fr>
//
// Copyright (c) 2015 Paul Schneider
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace BookAStar.Model.Workflow.Calendar
{
/// <summary>
/// Week day.
/// </summary>
public enum WeekDay:int {
/// <summary>
/// The monday (0).
/// </summary>
Monday=0,
/// <summary>
/// The tuesday.
/// </summary>
Tuesday,
/// <summary>
/// The wednesday.
/// </summary>
Wednesday,
/// <summary>
/// The thursday.
/// </summary>
Thursday,
/// <summary>
/// The friday.
/// </summary>
Friday,
/// <summary>
/// The saturday.
/// </summary>
Saturday,
/// <summary>
/// The sunday.
/// </summary>
Sunday
}
}

View file

@ -0,0 +1,15 @@
using BookAStar.Data;
using Newtonsoft.Json;
using System;
using System.Linq;
namespace BookAStar.Model.Social.Messaging
{
public class ChatMessage
{
public DateTime Date { get; set; }
public string SenderId { get; set; }
public string Message { get; set; }
public bool Read { get; set; }
}
}

View file

@ -0,0 +1,10 @@
namespace BookAStar.Model.Workflow.Messaging
{
public enum ChatStatus
{
OnLine,
Away,
OffLine
}
}

View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YavscLib;
namespace BookAStar.Model.Social.Chat
{
public class Connection : IConnection
{
public bool Connected
{
get; set;
}
public string ConnectionId
{
get; set;
}
public string UserAgent
{
get; set;
}
}
}

View file

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace BookAStar.Model.Social
{
public partial class Circle {
public long Id { get; set; }
public string Name { get; set; }
public string OwnerId { get; set; }
}
}

View file

@ -0,0 +1,41 @@
//
// EventPub.cs
//
// Author:
// Paul Schneider <paulschneider@free.fr>
//
// Copyright (c) 2015 Paul Schneider
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using BookAStar.Model.Workflow.Messaging;
using System.Collections.Generic;
namespace BookAStar.Model.Social
{
/// <summary>
/// Event pub.
/// </summary>
public class CircleEvent: YaEvent
{
/// <summary>
/// Gets or sets the circles.
/// </summary>
/// <value>The circles.</value>
public virtual List<Circle> Circles{ get; set; }
}
}

View file

@ -0,0 +1,8 @@
namespace BookAStar.Model.Social
{
public partial class CircleMember
{
public long Id { get; set; }
}
}

View file

@ -0,0 +1,108 @@
namespace BookAStar.Model.Social
{
public class CompanyInfoMessage
{
public bool success { get; set; }
public string errorType { get; set; }
public string errorCode { get; set; }
public string errorMessage { get; set; }
public CompanyInfo result { get; set; }
}
public class CompanyInfo
{
public string registration_number { get; set; }
public string vat_number { get; set; }
public string name { get; set; }
public string commercial_name { get; set; }
public string business_name { get; set; }
public string ape_code { get; set; }
public string ape_label { get; set; }
public string rcs_name { get; set; }
public string greffe_name { get; set; }
public string legal_person_type { get; set; }
public string legal_state { get; set; }
public string legal_type { get; set; }
public string legal_status { get; set; }
public string activity { get; set; }
public string street { get; set; }
public string postal_code { get; set; }
public string country_code { get; set; }
public decimal lng { get; set; }
public decimal lat { get; set; }
public string phone_number { get; set; }
public string capital { get; set; }
public Employee[] contacts { get; set; }
public string[] emails { get; set; }
public Stat[] stats { get; set; }
public MarkDetail[] marks_details { get; set; }
public Bodacc last_bodacc { get; set; }
}
public class MarkDetail
{
public MarkClass[] classes { get; set; }
public Mark[] marks { get; set; }
}
public class MarkClass
{
public string number { get; set; }
public string description { get; set; }
}
public class Mark
{
public string name { get; set; }
public long application_date { get; set; }
}
public class Stat
{
public string type { get; set; }
public int year { get; set; }
public string value { get; set; }
}
public class Bodacc
{
public string type { get; set; }
public string bodacc_type { get; set; }
public long parution_date { get; set; }
public string number { get; set; }
public string rcs_name { get; set; }
public string legal_name { get; set; }
public string legal_status { get; set; }
public string capital { get; set; }
public string administration { get; set; }
public string address { get; set; }
public string description { get; set; }
}
public class Employee
{
public string name { get; set; }
public string role { get; set; }
}
}

View file

@ -0,0 +1,11 @@
namespace BookAStar.Model.Social
{
public class Contact
{
public string UserId { get; set; }
public string OwnerId { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show more