WIP private chat

This commit is contained in:
2016-12-15 14:19:53 +01:00
parent ca1f577385
commit a841c0e391
13 changed files with 287 additions and 158 deletions

View File

@ -62,12 +62,12 @@
<Compile Include="Model\Settings\SignatureSettings.cs" />
<Compile Include="Model\Social\Chat\ChatStatus.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="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\ModelState.cs" />
<Compile Include="ViewModels\PageState.cs" />

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}
}

View File

@ -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");
}
}
}
}

View File

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

View File

@ -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);
}
}
}
}

View File

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

View File

@ -15,16 +15,18 @@
</ResourceDictionary>
</ContentView.Resources>
<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">
<DataTemplate>
<ViewCell>
<ViewCell.View>
<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 EMail}" />
<Label Text="{Binding RolesAsAString}" TextColor="{StaticResource QuietTextColor}"
FontSize="{StaticResource SmallFontSize}"/>
</StackLayout>
</ViewCell.View>
</ViewCell>

View File

@ -1,4 +1,5 @@
using BookAStar.Model;
using BookAStar.ViewModels.Messaging;
using System;
using System.Collections;
using System.Collections.Generic;
@ -6,7 +7,7 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
namespace BookAStar.Views
@ -14,24 +15,57 @@ namespace BookAStar.Views
public partial class UserListView : ContentView
{
public BindableProperty ItemsSourceProperty = BindableProperty.Create(
"ItemsSource", typeof(IEnumerable), typeof(UserListView));
"ItemsSource", typeof(ChatUserCollection), typeof(UserListView), default(ChatUserCollection),
BindingMode.OneWay);
public IEnumerable ItemsSource
{
get { return list.ItemsSource; }
set { list.ItemsSource = value; }
}
public BindableProperty ItemSelectedProperty = BindableProperty.Create(
"ItemSelected", typeof(ICommand), typeof(UserListView), default(ICommand));
/* public IEnumerable ItemsSource
public BindableProperty DisableSelectionProperty = BindableProperty.Create(
"DisableSelection", typeof(bool), typeof(UserListView), false);
public ChatUserCollection ItemsSource
{
get { return GetValue(ItemsSourceProperty) as IEnumerable; }
get { return (ChatUserCollection) GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
*/
public ICommand ItemSelected
{
get { return (ICommand) GetValue(ItemSelectedProperty); }
set { SetValue(ItemSelectedProperty, value); }
}
public bool DisableSelection
{
get { return (bool) GetValue(DisableSelectionProperty); }
set { SetValue(DisableSelectionProperty, value); }
}
public UserListView()
{
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;
}
}
}

View File

@ -3,20 +3,18 @@
"version": 2,
"targets": {
".NETFramework,Version=v4.5.1": {},
".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": {}
".NETPortable,Version=v4.5,Profile=Profile111": {}
},
"libraries": {},
"projectFileDependencyGroups": {
"": [],
".NETFramework,Version=v4.5.1": [],
".NETPortable,Version=v4.5,Profile=Profile111": [
"fx/System.Runtime >= 4.0.0",
"fx/System.Globalization >= 4.0.0",
"fx/System.Resources.ResourceManager >= 4.0.0"
"System.Globalization >= 4.0.0",
"System.Resources.ResourceManager >= 4.0.0",
"System.Runtime >= 4.0.0"
]
}
},
"tools": {},
"projectFileToolGroups": {}
}