WIP private chat
This commit is contained in:
@ -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" />
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
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>
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
159
BookAStar/BookAStar/ViewModels/Messaging/ChatUserInfo.cs
Normal file
159
BookAStar/BookAStar/ViewModels/Messaging/ChatUserInfo.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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.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"/>
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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": {}
|
||||
}
|
Reference in New Issue
Block a user