WIP private chat

main
Paul Schneider 9 years ago
parent ca1f577385
commit a841c0e391
13 changed files with 286 additions and 157 deletions

@ -62,12 +62,12 @@
<Compile Include="Model\Settings\SignatureSettings.cs" /> <Compile Include="Model\Settings\SignatureSettings.cs" />
<Compile Include="Model\Social\Chat\ChatStatus.cs" /> <Compile Include="Model\Social\Chat\ChatStatus.cs" />
<Compile Include="Model\Social\Chat\ChatMessage.cs" /> <Compile Include="Model\Social\Chat\ChatMessage.cs" />
<Compile Include="Model\Social\Chat\ChatUserInfo.cs" /> <Compile Include="ViewModels\Messaging\ChatUserCollection.cs" />
<Compile Include="ViewModels\Messaging\ChatUserInfo.cs" />
<Compile Include="Model\Social\Chat\Connection.cs" /> <Compile Include="Model\Social\Chat\Connection.cs" />
<Compile Include="Pages\Chat\PrivateChatPage.xaml.cs"> <Compile Include="Pages\Chat\PrivateChatPage.xaml.cs">
<DependentUpon>PrivateChatPage.xaml</DependentUpon> <DependentUpon>PrivateChatPage.xaml</DependentUpon>
</Compile> </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" />

@ -8,13 +8,13 @@
using NonCrUD; using NonCrUD;
using ViewModels; using ViewModels;
using Model.Access; using Model.Access;
using Model.Social.Chat; using ViewModels.Messaging;
public class DataManager public class DataManager
{ {
// TODO estimatetemplate rating service product tag // TODO estimatetemplate rating service product tag
public RemoteEntityRO<BookQueryData, long> BookQueries { get; set; } public RemoteEntityRO<BookQueryData, long> BookQueries { get; set; }
public RemoteEntityRO<ChatUserInfo, long> ChatUsers { get; set; } public ChatUserCollection ChatUsers { get; set; }
public EstimateEntity Estimates { get; set; } public EstimateEntity Estimates { get; set; }
public RemoteEntity<Blog, long> Blogspot { get; set; } public RemoteEntity<Blog, long> Blogspot { get; set; }
internal RemoteFilesEntity RemoteFiles { get; set; } internal RemoteFilesEntity RemoteFiles { get; set; }
@ -52,8 +52,7 @@
PrivateMessages = new LocalEntity<ChatMessage, int>(m=> m.GetHashCode()); PrivateMessages = new LocalEntity<ChatMessage, int>(m=> m.GetHashCode());
RemoteFiles = new RemoteFilesEntity (); RemoteFiles = new RemoteFilesEntity ();
BlackList = new RemoteEntity<BlackListed, long>("blacklist",u => u.Id); BlackList = new RemoteEntity<BlackListed, long>("blacklist",u => u.Id);
ChatUsers = new RemoteEntityRO<ChatUserInfo, long> ChatUsers = new ChatUserCollection();
("chat/users", u => u.UserId);
PrivateMessages.Load(); PrivateMessages.Load();
BookQueries.Load(); BookQueries.Load();
Estimates.Load(); Estimates.Load();
@ -64,6 +63,8 @@
EstimateLinesTemplates.Load(); EstimateLinesTemplates.Load();
RemoteFiles.Load(); RemoteFiles.Load();
BlackList.Load(); BlackList.Load();
ChatUsers.Load();
BlackList.Load();
} }
} }
} }

@ -1,33 +0,0 @@

using YavscLib;
namespace BookAStar.Model.Social.Chat
{
public class ChatUserInfo : IChatUserInfo
{
public string Avatar
{
get; set;
}
public IConnection[] Connections
{
get; set;
}
public string[] Roles
{
get; set;
}
public string UserId
{
get; set;
}
public string UserName
{
get; set;
}
}
}

@ -110,7 +110,7 @@
<Button x:Name="sendPVButton" Text = "Send" HorizontalOptions = "End" <Button x:Name="sendPVButton" Text = "Send" HorizontalOptions = "End"
VerticalOptions = "Center"></Button> VerticalOptions = "Center"></Button>
</StackLayout> </StackLayout>
<ListView x:Name="PVList" HasUnevenRows="true" ItemsSource="{Binding PVs}"> <!-- <ListView x:Name="PVList" HasUnevenRows="true" ItemsSource="{Binding PVs}">
<ListView.ItemTemplate HeightRequest="80" <ListView.ItemTemplate HeightRequest="80"
VerticalOptions="StartAndExpand"> VerticalOptions="StartAndExpand">
<DataTemplate> <DataTemplate>
@ -126,8 +126,8 @@
</ViewCell> </ViewCell>
</DataTemplate> </DataTemplate>
</ListView.ItemTemplate> </ListView.ItemTemplate>
</ListView> </ListView> -->
<!-- <views:UserListView ItemsSource="" /> --> <views:UserListView x:Name="chatUserList" />
</StackLayout> </StackLayout>
</ContentPage> </ContentPage>

@ -23,7 +23,6 @@ namespace BookAStar.Pages.Chat
name: "...", name: "...",
icon: null, icon: null,
activated: () => { })); */ activated: () => { })); */
BindingContext = new ChatViewModel();
App.ChatHubConnection.StateChanged += ChatHubConnection_StateChanged; App.ChatHubConnection.StateChanged += ChatHubConnection_StateChanged;
sendButton.Clicked += async (sender, args) => sendButton.Clicked += async (sender, args) =>
{ {
@ -43,6 +42,8 @@ namespace BookAStar.Pages.Chat
IsBusy = false; IsBusy = false;
}; };
chatUserList.BindingContext = DataManager.Instance.ChatUsers;
/* /*
sendPVButton.Clicked += async (sender, args) => sendPVButton.Clicked += async (sender, args) =>
{ {

@ -0,0 +1,34 @@
using BookAStar.Data;
using BookAStar.Model.Social.Chat;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
namespace BookAStar.ViewModels.Messaging
{
public class ChatUserCollection : RemoteEntityRO<ChatUserInfo, string>
{
public ChatUserCollection() : base ("chat/users", u=>u.UserId)
{
}
public override void Merge(ChatUserInfo item)
{
var key = GetKey(item);
var existent = this.FirstOrDefault(u => u.UserId == key);
if (existent != null) {
existent.UserName = item.UserName;
existent.Roles = item.Roles;
existent.Avatar = item.Avatar;
existent.Connections = item.Connections;
}
else Add(item);
}
}
}

@ -0,0 +1,159 @@

using BookAStar.Helpers;
using System.Collections.ObjectModel;
using System.Linq;
using Xamarin.Forms;
using XLabs.Forms.Mvvm;
using YavscLib;
using System;
using Newtonsoft.Json;
namespace BookAStar.Model.Social.Chat
{
public class ChatUserInfo : ViewModel, IChatUserInfo
{
public string avatar;
public string Avatar
{
get
{
return avatar;
}
set
{
var newSource = UserHelpers.Avatar(value);
SetProperty<string>(ref avatar, value);
SetProperty<ImageSource>(ref avatarSource, newSource, "AvatarSource");
}
}
ImageSource avatarSource;
[JsonIgnore]
public ImageSource AvatarSource
{
get
{
return avatarSource;
}
}
public Connection [] Connections
{
get
{
return ObservableConnections?.ToArray();
}
set
{
ObservableConnections = new ObservableCollection<Connection>(value);
}
}
ObservableCollection<Connection> connections;
[JsonIgnore]
public ObservableCollection<Connection> ObservableConnections
{
get
{
return connections;
}
set
{
SetProperty<ObservableCollection<Connection>>(ref connections, value);
}
}
string[] roles;
public string[] Roles
{
get
{
return roles;
}
set
{
SetProperty<string[]>(ref roles, value);
NotifyPropertyChanged("RolesAsAString");
}
}
[JsonIgnore]
public string RolesAsAString
{
get
{
return string.Join(", ", Roles);
}
}
string userId;
public string UserId
{
get
{
return userId;
}
set
{
SetProperty<string>(ref userId, value);
}
}
string userName;
public string UserName
{
get
{
return userName;
}
set
{
SetProperty<string>(ref userName, value);
}
}
public bool IsConnected { get
{
return Connections.Length > 0;
} }
[JsonIgnore]
IConnection[] IChatUserInfo.Connections
{
get
{
return Connections;
}
set
{
throw new NotImplementedException();
}
}
public void OnConnected(string cxId)
{
// We do assume this cxId dosn't already exist in this list.
var cx = new Connection { ConnectionId = cxId, Connected = true };
if (ObservableConnections == null)
ObservableConnections = new ObservableCollection<Connection>();
ObservableConnections.Add(cx);
if (this.ObservableConnections.Count == 1)
NotifyPropertyChanged("IsConnected");
}
public void OnDisconnected(string cxId)
{
var existentcx = Connections.FirstOrDefault(cx => cx.ConnectionId == cxId);
if (existentcx != null)
{
this.ObservableConnections.Remove(existentcx);
if (this.ObservableConnections.Count == 0)
NotifyPropertyChanged("IsConnected");
}
}
}
}

@ -7,6 +7,7 @@ using XLabs.Forms.Mvvm;
namespace BookAStar.ViewModels.Messaging namespace BookAStar.ViewModels.Messaging
{ {
using Data; using Data;
using Model.Social.Chat;
using Model.Social.Messaging; using Model.Social.Messaging;
class ChatViewModel: ViewModel class ChatViewModel: ViewModel
@ -14,7 +15,7 @@ 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<UserViewModel> Contacts { get; set; } public ChatUserCollection ChatUsers { get; set; }
private ConnectionState state; private ConnectionState state;
public ConnectionState State public ConnectionState State
@ -29,9 +30,7 @@ namespace BookAStar.ViewModels.Messaging
Messages = new ObservableCollection<ChatMessage>(); Messages = new ObservableCollection<ChatMessage>();
Notifs = new ObservableCollection<ChatMessage>(); Notifs = new ObservableCollection<ChatMessage>();
PVs = DataManager.Instance.PrivateMessages; PVs = DataManager.Instance.PrivateMessages;
Contacts = ChatUsers = DataManager.Instance.ChatUsers;
new ObservableCollection<UserViewModel>(
DataManager.Instance.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
@ -60,24 +59,33 @@ namespace BookAStar.ViewModels.Messaging
if (eventId == "connected") if (eventId == "connected")
OnUserConnected(cxId, userName); OnUserConnected(cxId, userName);
else if (eventId == "disconnected") else if (eventId == "disconnected")
OnUserDisconnected(userName); OnUserDisconnected(cxId, userName);
}); });
} }
private void OnUserConnected(string cxId, string userName) private void OnUserConnected(string cxId, string userName)
{ {
var user = Contacts.SingleOrDefault( var user = ChatUsers.SingleOrDefault(
c => c.Data.UserName == userName); c => c.UserName == userName);
if (user != null) if (user == null)
user.ConnexionId = cxId; {
user = new ChatUserInfo {
UserName = userName
};
ChatUsers.Add(user);
}
user.OnConnected(cxId);
} }
private void OnUserDisconnected (string userName) private void OnUserDisconnected (string cxId, string userName)
{ {
var user = Contacts.SingleOrDefault( var user = ChatUsers.SingleOrDefault(
c => c.Data.UserName == userName); c => c.UserName == userName);
if (user != null) if (user == null)
user.ConnexionId = null; {
return;
}
user.OnDisconnected(cxId);
} }
private void MainSettings_UserChanged(object sender, EventArgs e) private void MainSettings_UserChanged(object sender, EventArgs e)

@ -1,75 +0,0 @@
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);
}
}
[JsonIgnore]
public ImageSource SmallAvatar
{
get
{
return UserHelpers.SmallAvatar(Data.Avatar, Data.UserName);
}
}
[JsonIgnore]
public ImageSource ExtraSmallAvatar
{
get
{
return UserHelpers.ExtraSmallAvatar(Data.Avatar, Data.UserName);
}
}
}
}

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

@ -15,16 +15,18 @@
</ResourceDictionary> </ResourceDictionary>
</ContentView.Resources> </ContentView.Resources>
<ContentView.Content> <ContentView.Content>
<ListView x:Name="list" ItemTapped="OnViewDetail" HasUnevenRows="true" RowHeight="80"> <ListView x:Name="list" IsPullToRefreshEnabled="True"
HasUnevenRows="true" RowHeight="80" ItemsSource="{Binding .}"
SeparatorVisibility="Default" SeparatorColor="Black">
<ListView.ItemTemplate HeightRequest="80" VerticalOptions="StartAndExpand"> <ListView.ItemTemplate HeightRequest="80" VerticalOptions="StartAndExpand">
<DataTemplate> <DataTemplate>
<ViewCell> <ViewCell>
<ViewCell.View> <ViewCell.View>
<StackLayout Orientation="Horizontal" Padding="10,10,10,10" VerticalOptions="StartAndExpand"> <StackLayout Orientation="Horizontal" Padding="10,10,10,10" VerticalOptions="StartAndExpand">
<Image Source="{Binding AvatarOrNot}" Aspect="AspectFit" /> <Image Source="{Binding AvatarSource}" Aspect="AspectFit" />
<Label Text="{Binding UserName}" /> <Label Text="{Binding UserName}" />
<Label Text="{Binding EMail}" /> <Label Text="{Binding RolesAsAString}" TextColor="{StaticResource QuietTextColor}"
FontSize="{StaticResource SmallFontSize}"/>
</StackLayout> </StackLayout>
</ViewCell.View> </ViewCell.View>
</ViewCell> </ViewCell>

@ -1,4 +1,5 @@
using BookAStar.Model; using BookAStar.Model;
using BookAStar.ViewModels.Messaging;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -6,7 +7,7 @@ using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms; using Xamarin.Forms;
namespace BookAStar.Views namespace BookAStar.Views
@ -14,24 +15,57 @@ namespace BookAStar.Views
public partial class UserListView : ContentView public partial class UserListView : ContentView
{ {
public BindableProperty ItemsSourceProperty = BindableProperty.Create( public BindableProperty ItemsSourceProperty = BindableProperty.Create(
"ItemsSource", typeof(IEnumerable), typeof(UserListView)); "ItemsSource", typeof(ChatUserCollection), typeof(UserListView), default(ChatUserCollection),
BindingMode.OneWay);
public BindableProperty ItemSelectedProperty = BindableProperty.Create(
"ItemSelected", typeof(ICommand), typeof(UserListView), default(ICommand));
public BindableProperty DisableSelectionProperty = BindableProperty.Create(
"DisableSelection", typeof(bool), typeof(UserListView), false);
public IEnumerable ItemsSource public ChatUserCollection ItemsSource
{ {
get { return list.ItemsSource; } get { return (ChatUserCollection) GetValue(ItemsSourceProperty); }
set { list.ItemsSource = value; } set { SetValue(ItemsSourceProperty, value); }
} }
/* public IEnumerable ItemsSource public ICommand ItemSelected
{ {
get { return GetValue(ItemsSourceProperty) as IEnumerable; } get { return (ICommand) GetValue(ItemSelectedProperty); }
set { SetValue(ItemsSourceProperty, value); } set { SetValue(ItemSelectedProperty, value); }
} }
*/
public bool DisableSelection
{
get { return (bool) GetValue(DisableSelectionProperty); }
set { SetValue(DisableSelectionProperty, value); }
}
public UserListView() public UserListView()
{ {
InitializeComponent(); InitializeComponent();
} list.ItemSelected += OnUserSelected;
} }
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
ICommand dataCommand = (ICommand) BindingContext;
list.RefreshCommand = new Command(
() => {
dataCommand.Execute(null);
list.EndRefresh();
});
}
public void OnUserSelected(object sender, SelectedItemChangedEventArgs ev)
{
if (ItemSelected != null)
if (ItemSelected.CanExecute(ev.SelectedItem))
{
ItemSelected.Execute(ev.SelectedItem);
}
if (DisableSelection) list.SelectedItem = null;
}
}
} }

@ -3,20 +3,18 @@
"version": 2, "version": 2,
"targets": { "targets": {
".NETFramework,Version=v4.5.1": {}, ".NETFramework,Version=v4.5.1": {},
".NETPortable,Version=v4.5,Profile=Profile111": {}, ".NETPortable,Version=v4.5,Profile=Profile111": {}
".NETFramework,Version=v4.5.1/debian.8-x86": {},
".NETFramework,Version=v4.5.1/debian.8-x64": {},
".NETPortable,Version=v4.5,Profile=Profile111/debian.8-x86": {},
".NETPortable,Version=v4.5,Profile=Profile111/debian.8-x64": {}
}, },
"libraries": {}, "libraries": {},
"projectFileDependencyGroups": { "projectFileDependencyGroups": {
"": [], "": [],
".NETFramework,Version=v4.5.1": [], ".NETFramework,Version=v4.5.1": [],
".NETPortable,Version=v4.5,Profile=Profile111": [ ".NETPortable,Version=v4.5,Profile=Profile111": [
"fx/System.Runtime >= 4.0.0", "System.Globalization >= 4.0.0",
"fx/System.Globalization >= 4.0.0", "System.Resources.ResourceManager >= 4.0.0",
"fx/System.Resources.ResourceManager >= 4.0.0" "System.Runtime >= 4.0.0"
] ]
} },
"tools": {},
"projectFileToolGroups": {}
} }
Loading…