Paul Schneider 9 years ago
parent 32eaa116ad
commit fc8a64de96
26 changed files with 382 additions and 210 deletions

@ -323,7 +323,7 @@ namespace BookAStar.Droid
clientId: "d9be5e97-c19d-42e4-b444-0e65863b19e1", clientId: "d9be5e97-c19d-42e4-b444-0e65863b19e1",
clientSecret: "blouh", clientSecret: "blouh",
scope: "profile", scope: "profile",
authorizeUrl: new Uri("http://dev.pschneider.fr/authorize"), authorizeUrl: new Uri(Constants.AuthorizeUrl),
redirectUrl: new Uri("http://dev.pschneider.fr/oauth/success"), redirectUrl: new Uri("http://dev.pschneider.fr/oauth/success"),
accessTokenUrl: new Uri("http://dev.pschneider.fr/token")); accessTokenUrl: new Uri("http://dev.pschneider.fr/token"));
public void AddAccount() public void AddAccount()
@ -348,18 +348,15 @@ namespace BookAStar.Droid
{ {
using (var client = new HttpClient()) using (var client = new HttpClient())
{ {
// get me // get me
// var request = new OAuth2Request("GET", new Uri(Constants.UserInfoUrl), null, eventArgs.Account); using (var request = new HttpRequestMessage(HttpMethod.Get, Constants.UserInfoUrl))
var request = new HttpRequestMessage(HttpMethod.Get, Constants.UserInfoUrl); {
request.Headers.Authorization = request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokens.AccessToken); new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokens.AccessToken);
var response = await client.SendAsync(request); using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
string userJson = await response.Content.ReadAsStringAsync(); string userJson = await response.Content.ReadAsStringAsync();
JObject jactiveUser = JObject.Parse(userJson); JObject jactiveUser = JObject.Parse(userJson);
Account acc = eventArgs.Account; Account acc = eventArgs.Account;
@ -368,45 +365,31 @@ namespace BookAStar.Droid
var username = jactiveUser["UserName"].Value<string>(); var username = jactiveUser["UserName"].Value<string>();
var roles = jactiveUser["Roles"].Values<string>().ToList(); var roles = jactiveUser["Roles"].Values<string>().ToList();
var emails = jactiveUser["EMails"].Values<string>().ToList(); var emails = jactiveUser["EMails"].Values<string>().ToList();
var avatar = jactiveUser["Avatar"].Value<string>();
var address = jactiveUser["Avatar"].Value<string>();
var newuser = new User var newuser = new User
{ {
UserName = username, UserName = username,
EMails = emails, EMails = emails,
Roles = roles, Roles = roles,
Id = uid, Id = uid,
YavscTokens = tokens YavscTokens = tokens,
Avatar = avatar,
Address = address
}; };
MainSettings.SaveUser(newuser); MainSettings.SaveUser(newuser);
accStore.Save(acc, Constants.ApplicationName); accStore.Save(acc, Constants.ApplicationName);
} }
} }
}
); });
} }
}; };
auth.Error += Auth_Error; auth.Error += Auth_Error;
StartActivity(loginIntent); StartActivity(loginIntent);
} }
public static void PopulateUserWithAccount(User u, Account a)
{
u.YavscTokens = new Model.Auth.Account.Tokens
{
AccessToken =
a.Properties["access_token"],
RefreshToken =
a.Properties["refresh_token"],
ExpiresIn =
int.Parse(a.Properties["expires_in"]),
TokenType = a.Properties["token_type"]
};
u.UserName = a.Username;
}
private void Auth_Error(object sender, AuthenticatorErrorEventArgs e) private void Auth_Error(object sender, AuthenticatorErrorEventArgs e)
{ {
// TODO handle // TODO handle

@ -200,7 +200,7 @@ namespace BookAStar.Rendering
var uriImageLoader = imagesource as UriImageSource; var uriImageLoader = imagesource as UriImageSource;
if (uriImageLoader != null && uriImageLoader.Uri != null) if (uriImageLoader != null && uriImageLoader.Uri != null)
{ {
using (var client = UserHelpers.CreateClient()) using (var client = UserHelpers.CreateJsonClient())
{ {
using (var response = await client.GetAsync(uriImageLoader.Uri)) using (var response = await client.GetAsync(uriImageLoader.Uri))
{ {

@ -9,7 +9,7 @@
<ResourceDictionary> <ResourceDictionary>
<Color x:Key="PageBackgroundColor">#FFAAAAFF</Color> <Color x:Key="PageBackgroundColor">#FFAAAAFF</Color>
<Color x:Key="ContentBackgroundColor">#80AFAFAF</Color> <Color x:Key="ContentBackgroundColor">#80FFFFFF</Color>
<Color x:Key="BackgroundColor">#FFFFFFFF</Color> <Color x:Key="BackgroundColor">#FFFFFFFF</Color>
<Color x:Key="LabelBackgroundColor">#FFFFFFFF</Color> <Color x:Key="LabelBackgroundColor">#FFFFFFFF</Color>
@ -25,9 +25,9 @@
<Color x:Key="EmphasisTextColor">#800080</Color> <Color x:Key="EmphasisTextColor">#800080</Color>
<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="Font" Android="90" iOS="90" WinPhone="90" x:Key="LargeFontSize" /> <OnPlatform x:TypeArguments="x:Double" Android="22" iOS="22" WinPhone="22" x:Key="LargeFontSize" />
<OnPlatform x:TypeArguments="Font" Android="50" iOS="50" WinPhone="50" x:Key="MediumFontSize" /> <OnPlatform x:TypeArguments="x:Double" Android="16" iOS="16" WinPhone="16" x:Key="MediumFontSize" />
<OnPlatform x:TypeArguments="Font" Android="40" iOS="40" WinPhone="40" x:Key="SmallFontSize" /> <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" /> <OnPlatform x:TypeArguments="x:Double" Android="130" iOS="130" WinPhone="130" x:Key="BigUserAvatarSize" />
<Style x:Key="LabelPageHeadingStyle" TargetType="Label"> <Style x:Key="LabelPageHeadingStyle" TargetType="Label">

@ -28,6 +28,8 @@ namespace BookAStar
using ViewModels.EstimateAndBilling; using ViewModels.EstimateAndBilling;
using Pages.EstimatePages; using Pages.EstimatePages;
using ViewModels; using ViewModels;
using Pages.Chat;
using System.Collections.Generic;
public partial class App : Application // superclass new in 1.3 public partial class App : Application // superclass new in 1.3
{ {
@ -93,16 +95,21 @@ namespace BookAStar
// TODO special startup pages as // TODO special startup pages as
// notification details or wizard setup page // notification details or wizard setup page
} }
private INavigation Navigation
{
get
{
return masterDetail.Detail.Navigation;
}
}
// Called on rotation // Called on rotation
private void OnSuspended(object sender, EventArgs e) private void OnSuspended(object sender, EventArgs e)
{ {
// TODO save the navigation stack // TODO save the navigation stack
int position = 0; int position = 0;
DataManager.Current.AppState.Clear();
foreach (Page page in MainPage.Navigation.NavigationStack) foreach (Page page in Navigation.NavigationStack)
{ {
DataManager.Current.AppState.Add( DataManager.Current.AppState.Add(
new PageState new PageState
{ {
@ -141,7 +148,7 @@ namespace BookAStar
{ {
ViewFactory.EnableCache = true; ViewFactory.EnableCache = true;
ViewFactory.Register<ChatPage, ChatViewModel>( ViewFactory.Register<ChatPage, ChatViewModel>(
r=> new ChatViewModel { ChatUser = MainSettings.UserName } r=> new ChatViewModel { }
); );
ViewFactory.Register<DashboardPage, DashboardViewModel>( ViewFactory.Register<DashboardPage, DashboardViewModel>(
resolver => new DashboardViewModel()); resolver => new DashboardViewModel());
@ -183,13 +190,14 @@ namespace BookAStar
private void ShowPage(Page page) private void ShowPage(Page page)
{ {
if (masterDetail.Detail.Navigation.NavigationStack.Contains(page))
if (Navigation.NavigationStack.Contains(page))
{ {
if (masterDetail.Detail.Navigation.NavigationStack.Last() == page) return; if (Navigation.NavigationStack.Last() == page) return;
masterDetail.Detail.Navigation.RemovePage(page); Navigation.RemovePage(page);
page.Parent = null; page.Parent = null;
} }
masterDetail.Detail.Navigation.PushAsync(page); Navigation.PushAsync(page);
} }
private void BuildMainPage() private void BuildMainPage()
@ -261,11 +269,11 @@ namespace BookAStar
masterDetail.ToolbarItems.Add(tiPubChat); masterDetail.ToolbarItems.Add(tiPubChat);
this.MainPage = masterDetail; this.MainPage = masterDetail;
NavigationService = new NavigationService(masterDetail.Detail.Navigation); NavigationService = new NavigationService(Navigation);
} }
public static Task<string> DisplayActionSheet(string title, string cancel, string destruction, string [] buttons) public static Task<string> DisplayActionSheet(string title, string cancel, string destruction, string [] buttons)
{ {
var currentPage = CurrentApp.masterDetail.Detail.Navigation.NavigationStack.Last(); var currentPage = App.CurrentApp.Navigation.NavigationStack.Last();
return currentPage.DisplayActionSheet(title, cancel, destruction, buttons); return currentPage.DisplayActionSheet(title, cancel, destruction, buttons);
} }
@ -347,13 +355,13 @@ namespace BookAStar
private void MainSettings_UserChanged(object sender, EventArgs e) private void MainSettings_UserChanged(object sender, EventArgs e)
{ {
if (MainSettings.CurrentUser == null) if (chatHubConnection != null)
{ {
chatHubConnection.Dispose(); chatHubConnection.Dispose();
chatHubConnection = null; chatHubConnection = null;
chatHubProxy = null; chatHubProxy = null;
} }
else if (MainSettings.CurrentUser != null)
{ {
var token = MainSettings.CurrentUser.YavscTokens.AccessToken; var token = MainSettings.CurrentUser.YavscTokens.AccessToken;
SetupHubConnection(); SetupHubConnection();

@ -61,6 +61,10 @@
<Compile Include="Model\Settings\SignatureSettings.cs" /> <Compile Include="Model\Settings\SignatureSettings.cs" />
<Compile Include="Model\Social\Messaging\ChatStatus.cs" /> <Compile Include="Model\Social\Messaging\ChatStatus.cs" />
<Compile Include="Model\Social\Messaging\PrivateMessage.cs" /> <Compile Include="Model\Social\Messaging\PrivateMessage.cs" />
<Compile Include="Pages\Chat\PrivateChatPage.xaml.cs">
<DependentUpon>PrivateChatPage.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\Messaging\UserViewModel.cs" />
<Compile Include="ViewModels\Validation\Error.cs" /> <Compile Include="ViewModels\Validation\Error.cs" />
<Compile Include="ViewModels\Validation\ModelState.cs" /> <Compile Include="ViewModels\Validation\ModelState.cs" />
<Compile Include="ViewModels\PageState.cs" /> <Compile Include="ViewModels\PageState.cs" />
@ -135,7 +139,7 @@
<Compile Include="Pages\EstimatePages\BookQueryPage.xaml.cs"> <Compile Include="Pages\EstimatePages\BookQueryPage.xaml.cs">
<DependentUpon>BookQueryPage.xaml</DependentUpon> <DependentUpon>BookQueryPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\ChatPage.xaml.cs"> <Compile Include="Pages\Chat\ChatPage.xaml.cs">
<DependentUpon>ChatPage.xaml</DependentUpon> <DependentUpon>ChatPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\EstimatePages\EditBillingLinePage.xaml.cs"> <Compile Include="Pages\EstimatePages\EditBillingLinePage.xaml.cs">
@ -426,7 +430,7 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Pages\ChatPage.xaml"> <EmbeddedResource Include="Pages\Chat\ChatPage.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator> <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</EmbeddedResource> </EmbeddedResource>
@ -500,6 +504,12 @@
<Name>YavscLib</Name> <Name>YavscLib</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Pages\Chat\PrivateChatPage.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" /> <Import Project="..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

@ -26,6 +26,11 @@ namespace BookAStar
#endif #endif
#endif #endif
#endif #endif
public static readonly string SignInUrl = YavscHomeUrl + "/signin";
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 YavscApiUrl = YavscHomeUrl + "/api";
public static readonly string MobileRegistrationUrl = YavscApiUrl + "/gcm/register"; public static readonly string MobileRegistrationUrl = YavscApiUrl + "/gcm/register";
public static readonly string UserInfoUrl = YavscApiUrl + "/me"; public static readonly string UserInfoUrl = YavscApiUrl + "/me";

@ -28,7 +28,7 @@ namespace BookAStar.Data
} }
this.Add(estimate); this.Add(estimate);
} }
using (HttpClient client = UserHelpers.CreateClient()) using (HttpClient client = UserHelpers.CreateJsonClient())
{ {
try try
{ {

@ -17,7 +17,7 @@ namespace BookAStar.Data.NonCrUD
public override async void Execute(object parameter) public override async void Execute(object parameter)
{ {
BeforeExecute(); BeforeExecute();
using (var client = UserHelpers.CreateClient()) using (var client = UserHelpers.CreateJsonClient())
{ {
// Get the whole data // Get the whole data
try try

@ -49,7 +49,7 @@ namespace BookAStar.Data
public virtual async void Execute(object parameter) public virtual async void Execute(object parameter)
{ {
BeforeExecute(); BeforeExecute();
using (HttpClient client = UserHelpers.CreateClient()) using (HttpClient client = UserHelpers.CreateJsonClient())
{ {
// Get the whole data // Get the whole data
try try
@ -105,7 +105,7 @@ namespace BookAStar.Data
// Get the whole data // Get the whole data
var uri = GetUri(key); var uri = GetUri(key);
using (HttpClient client = UserHelpers.CreateClient()) using (HttpClient client = UserHelpers.CreateJsonClient())
{ {
using (var response = await client.GetAsync(uri)) using (var response = await client.GetAsync(uri))
{ {
@ -128,7 +128,7 @@ namespace BookAStar.Data
bool created = false; bool created = false;
BeforeExecute(); BeforeExecute();
using (HttpClient client = UserHelpers.CreateClient()) using (HttpClient client = UserHelpers.CreateJsonClient())
{ {
var stringContent = JsonConvert.SerializeObject(item); var stringContent = JsonConvert.SerializeObject(item);
@ -164,7 +164,7 @@ namespace BookAStar.Data
BeforeExecute(); BeforeExecute();
var uri = GetUri(GetKey(item)); var uri = GetUri(GetKey(item));
using (HttpClient client = UserHelpers.CreateClient()) using (HttpClient client = UserHelpers.CreateJsonClient())
{ {
HttpContent content = new StringContent( HttpContent content = new StringContent(
JsonConvert.SerializeObject(item), Encoding.UTF8, "application/json" JsonConvert.SerializeObject(item), Encoding.UTF8, "application/json"
@ -203,7 +203,7 @@ namespace BookAStar.Data
{ {
BeforeExecute(); BeforeExecute();
var uri = GetUri(key); var uri = GetUri(key);
using (HttpClient client = UserHelpers.CreateClient()) using (HttpClient client = UserHelpers.CreateJsonClient())
{ {
using (var response = await client.DeleteAsync(uri)) using (var response = await client.DeleteAsync(uri))
{ {

@ -17,22 +17,27 @@ namespace BookAStar.Helpers
{ {
var result = avatarPath == null ? var result = avatarPath == null ?
ImageSource.FromResource( "BookAStar.Images.Users.icon_user.png") : ImageSource.FromResource( "BookAStar.Images.Users.icon_user.png") :
avatarPath.StartsWith("res://") ? ImageSource.FromUri(new Uri(Constants.YavscHomeUrl+"/Avatars/"+avatarPath)) ;
ImageSource.FromResource(avatarPath.Substring(6)) :
ImageSource.FromUri(new Uri(avatarPath));
return result; return result;
} }
public static HttpClient CreateClient() public static HttpClient CreateJsonClient()
{
return CreateJsonClient(MainSettings.CurrentUser.YavscTokens.AccessToken);
}
public static HttpClient CreateJsonClient(string accessToken)
{ {
var client = new HttpClient(); var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue( new System.Net.Http.Headers.AuthenticationHeaderValue(
"Bearer", MainSettings.CurrentUser.YavscTokens.AccessToken); "Bearer", accessToken);
client.DefaultRequestHeaders.Add("Accept", "application/json"); client.DefaultRequestHeaders.Add("Accept", "application/json");
return client; return client;
} }
/// <summary> /// <summary>
/// Uploads the given stream to /// Uploads the given stream to
/// /api/fs, in order to be saved under the given file name /// /api/fs, in order to be saved under the given file name
@ -42,7 +47,7 @@ namespace BookAStar.Helpers
/// <returns></returns> /// <returns></returns>
public static async Task<bool> Upload(Stream inputStream, string fileName) public static async Task<bool> Upload(Stream inputStream, string fileName)
{ {
using (var client = CreateClient()) using (var client = CreateJsonClient())
{ {
using (var content = using (var content =
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture))) new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))

@ -1,12 +1,7 @@
using BookAStar.Helpers; using BookAStar.Helpers;
using Newtonsoft.Json; using Newtonsoft.Json;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms; using Xamarin.Forms;
namespace BookAStar.Model.Auth.Account namespace BookAStar.Model.Auth.Account
@ -81,6 +76,20 @@ namespace BookAStar.Model.Auth.Account
OnPropertyChanged("Avatar"); OnPropertyChanged("Avatar");
} }
} }
private string address;
public string Address
{
get
{
return address;
}
set
{
address = value;
OnPropertyChanged("Address");
}
}
[JsonIgnore] [JsonIgnore]
public ImageSource AvatarSource public ImageSource AvatarSource
{ {

@ -12,22 +12,14 @@ namespace BookAStar.Model
public string Avatar { get; set; } public string Avatar { get; set; }
public string UserId { 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 int Rate { get; set; }
public string EMail { get; set; } public string EMail { get; set; }
public string Phone { get; set; } public string Phone { get; set; }
public Location BillingAddress { get; set; } public Location BillingAddress { get; set; }
// TODO Get User Professional status existence as a boolean
// And hack the avatar with
[JsonIgnore]
public ImageSource AvatarOrNot
{
get
{
return UserHelpers.Avatar(Avatar);
}
}
public string ChatHubConnectionId { get; set; }
public override string ToString() public override string ToString()
{ {

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms" <TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BookAStar.Pages.ChatPage" x:Class="BookAStar.Pages.Chat.ChatPage"
xmlns:views="clr-namespace:BookAStar.Views;assembly=BookAStar" xmlns:views="clr-namespace:BookAStar.Views;assembly=BookAStar"
xmlns:controls="clr-namespace:XLabs.Forms.Controls;assembly=XLabs.Forms" xmlns:controls="clr-namespace:XLabs.Forms.Controls;assembly=XLabs.Forms"
xmlns:toolkit="clr-namespace:XLabs.Forms.Mvvm;assembly=XLabs.Forms" xmlns:toolkit="clr-namespace:XLabs.Forms.Mvvm;assembly=XLabs.Forms"
@ -105,10 +105,8 @@
<Entry x:Name="pvEntry" Placeholder = "enter your private message" <Entry x:Name="pvEntry" Placeholder = "enter your private message"
VerticalOptions = "Center" VerticalOptions = "Center"
HorizontalOptions = "FillAndExpand"></Entry> HorizontalOptions = "FillAndExpand"></Entry>
<!--
<controls:ExtendedPicker x:Name="contactPicker" Display="{Binding UserName}"></controls:ExtendedPicker>
-->
<controls:ExtendedPicker x:Name="contactPicker" ItemsSource="{Binding Contacts}" />
<Button x:Name="sendPVButton" Text = "Send" HorizontalOptions = "End" <Button x:Name="sendPVButton" Text = "Send" HorizontalOptions = "End"
VerticalOptions = "Center"></Button> VerticalOptions = "Center"></Button>
</StackLayout> </StackLayout>

@ -3,7 +3,7 @@ using System.Diagnostics;
using Microsoft.AspNet.SignalR.Client; using Microsoft.AspNet.SignalR.Client;
using Xamarin.Forms; using Xamarin.Forms;
namespace BookAStar.Pages namespace BookAStar.Pages.Chat
{ {
using Data; using Data;
using System.Linq; using System.Linq;
@ -19,7 +19,7 @@ namespace BookAStar.Pages
Title = "Chat"; Title = "Chat";
BindingContext = new ChatViewModel(); BindingContext = new ChatViewModel();
App.ChatHubConnection.StateChanged += ChatHubConnection_StateChanged;
sendButton.Clicked += async (sender, args) => sendButton.Clicked += async (sender, args) =>
{ {
IsBusy = true; IsBusy = true;
@ -38,17 +38,15 @@ namespace BookAStar.Pages
IsBusy = false; IsBusy = false;
}; };
/*
sendPVButton.Clicked += async (sender, args) => sendPVButton.Clicked += async (sender, args) =>
{ {
string userName = contactPicker.SelectedItem as string; string userName = contactPicker.SelectedItem as string;
if (string.IsNullOrEmpty(userName)) return; if (string.IsNullOrEmpty(userName)) return;
var user = DataManager.Current.Contacts.Single( var user = DataManager.Current.Contacts.Single(
c => c.UserName == userName); c => c.UserName == userName);
if (string.IsNullOrEmpty(user.ChatHubConnectionId)) return;
IsBusy = true; IsBusy = true;
try try
{ {
await App.ChatHubProxy.Invoke<string>("SendPV", user.ChatHubConnectionId, pvEntry.Text); await App.ChatHubProxy.Invoke<string>("SendPV", user.ChatHubConnectionId, pvEntry.Text);
pvEntry.Text = null; pvEntry.Text = null;
@ -58,7 +56,7 @@ namespace BookAStar.Pages
Debug.WriteLine(ex); Debug.WriteLine(ex);
} }
IsBusy = false; IsBusy = false;
}; };*/
} }

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BookAStar.Pages.Chat.PrivateChatPage">
<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BookAStar.Pages.Chat
{
public partial class PrivateChatPage : ContentPage
{
public PrivateChatPage()
{
InitializeComponent();
}
}
}

@ -21,36 +21,34 @@
<ContentPage.Content> <ContentPage.Content>
<ScrollView> <ScrollView>
<StackLayout BoxView.Color="{StaticResource ContentBackgroundColor}"> <StackLayout BoxView.Color="{StaticResource ContentBackgroundColor}">
<Label Text="{Binding UserName}" Style="{StaticResource LabelPageHeadingStyle}" <Image Source="{Binding Avatar}" HeightRequest="{StaticResource BigUserAvatarSize}" />
HorizontalTextAlignment="Center" <Button Text="{Binding UserName}" Clicked="OnRefreshQuery" />
LineBreakMode="WordWrap" XAlign="Center"
></Label>
<Image Source="{Binding Avatar}"
VisualElement.HeightRequest="{StaticResource BigUserAvatarSize}" />
<views:RatingView Rating="{Binding Rating, Mode=TwoWay}" x:Name="ratingView" />
<Button Text="{Binding UserFilesText}" Clicked="OnManageFiles" />
<StackLayout VisualElement.IsVisible="{Binding HaveAnUser}">
<Button Text="{Binding PerformerStatus}" Clicked="OnViewPerformerStatus" /> <Button Text="{Binding PerformerStatus}" Clicked="OnViewPerformerStatus" />
<Button Text="{Binding UserQueries}" Clicked="OnViewUserQueries" <Button Text="{Binding UserQueries}" Clicked="OnViewUserQueries"
VisualElement.IsVisible="{Binding UserIsPro}"/> VisualElement.IsVisible="{Binding UserIsPro}"/>
<Button Text="{Binding UserFilesLabel}" Clicked="OnManageFiles" /> <StackLayout Orientation="Horizontal">
<StackLayout Orientation="Horizontal" VisualElement.IsVisible="{Binding HaveAnUser}">
<Label Text="Recevoir les notifications push" StyleClass="Header" /> <Label Text="Recevoir les notifications push" StyleClass="Header" />
<Switch IsToggled="{Binding ReceivePushNotifications, Mode=TwoWay}" <Switch IsToggled="{Binding ReceivePushNotifications, Mode=TwoWay}"
HorizontalOptions="End" /> HorizontalOptions="End" />
</StackLayout> </StackLayout>
</StackLayout>
<StackLayout Orientation="Horizontal"> <StackLayout Orientation="Horizontal">
<Label Text="Utiliser ma position" StyleClass="Header" /> <Label Text="Utiliser ma position" StyleClass="Header" />
<Switch HorizontalOptions="End" IsToggled="{Binding AllowUseMyPosition, Mode=TwoWay}"/> <Switch HorizontalOptions="End" IsToggled="{Binding AllowUseMyPosition, Mode=TwoWay}"/>
</StackLayout> </StackLayout>
<StackLayout Orientation="Horizontal" VerticalOptions="Start" <StackLayout VisualElement.IsVisible="{Binding UserIsPro}" >
VisualElement.IsVisible="{Binding UserIsPro}" > <Label Text="{x:Static local:Strings.Profprof}" Style="{StaticResource LabelStyle}"/>
<views:RatingView Rating="{Binding Rating, Mode=TwoWay}" x:Name="ratingView" />
<StackLayout Orientation="Horizontal" VerticalOptions="Start">
<Label Text="Ne recevoir de demande de devis que de la part de professionnels uniquement" /> <Label Text="Ne recevoir de demande de devis que de la part de professionnels uniquement" />
<Switch HorizontalOptions="End" IsToggled="{Binding AllowProBookingOnly, Mode=TwoWay}"/> <Switch HorizontalOptions="End" IsToggled="{Binding AllowProBookingOnly, Mode=TwoWay}"/>
</StackLayout> </StackLayout>
</StackLayout> </StackLayout>
</StackLayout>
</ScrollView> </ScrollView>
</ContentPage.Content> </ContentPage.Content>
</ContentPage> </ContentPage>

@ -5,6 +5,10 @@ using XLabs.Forms.Behaviors;
namespace BookAStar.Pages.UserProfile namespace BookAStar.Pages.UserProfile
{ {
using Data; using Data;
using Helpers;
using Newtonsoft.Json.Linq;
using System.Linq;
using System.Net.Http;
using ViewModels.UserProfile; using ViewModels.UserProfile;
public partial class DashboardPage : ContentPage public partial class DashboardPage : ContentPage
@ -18,11 +22,36 @@ namespace BookAStar.Pages.UserProfile
protected override void OnBindingContextChanged() protected override void OnBindingContextChanged()
{ {
base.OnBindingContextChanged(); base.OnBindingContextChanged();
// Assert ((DashboardViewModel)BindingContext!=null) }
((DashboardViewModel)BindingContext).UserNameGesture
= new RelayGesture( (gesture,arg) => { public async void OnRefreshQuery(object sender, EventArgs e)
ShowPage<AccountChooserPage>(null, true); {
}); IsBusy = true;
using (var client = UserHelpers.CreateJsonClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Get, Constants.UserInfoUrl))
{
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
string userJson = await response.Content.ReadAsStringAsync();
JObject jactiveUser = JObject.Parse(userJson);
var username = jactiveUser["UserName"].Value<string>();
var roles = jactiveUser["Roles"].Values<string>().ToList();
var emails = jactiveUser["EMails"].Values<string>().ToList();
var avatar = jactiveUser["Avatar"].Value<string>();
var address = jactiveUser["Avatar"].Value<string>();
var me = MainSettings.CurrentUser;
me.Address = address;
me.Avatar = avatar;
me.EMails = emails;
me.UserName = username;
me.Roles = roles;
MainSettings.SaveUser(me);
}
}
}
IsBusy = false;
} }
public void OnManageFiles(object sender, EventArgs e) public void OnManageFiles(object sender, EventArgs e)

@ -171,21 +171,34 @@ namespace BookAStar
public static event EventHandler<EventArgs> UserChanged; public static event EventHandler<EventArgs> UserChanged;
/// <summary>
/// Saves the given user account in the account list.
/// An existent presenting the same Id will be dropped.
/// </summary>
/// <param name="user"></param>
public static void SaveUser(User user) public static void SaveUser(User user)
{ {
var existent = AccountList.FirstOrDefault(u => u.UserName == user.UserName); var existent = AccountList.FirstOrDefault(u => u.Id == user.Id);
if (existent != null) if (existent != null)
AccountList.Remove(existent); AccountList.Remove(existent);
AccountList.Add(user); AccountList.Add(user);
var json = JsonConvert.SerializeObject(AccountList.ToArray()); var json = JsonConvert.SerializeObject(AccountList.ToArray());
AppSettings.AddOrUpdateValue(UserListsKey, json); AppSettings.AddOrUpdateValue(UserListsKey, json);
} }
/// <summary>
/// Gets an account connection info, given its name
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
public static User GetUser(string username) public static User GetUser(string username)
{ {
return AccountList.FirstOrDefault(a => a.UserName == username); return AccountList.FirstOrDefault(a => a.UserName == username);
} }
// FIXME real time usage
/// <summary>
/// Enables/disables push notifications
/// </summary>
public static bool PushNotifications public static bool PushNotifications
{ {
get get
@ -203,6 +216,10 @@ namespace BookAStar
} }
} }
// FIXME real time usage
/// <summary>
/// Enables/disables GPS usage
/// </summary>
public static bool AllowGPSUsage public static bool AllowGPSUsage
{ {
get get
@ -218,7 +235,11 @@ namespace BookAStar
value); value);
} }
} }
// TODO make it a server side user's parameter // TODO make it a server side user's parameter
/// <summary>
/// Only allow professionals to ask for user's services
/// </summary>
public static bool AllowProBookingOnly public static bool AllowProBookingOnly
{ {
get get

@ -214,6 +214,15 @@ namespace BookAStar {
} }
} }
/// <summary>
/// Recherche une chaîne localisée semblable à Profile professionnel.
/// </summary>
public static string Profprof {
get {
return ResourceManager.GetString("Profprof", resourceCulture);
}
}
/// <summary> /// <summary>
/// Recherche une chaîne localisée semblable à Signer. /// Recherche une chaîne localisée semblable à Signer.
/// </summary> /// </summary>
@ -268,6 +277,15 @@ namespace BookAStar {
} }
} }
/// <summary>
/// Recherche une chaîne localisée semblable à Vos fichiers .
/// </summary>
public static string YourFiles {
get {
return ResourceManager.GetString("YourFiles", resourceCulture);
}
}
/// <summary> /// <summary>
/// Recherche une chaîne localisée semblable à Votre texte a été taillé car il était trop long.. /// Recherche une chaîne localisée semblable à Votre texte a été taillé car il était trop long..
/// </summary> /// </summary>

@ -191,4 +191,10 @@
<data name="MinMaxIntError" xml:space="preserve"> <data name="MinMaxIntError" xml:space="preserve">
<value>Veuillez saisir une valeur entre {0} et {1}.</value> <value>Veuillez saisir une valeur entre {0} et {1}.</value>
</data> </data>
<data name="YourFiles" xml:space="preserve">
<value>Vos fichiers </value>
</data>
<data name="Profprof" xml:space="preserve">
<value>Profile professionnel</value>
</data>
</root> </root>

@ -136,18 +136,20 @@ namespace BookAStar.ViewModels.EstimateAndBilling
{ {
get get
{ {
/*
OnPlatform<Font> lfs = (OnPlatform<Font>)App.Current.Resources["MediumFontSize"]; OnPlatform<Font> lfs = (OnPlatform<Font>)App.Current.Resources["MediumFontSize"];
*/
OnPlatform<double> mfs = (OnPlatform < double > ) App.Current.Resources["MediumFontSize"];
Color etc = (Color) App.Current.Resources["EmphasisTextColor"]; Color etc = (Color) App.Current.Resources["EmphasisTextColor"];
return new FormattedString return new FormattedString
{ {
Spans = { Spans = {
new Span { Text = "Total TTC: " }, new Span { Text = "Total TTC: " },
new Span { Text = Data.Total.ToString(), new Span { Text = Data.Total.ToString(),
ForegroundColor = etc, ForegroundColor = etc,
FontSize = (double) lfs.Android.FontSize }, FontSize = mfs },
new Span { Text = "€", FontSize = (double) lfs.Android.FontSize } new Span { Text = "€", FontSize = mfs }
} }
}; };
} }

@ -7,7 +7,6 @@ using XLabs.Forms.Mvvm;
namespace BookAStar.ViewModels.Messaging namespace BookAStar.ViewModels.Messaging
{ {
using Data; using Data;
using Model;
using Model.Social.Messaging; using Model.Social.Messaging;
class ChatViewModel: ViewModel class ChatViewModel: ViewModel
@ -15,19 +14,8 @@ namespace BookAStar.ViewModels.Messaging
public ObservableCollection<ChatMessage> Messages { get; set; } public ObservableCollection<ChatMessage> Messages { get; set; }
public ObservableCollection<ChatMessage> Notifs { get; set; } public ObservableCollection<ChatMessage> Notifs { get; set; }
public ObservableCollection<ChatMessage> PVs { get; set; } public ObservableCollection<ChatMessage> PVs { get; set; }
public ObservableCollection<ClientProviderInfo> Contacts { get; set; } public ObservableCollection<UserViewModel> Contacts { get; set; }
private string chatUser;
public string ChatUser
{
get
{
return chatUser;
}
set
{
SetProperty<string>(ref chatUser, value);
}
}
private ConnectionState state; private ConnectionState state;
public ConnectionState State public ConnectionState State
{ {
@ -41,7 +29,9 @@ namespace BookAStar.ViewModels.Messaging
Messages = new ObservableCollection<ChatMessage>(); Messages = new ObservableCollection<ChatMessage>();
Notifs = new ObservableCollection<ChatMessage>(); Notifs = new ObservableCollection<ChatMessage>();
PVs = DataManager.Current.PrivateMessages; PVs = DataManager.Current.PrivateMessages;
Contacts = DataManager.Current.Contacts; Contacts =
new ObservableCollection<UserViewModel>(
DataManager.Current.Contacts.Select(c=>new UserViewModel { Data = c }));
App.ChatHubProxy.On<string, string>("addMessage", (n, m) => App.ChatHubProxy.On<string, string>("addMessage", (n, m) =>
{ {
Messages.Add(new ChatMessage Messages.Add(new ChatMessage
@ -54,45 +44,44 @@ namespace BookAStar.ViewModels.Messaging
App.ChatHubProxy.On<string, string, string>("notify", (eventId, cxId, userName) => App.ChatHubProxy.On<string, string, string>("notify", (eventId, cxId, userName) =>
{ {
// TODO make admin possible var msg = new ChatMessage
// by assigning a server side username to anonymous.
// From now, don't log anonymous
if (!string.IsNullOrEmpty(userName))
{
Notifs.Add(new ChatMessage
{ {
Message = eventId, Message = eventId,
SenderId = userName, SenderId = userName,
Date = DateTime.Now Date = DateTime.Now
}); };
// TODO make admin possible
// by assigning a server side username to anonymous.
if (string.IsNullOrEmpty(userName))
{
msg.SenderId = $"({cxId})";
}
Notifs.Add(msg);
if (eventId == "connected") if (eventId == "connected")
OnUserConnected(cxId, userName); OnUserConnected(cxId, userName);
else if (eventId == "disconnected") else if (eventId == "disconnected")
OnUserDisconnected(userName); OnUserDisconnected(userName);
}
}); });
ChatUser = MainSettings.UserName;
} }
private void OnUserConnected(string cxId, string userName) private void OnUserConnected(string cxId, string userName)
{ {
var user = Contacts.SingleOrDefault( var user = Contacts.SingleOrDefault(
c => c.UserName == userName); c => c.Data.UserName == userName);
if (user != null) if (user != null)
user.ChatHubConnectionId = cxId; user.ConnexionId = cxId;
} }
private void OnUserDisconnected (string userName) private void OnUserDisconnected (string userName)
{ {
var user = Contacts.SingleOrDefault( var user = Contacts.SingleOrDefault(
c => c.UserName == userName); c => c.Data.UserName == userName);
if (user != null) if (user != null)
user.ChatHubConnectionId = null; user.ConnexionId = null;
} }
private void MainSettings_UserChanged(object sender, EventArgs e) private void MainSettings_UserChanged(object sender, EventArgs e)
{ {
ChatUser = MainSettings.UserName;
} }
private void ChatHubConnection_StateChanged(StateChange obj) private void ChatHubConnection_StateChanged(StateChange obj)

@ -0,0 +1,57 @@
using BookAStar.Helpers;
using BookAStar.Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using XLabs.Forms.Mvvm;
namespace BookAStar.ViewModels.Messaging
{
class UserViewModel : ViewModel
{
private ClientProviderInfo data;
public ClientProviderInfo Data {
get
{
return data;
}
set
{
SetProperty(ref data, value);
NotifyPropertyChanged("Avatar");
}
}
private string connexionId;
public string ConnexionId
{
get
{
return connexionId;
}
set
{
SetProperty(ref connexionId, value);
NotifyPropertyChanged("Connected");
}
}
public bool Connected
{
get { return connexionId != null; }
}
[JsonIgnore]
public ImageSource Avatar
{
get
{
return UserHelpers.Avatar(Data.Avatar);
}
}
}
}

@ -13,6 +13,7 @@ namespace BookAStar.ViewModels.UserProfile
using Helpers; using Helpers;
using Model.Auth.Account; using Model.Auth.Account;
using Pages.UserProfile; using Pages.UserProfile;
using System.Threading.Tasks;
internal class DashboardViewModel : ViewModel internal class DashboardViewModel : ViewModel
{ {
@ -97,7 +98,6 @@ namespace BookAStar.ViewModels.UserProfile
if (user!=null) if (user!=null)
{ {
user.PropertyChanged += User_PropertyChanged; user.PropertyChanged += User_PropertyChanged;
} }
UpdateUserMeta(); UpdateUserMeta();
@ -173,13 +173,15 @@ namespace BookAStar.ViewModels.UserProfile
private void UpdateUserMeta () private void UpdateUserMeta ()
{ {
Task.Run( ()=> {
string newStatusString; string newStatusString;
long newQueryCount; long newQueryCount;
bool newUserIsPro; bool newUserIsPro;
ImageSource newAvatar; ImageSource newAvatar;
string newQueriesButtonText; string newQueriesButtonText;
bool newHaveAnUser = user == null; bool newHaveAnUser = user == null;
if (newHaveAnUser) { if (newHaveAnUser)
{
newQueryCount = 0; newQueryCount = 0;
newUserIsPro = false; newUserIsPro = false;
newStatusString = null; newStatusString = null;
@ -205,8 +207,20 @@ namespace BookAStar.ViewModels.UserProfile
SetProperty<string>(ref performerStatus, newStatusString, "PerformerStatus"); SetProperty<string>(ref performerStatus, newStatusString, "PerformerStatus");
SetProperty<string>(ref userQueries, newQueriesButtonText, "UserQueries"); SetProperty<string>(ref userQueries, newQueriesButtonText, "UserQueries");
SetProperty<long>(ref queryCount, newQueryCount, "QueryCount"); SetProperty<long>(ref queryCount, newQueryCount, "QueryCount");
try
{
SetProperty<ImageSource>(ref avatar, newAvatar, "Avatar"); SetProperty<ImageSource>(ref avatar, newAvatar, "Avatar");
} }
catch (TaskCanceledException)
{ }
NotifyPropertyChanged("UserName");
NotifyPropertyChanged("UserId");
NotifyPropertyChanged("HaveAnUser");
NotifyPropertyChanged("UserIsPro");
});
}
private void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) private void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{ {
@ -214,6 +228,12 @@ namespace BookAStar.ViewModels.UserProfile
} }
public RelayGesture UserNameGesture { get; set; } public RelayGesture UserNameGesture { get; set; }
public string UserFilesText
{
get
{
return Strings.YourFiles;
}
}
} }
} }

@ -15,7 +15,7 @@
</ContentView.Resources> </ContentView.Resources>
<ContentView.Content> <ContentView.Content>
<StackLayout> <StackLayout>
<StackLayout Orientation="Horizontal" > <StackLayout Orientation="Horizontal" VisualElement.HeightRequest="{StaticResource SmallFontSize}" >
<Grid> <Grid>
<Grid.Behaviors> <Grid.Behaviors>
<behaviors:StarBehavior x:Name="starOne" GroupName="myStar"/> <behaviors:StarBehavior x:Name="starOne" GroupName="myStar"/>

Loading…