diff --git a/Softeq.XToolkit.Chat.Droid/Listeners/LoadMoreScrollListener.cs b/Softeq.XToolkit.Chat.Droid/Listeners/LoadMoreScrollListener.cs
new file mode 100644
index 0000000..d0c86b1
--- /dev/null
+++ b/Softeq.XToolkit.Chat.Droid/Listeners/LoadMoreScrollListener.cs
@@ -0,0 +1,42 @@
+// Developed by Softeq Development Corporation
+// http://www.softeq.com
+
+using System;
+using Android.Support.V7.Widget;
+using Softeq.XToolkit.Common;
+
+namespace Softeq.XToolkit.Chat.Droid.Listeners
+{
+ public class LoadMoreScrollListener : RecyclerView.OnScrollListener
+ {
+ private const int VisibleThreshold = 5;
+
+ private readonly TaskReference _onScrolled;
+
+ private bool _isBusy;
+
+ public LoadMoreScrollListener(TaskReference onScrolled)
+ {
+ _onScrolled = onScrolled ?? throw new ArgumentNullException(nameof(onScrolled));
+ }
+
+ public override async void OnScrolled(RecyclerView recyclerView, int dx, int dy)
+ {
+ base.OnScrolled(recyclerView, dx, dy);
+
+ var linearLayoutManager = (LinearLayoutManager)recyclerView.GetLayoutManager();
+
+ var totalItemCount = linearLayoutManager.ItemCount;
+ var lastVisibleItem = linearLayoutManager.FindLastVisibleItemPosition();
+
+ if (!_isBusy && totalItemCount <= (lastVisibleItem + VisibleThreshold))
+ {
+ _isBusy = true;
+
+ await _onScrolled.RunAsync();
+
+ _isBusy = false;
+ }
+ }
+ }
+}
diff --git a/Softeq.XToolkit.Chat.Droid/Resources/layout/activity_chat_create.xml b/Softeq.XToolkit.Chat.Droid/Resources/layout/activity_chat_create.xml
index 77d70c4..bf4b801 100644
--- a/Softeq.XToolkit.Chat.Droid/Resources/layout/activity_chat_create.xml
+++ b/Softeq.XToolkit.Chat.Droid/Resources/layout/activity_chat_create.xml
@@ -34,6 +34,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_toRightOf="@+id/iv_chat_photo"
+ android:maxLines="1"
+ android:inputType="text"
android:hint="Group Name"
android:textSize="20sp" />
diff --git a/Softeq.XToolkit.Chat.Droid/Resources/layout/dialog_select_members.xml b/Softeq.XToolkit.Chat.Droid/Resources/layout/dialog_select_members.xml
index 677543b..e5e84c0 100644
--- a/Softeq.XToolkit.Chat.Droid/Resources/layout/dialog_select_members.xml
+++ b/Softeq.XToolkit.Chat.Droid/Resources/layout/dialog_select_members.xml
@@ -22,6 +22,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
+ android:maxLines="1"
+ android:inputType="text"
android:hint="Search" />
27.0.2.1
- 2.4.3.840
+ 2.4.4.859
@@ -94,6 +94,7 @@
+
diff --git a/Softeq.XToolkit.Chat.Droid/StyleHelper.cs b/Softeq.XToolkit.Chat.Droid/StyleHelper.cs
index 55e71e4..8ad9602 100644
--- a/Softeq.XToolkit.Chat.Droid/StyleHelper.cs
+++ b/Softeq.XToolkit.Chat.Droid/StyleHelper.cs
@@ -37,6 +37,8 @@ public interface IChatDroidStyle
int UnderlinedBg { get; }
int CheckedIcon { get; }
int UnCheckedIcon { get; }
+ int UnreadMessagesCountColor { get; }
+ int UnreadMutedMessagesCountColor { get; }
}
public abstract class ChatDroidStyleBase : IChatDroidStyle
@@ -62,5 +64,7 @@ public abstract class ChatDroidStyleBase : IChatDroidStyle
public abstract int UnderlinedBg { get; }
public abstract int CheckedIcon { get; }
public abstract int UnCheckedIcon { get; }
+ public abstract int UnreadMessagesCountColor { get; }
+ public abstract int UnreadMutedMessagesCountColor { get; }
}
}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat.Droid/ViewHolders/ChatViewHolder.cs b/Softeq.XToolkit.Chat.Droid/ViewHolders/ChatViewHolder.cs
index 9df0b6a..646d016 100644
--- a/Softeq.XToolkit.Chat.Droid/ViewHolders/ChatViewHolder.cs
+++ b/Softeq.XToolkit.Chat.Droid/ViewHolders/ChatViewHolder.cs
@@ -6,23 +6,23 @@
using Android.Graphics.Drawables;
using Android.Views;
using Android.Widget;
+using Android.Support.V4.Content;
using FFImageLoading.Cross;
using FFImageLoading.Transformations;
-using FFImageLoading.Work;
using Softeq.XToolkit.Bindings;
using Softeq.XToolkit.Chat.Models;
using Softeq.XToolkit.Chat.ViewModels;
using Softeq.XToolkit.Common;
using Softeq.XToolkit.Common.Command;
using Softeq.XToolkit.Common.Droid.Converters;
+using Softeq.XToolkit.WhiteLabel.Droid.Controls;
using Softeq.XToolkit.WhiteLabel.Droid.Extensions;
namespace Softeq.XToolkit.Chat.Droid.ViewHolders
{
public class ChatViewHolder : BindableViewHolder
{
- private const string UnreadMessagesCountColor = "#5bc6c9";
- private const string UnreadMutedMessagesCountColor = "#b4b4b4";
+ //TODO: move this to resources
private const string ChatStatusDefaultColor = "#dedede";
private readonly WeakAction _selectChatAction;
@@ -71,8 +71,12 @@ public override void BindViewModel(ChatSummaryViewModel viewModel)
ChatPhotoImageView.LoadImageWithTextPlaceholder(
_viewModelRef.Target.ChatPhotoUrl,
_viewModelRef.Target.ChatName,
- StyleHelper.Style.ChatAvatarStyles,
- (TaskParameter x) => x.Transform(new CircleTransformation()));
+ new AvatarPlaceholderDrawable.AvatarStyles
+ {
+ BackgroundHexColors = StyleHelper.Style.ChatAvatarStyles.BackgroundHexColors,
+ Size = new System.Drawing.Size(45, 45)
+ },
+ x => x.Transform(new CircleTransformation()));
}));
Bindings.Add(this.SetBinding(() => _viewModelRef.Target.UnreadMessageCount).WhenSourceChanges(() =>
@@ -88,8 +92,13 @@ public override void BindViewModel(ChatSummaryViewModel viewModel)
{
if (UnreadMessageCountTextView != null)
{
- var color = _viewModelRef.Target.IsMuted ? UnreadMutedMessagesCountColor : UnreadMessagesCountColor;
- UnreadMessageCountTextView.Background = CreateBackgroundWithCornerRadius(Color.ParseColor(color), 56f);
+ var colorResId = _viewModelRef.Target.IsMuted
+ ? StyleHelper.Style.UnreadMutedMessagesCountColor
+ : StyleHelper.Style.UnreadMessagesCountColor;
+
+ var color = ContextCompat.GetColor(UnreadMessageCountTextView.Context, colorResId);
+
+ UnreadMessageCountTextView.Background = CreateBackgroundWithCornerRadius(color, 56f);
}
}));
@@ -115,7 +124,7 @@ public override void BindViewModel(ChatSummaryViewModel viewModel)
}
// TODO: move to XToolkit.Common
- private static Drawable CreateBackgroundWithCornerRadius(Color color, float radius)
+ private static Drawable CreateBackgroundWithCornerRadius(int color, float radius)
{
var drawable = new GradientDrawable();
diff --git a/Softeq.XToolkit.Chat.Droid/ViewHolders/ConversationViewHolder.cs b/Softeq.XToolkit.Chat.Droid/ViewHolders/ConversationViewHolder.cs
index e1dfe2b..91b30ca 100644
--- a/Softeq.XToolkit.Chat.Droid/ViewHolders/ConversationViewHolder.cs
+++ b/Softeq.XToolkit.Chat.Droid/ViewHolders/ConversationViewHolder.cs
@@ -113,7 +113,10 @@ public override void BindViewModel(ChatMessageViewModel viewModel)
SenderPhotoImageView.LoadImageWithTextPlaceholder(
_viewModelRef.Target.SenderPhotoUrl,
_viewModelRef.Target.SenderName,
- StyleHelper.Style.ChatAvatarStyles,
+ new WhiteLabel.Droid.Controls.AvatarPlaceholderDrawable.AvatarStyles {
+ BackgroundHexColors = StyleHelper.Style.ChatAvatarStyles.BackgroundHexColors,
+ Size = new System.Drawing.Size(35, 35)
+ },
(TaskParameter x) => x.Transform(new CircleTransformation()));
}
diff --git a/Softeq.XToolkit.Chat.Droid/Views/AddContactsDialogFragment.cs b/Softeq.XToolkit.Chat.Droid/Views/AddContactsDialogFragment.cs
index 611693d..38d3c4c 100644
--- a/Softeq.XToolkit.Chat.Droid/Views/AddContactsDialogFragment.cs
+++ b/Softeq.XToolkit.Chat.Droid/Views/AddContactsDialogFragment.cs
@@ -12,6 +12,8 @@
using Softeq.XToolkit.Common.Command;
using Softeq.XToolkit.WhiteLabel.Droid.Controls;
using Softeq.XToolkit.WhiteLabel.Droid.Dialogs;
+using Softeq.XToolkit.Chat.Droid.Listeners;
+using Softeq.XToolkit.Common;
namespace Softeq.XToolkit.Chat.Droid.Views
{
@@ -37,11 +39,7 @@ public override void OnViewCreated(View view, Bundle savedInstanceState)
View.SetBackgroundResource(StyleHelper.Style.ContentColor);
- _navigationBarView = View.FindViewById(Resource.Id.dialog_select_members_nav_bar);
- _navigationBarView.SetLeftButton(StyleHelper.Style.NavigationBarBackButtonIcon, new RelayCommand(Close));
- _navigationBarView.SetRightButton(ViewModel.Resources.Done, ViewModel.DoneCommand);
- _navigationBarView.SetTitle(ViewModel.Title);
- _navigationBarView.SetBackground(StyleHelper.Style.ContentColor);
+ InitNavigationBarView(view);
var searchContainer = View.FindViewById(Resource.Id.dialog_select_members_serch_container);
searchContainer.SetBackgroundResource(StyleHelper.Style.UnderlinedBg);
@@ -49,7 +47,43 @@ public override void OnViewCreated(View view, Bundle savedInstanceState)
_editText = View.FindViewById(Resource.Id.dialog_select_members_serch_text);
_editText.Hint = ViewModel.Resources.Search;
- _addedMembers = View.FindViewById(Resource.Id.dialog_select_members_added_members);
+ InitSelectedRecyclerView(view);
+ InitFilteredRecyclerView(view);
+ }
+
+ protected override void DoAttachBindings()
+ {
+ base.DoAttachBindings();
+
+ Bindings.Add(this.SetBinding(() => ViewModel.ContactNameSearchQuery, () => _editText.Text, BindingMode.TwoWay));
+ Bindings.Add(this.SetBinding(() => ViewModel.HasSelectedContacts).WhenSourceChanges(() =>
+ {
+ _addedMembers.Visibility = ViewModel.HasSelectedContacts
+ ? ViewStates.Visible
+ : ViewStates.Gone;
+ }));
+ }
+
+ public override void OnDestroy()
+ {
+ base.OnDestroy();
+
+ _filteredAdapter.Dispose();
+ _selectedAdapter.Dispose();
+ }
+
+ private void InitNavigationBarView(View view)
+ {
+ _navigationBarView = view.FindViewById(Resource.Id.dialog_select_members_nav_bar);
+ _navigationBarView.SetLeftButton(StyleHelper.Style.NavigationBarBackButtonIcon, new RelayCommand(Close));
+ _navigationBarView.SetRightButton(ViewModel.Resources.Done, ViewModel.DoneCommand);
+ _navigationBarView.SetTitle(ViewModel.Title);
+ _navigationBarView.SetBackground(StyleHelper.Style.ContentColor);
+ }
+
+ private void InitSelectedRecyclerView(View view)
+ {
+ _addedMembers = view.FindViewById(Resource.Id.dialog_select_members_added_members);
_addedMembers.SetLayoutManager(new LinearLayoutManager(Context, LinearLayoutManager.Horizontal, false));
_selectedAdapter = new ObservableRecyclerViewAdapter(
ViewModel.SelectedContacts,
@@ -62,14 +96,17 @@ public override void OnViewCreated(View view, Bundle savedInstanceState)
{
var viewHolder = (SelectedContactViewHolder)holder;
viewHolder.Bind(item);
- });
+ });
_addedMembers.SetAdapter(_selectedAdapter);
+ }
- _filteredMembers = View.FindViewById(Resource.Id.dialog_select_members_filtered_members);
+ private void InitFilteredRecyclerView(View view)
+ {
+ _filteredMembers = view.FindViewById(Resource.Id.dialog_select_members_filtered_members);
_filteredMembers.SetLayoutManager(new LinearLayoutManager(Context));
_filteredMembers.AddItemDecoration(new DividerItemDecoration(Context, DividerItemDecoration.Vertical));
_filteredAdapter = new ObservableRecyclerViewAdapter(
- ViewModel.FoundContacts,
+ ViewModel.PaginationViewModel.Items,
(parent, i) =>
{
var v = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.view_holder_member_filter_item, parent, false);
@@ -81,32 +118,15 @@ public override void OnViewCreated(View view, Bundle savedInstanceState)
viewHolder.Bind(item);
});
_filteredMembers.SetAdapter(_filteredAdapter);
- }
-
- protected override void DoAttachBindings()
- {
- base.DoAttachBindings();
-
- this.SetBinding(() => ViewModel.ContactNameSearchQuery, () => _editText.Text, BindingMode.TwoWay);
- this.SetBinding(() => ViewModel.HasSelectedContacts).WhenSourceChanges(() =>
- {
- _addedMembers.Visibility = ViewModel.HasSelectedContacts
- ? ViewStates.Visible
- : ViewStates.Gone;
- });
- }
-
- public override void OnDestroy()
- {
- base.OnDestroy();
+ _filteredMembers.AddOnScrollListener(new LoadMoreScrollListener(new TaskReference(async () =>
+ {
+ await ViewModel.PaginationViewModel.LoadNextPageAsync();
+ })));
+ }
- _filteredAdapter.Dispose();
- _selectedAdapter.Dispose();
- }
-
private void Close()
{
ViewModel.DialogComponent.CloseCommand.Execute(false);
- }
+ }
}
}
diff --git a/Softeq.XToolkit.Chat.Droid/Views/ChatDetailsActivity.cs b/Softeq.XToolkit.Chat.Droid/Views/ChatDetailsActivity.cs
index 466d842..939c32b 100644
--- a/Softeq.XToolkit.Chat.Droid/Views/ChatDetailsActivity.cs
+++ b/Softeq.XToolkit.Chat.Droid/Views/ChatDetailsActivity.cs
@@ -97,7 +97,11 @@ protected override void DoAttachBindings()
_chatPhotoImageView.LoadImageWithTextPlaceholder(
ViewModel.Summary.AvatarUrl,
ViewModel.Summary.Name,
- StyleHelper.Style.ChatAvatarStyles,
+ new AvatarPlaceholderDrawable.AvatarStyles
+ {
+ BackgroundHexColors = StyleHelper.Style.ChatAvatarStyles.BackgroundHexColors,
+ Size = new System.Drawing.Size(64, 64)
+ },
x => x.Transform(new CircleTransformation()));
});
}));
diff --git a/Softeq.XToolkit.Chat.Droid/Views/ChatMessagesActivity.cs b/Softeq.XToolkit.Chat.Droid/Views/ChatMessagesActivity.cs
index 27928b2..65d33f1 100644
--- a/Softeq.XToolkit.Chat.Droid/Views/ChatMessagesActivity.cs
+++ b/Softeq.XToolkit.Chat.Droid/Views/ChatMessagesActivity.cs
@@ -46,7 +46,7 @@ public class ChatMessagesActivity : ActivityBase
private ImageButton _editingMessageCloseButton;
private ImageButton _scrollDownImageButton;
private ContextMenuComponent _contextMenuComponent;
- private bool _shouldSendStateMessageToChat;
+ //private bool _shouldSendStateMessageToChat;
private bool _isAdapterSourceInitialized;
private bool _isAutoScrollToFooterEnabled = true;
private ImagePicker _imagePicker;
@@ -113,10 +113,10 @@ protected override void OnCreate(Bundle savedInstanceState)
protected override void OnPause()
{
- if (_shouldSendStateMessageToChat)
- {
- Messenger.Default.Send(new ChatInBackgroundMessage());
- }
+ //if (_shouldSendStateMessageToChat)
+ //{
+ // Messenger.Default.Send(new ChatInBackgroundMessage());
+ //}
KeyboardService.HideSoftKeyboard(_messageEditText);
@@ -127,22 +127,23 @@ protected override void OnResume()
{
base.OnResume();
- if (_shouldSendStateMessageToChat)
- {
- Messenger.Default.Send(new ChatInForegroundMessage());
- }
- else
- {
- _shouldSendStateMessageToChat = true;
- }
+ // TODO YP: think about disconnecting when app in background
+ //if (_shouldSendStateMessageToChat)
+ //{
+ // Messenger.Default.Send(new ChatInForegroundMessage());
+ //}
+ //else
+ //{
+ // _shouldSendStateMessageToChat = true;
+ //}
}
- public override void OnBackPressed()
- {
- _shouldSendStateMessageToChat = false;
+ //public override void OnBackPressed()
+ //{
+ // _shouldSendStateMessageToChat = false;
- base.OnBackPressed();
- }
+ // base.OnBackPressed();
+ //}
protected override void OnDestroy()
{
@@ -301,6 +302,7 @@ private void CloseEditImageContainer()
{
_editImageContainer.Visibility = ViewStates.Gone;
_previewImageKey = null;
+ _imagePicker.ViewModel.ImageCacheKey = null;
_imagePreview.SetImageDrawable(null);
});
}
diff --git a/Softeq.XToolkit.Chat.Droid/Views/ChatsListFragment.cs b/Softeq.XToolkit.Chat.Droid/Views/ChatsListFragment.cs
index d52c110..4a6af9a 100644
--- a/Softeq.XToolkit.Chat.Droid/Views/ChatsListFragment.cs
+++ b/Softeq.XToolkit.Chat.Droid/Views/ChatsListFragment.cs
@@ -102,14 +102,14 @@ private BindableViewHolder CreateChatViewHolder((ViewGroup
private void ConfigureSwipeForViewHolder(RecyclerView.ViewHolder viewHolder, int position,
ICollection actions)
{
- actions.Add(new SimpleSwipeActionView(ViewModel.LeaveChatOptionText, _swipeLeaveActionViewOptions, pos =>
+ actions.Add(new SimpleSwipeActionView(ViewModel.LocalizedStrings.Leave, _swipeLeaveActionViewOptions, pos =>
{
ViewModel.LeaveChatCommand.Execute(ViewModel.Chats[pos]);
}));
if (ViewModel.Chats[position].IsCreatedByMe)
{
- actions.Add(new SimpleSwipeActionView(ViewModel.DeleteChatOptionText, _swipeCloseActionViewOptions, pos =>
+ actions.Add(new SimpleSwipeActionView(ViewModel.LocalizedStrings.Delete, _swipeCloseActionViewOptions, pos =>
{
ViewModel.DeleteChatCommand.Execute(ViewModel.Chats[pos]);
}));
diff --git a/Softeq.XToolkit.Chat.HttpClient/HttpChatAdapter.cs b/Softeq.XToolkit.Chat.HttpClient/HttpChatAdapter.cs
index d653b70..a3b0400 100644
--- a/Softeq.XToolkit.Chat.HttpClient/HttpChatAdapter.cs
+++ b/Softeq.XToolkit.Chat.HttpClient/HttpChatAdapter.cs
@@ -64,12 +64,11 @@ public Task CreateChatAsync(IEnumerable participantsId
return _httpClient.GetModelAsync(request, _logger, Mapper.DtoToChatSummary);
}
- public async Task> GetChatsHeadersAsync()
+ public async Task> GetChatsListAsync()
{
var request = new GetChatsListRequest(_chatConfig.ApiUrl);
- var result = await _httpClient.GetModelOrExceptionAsync, IList>(request, _logger,
- x => x.Select(Mapper.DtoToChatSummary).ToList())
- .ConfigureAwait(false);
+ var result = await _httpClient.GetModelOrExceptionAsync, IList>(
+ request, _logger, x => x.Select(Mapper.DtoToChatSummary).ToList()).ConfigureAwait(false);
return result.Model;
}
diff --git a/Softeq.XToolkit.Chat.HttpClient/MockHttpChatAdapter.cs b/Softeq.XToolkit.Chat.HttpClient/MockHttpChatAdapter.cs
index d484768..e127d3e 100644
--- a/Softeq.XToolkit.Chat.HttpClient/MockHttpChatAdapter.cs
+++ b/Softeq.XToolkit.Chat.HttpClient/MockHttpChatAdapter.cs
@@ -87,7 +87,7 @@ public async Task CreateChatAsync(IEnumerable particip
};
}
- public async Task> GetChatsHeadersAsync()
+ public async Task> GetChatsListAsync()
{
return new List
{
diff --git a/Softeq.XToolkit.Chat.Models/Interfaces/IChatService.cs b/Softeq.XToolkit.Chat.Models/Interfaces/IChatService.cs
index f655bf0..20af998 100644
--- a/Softeq.XToolkit.Chat.Models/Interfaces/IChatService.cs
+++ b/Softeq.XToolkit.Chat.Models/Interfaces/IChatService.cs
@@ -24,7 +24,7 @@ public interface IChatService
IObservable ConnectionStatusChanged { get; }
SocketConnectionStatus ConnectionStatus { get; }
- Task> GetChatsHeadersAsync();
+ Task> GetChatsListAsync();
Task CreateChatAsync(string chatName, IList participantsIds, string imagePath);
Task CloseChatAsync(string chatId);
Task LeaveChatAsync(string chatId);
diff --git a/Softeq.XToolkit.Chat.Models/Interfaces/IHttpChatAdapter.cs b/Softeq.XToolkit.Chat.Models/Interfaces/IHttpChatAdapter.cs
index ad22cc8..4b9138c 100644
--- a/Softeq.XToolkit.Chat.Models/Interfaces/IHttpChatAdapter.cs
+++ b/Softeq.XToolkit.Chat.Models/Interfaces/IHttpChatAdapter.cs
@@ -11,7 +11,7 @@ namespace Softeq.XToolkit.Chat.Models.Interfaces
public interface IHttpChatAdapter
{
Task GetUserSummaryAsync();
- Task> GetChatsHeadersAsync();
+ Task> GetChatsListAsync();
Task> GetOlderMessagesAsync(string chatId,
string messageFromId = null,
diff --git a/Softeq.XToolkit.Chat.SignalRClient/SignalRAdapter.cs b/Softeq.XToolkit.Chat.SignalRClient/SignalRAdapter.cs
index 90bd8fd..daa3a84 100644
--- a/Softeq.XToolkit.Chat.SignalRClient/SignalRAdapter.cs
+++ b/Softeq.XToolkit.Chat.SignalRClient/SignalRAdapter.cs
@@ -49,7 +49,6 @@ public SignalRAdapter(IAccountService accountService,
IRefreshTokenService refreshTokenService,
IRestHttpClient httpClient,
ILogManager logManager,
- IInternetConnectionManager internetConnectionManager,
IChatConfig chatConfig)
{
_accountService = accountService;
@@ -60,8 +59,6 @@ public SignalRAdapter(IAccountService accountService,
SubscribeToEvents();
- internetConnectionManager.NetworkConnectionChanged += OnNetworkConnectionChanged;
-
// TODO YP: need investigate auto-connect (when init before login)
//ConnectIfNotConnectedAsync().SafeTaskWrapper();
}
@@ -253,19 +250,6 @@ private void SubscribeToEvents()
_signalRClient.Disconnected += OnDisconnected;
}
- private void OnNetworkConnectionChanged(object sender, NetworkConnectionEventArgs e)
- {
- if (e.IsNetworkAvailable)
- {
- ConnectIfNotConnectedAsync(true).SafeTaskWrapper();
- }
- else
- {
- _isConnected = false;
- UpdateConnectionStatus(SocketConnectionStatus.WaitingForNetwork);
- }
- }
-
private async Task CheckConnectionAndSendRequest(TaskReference funcSendRequest)
{
try
diff --git a/Softeq.XToolkit.Chat.SignalRClient/SignalRClient.cs b/Softeq.XToolkit.Chat.SignalRClient/SignalRClient.cs
index 954fa34..0a22dac 100644
--- a/Softeq.XToolkit.Chat.SignalRClient/SignalRClient.cs
+++ b/Softeq.XToolkit.Chat.SignalRClient/SignalRClient.cs
@@ -2,6 +2,7 @@
// http://www.softeq.com
using System;
+using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;
@@ -10,12 +11,16 @@
using Softeq.XToolkit.Chat.SignalRClient.DTOs.Client;
using Softeq.XToolkit.Chat.SignalRClient.DTOs.Member;
using Softeq.XToolkit.Chat.SignalRClient.DTOs.Message;
+using Softeq.XToolkit.Common.Extensions;
namespace Softeq.XToolkit.Chat.SignalRClient
{
internal class SignalRClient
{
+ private readonly List _subscriptions = new List();
+
private HubConnection _connection;
+ private IDisposable _accessTokenExpiredSubscription;
public SignalRClient(string url)
{
@@ -97,12 +102,16 @@ public async Task ConnectAsync(string accessToken)
}
}
- _connection.On(ClientEvents.AccessTokenExpired, (requestId) =>
+ _accessTokenExpiredSubscription?.Dispose();
+ _accessTokenExpiredSubscription = _connection.On(ClientEvents.AccessTokenExpired, (requestId) =>
{
AccessTokenExpired?.Invoke();
});
+
var client = await _connection.InvokeAsync(ServerMethods.AddClientAsync).ConfigureAwait(false);
+
SubscribeToEvents();
+
return client;
}
@@ -241,65 +250,68 @@ public async Task Disconnect()
private void SubscribeToEvents()
{
- _connection.On(ClientEvents.MessageAdded, (message) =>
+ _subscriptions.Apply(x => x.Dispose());
+ _subscriptions.Clear();
+
+ _subscriptions.Add(_connection.On(ClientEvents.MessageAdded, (message) =>
{
MessageAdded?.Invoke(message);
- });
+ }));
- _connection.On(ClientEvents.MessageDeleted, (deletedMessageId, updatedChannelSummary) =>
+ _subscriptions.Add(_connection.On(ClientEvents.MessageDeleted, (deletedMessageId, updatedChannelSummary) =>
{
MessageDeleted?.Invoke(deletedMessageId.ToString(), updatedChannelSummary);
- });
+ }));
- _connection.On(ClientEvents.MessageUpdated, (message) =>
+ _subscriptions.Add(_connection.On(ClientEvents.MessageUpdated, (message) =>
{
MessageUpdated?.Invoke(message);
- });
+ }));
- _connection.On(ClientEvents.MemberLeft, (user, channelId) =>
+ _subscriptions.Add(_connection.On(ClientEvents.MemberLeft, (user, channelId) =>
{
MemberLeft?.Invoke(user, channelId);
- });
+ }));
- _connection.On(ClientEvents.MemberJoined, (user, channel) =>
+ _subscriptions.Add(_connection.On(ClientEvents.MemberJoined, (user, channel) =>
{
MemberJoined?.Invoke(user, channel);
- });
+ }));
- _connection.On(ClientEvents.ChannelUpdated, (channel) =>
+ _subscriptions.Add(_connection.On(ClientEvents.ChannelUpdated, (channel) =>
{
ChannelUpdated?.Invoke(channel);
- });
+ }));
- _connection.On(ClientEvents.ChannelClosed, (channel) =>
+ _subscriptions.Add(_connection.On(ClientEvents.ChannelClosed, (channel) =>
{
ChannelClosed?.Invoke(channel);
- });
+ }));
_connection.On(ClientEvents.ChannelAdded, (channel) =>
{
ChannelAdded?.Invoke(channel);
});
- _connection.On(ClientEvents.AttachmentAdded, (username, message) =>
+ _subscriptions.Add(_connection.On(ClientEvents.AttachmentAdded, (username, message) =>
{
AttachmentAdded?.Invoke(username, message);
- });
+ }));
- _connection.On(ClientEvents.AttachmentDeleted, (username, message) =>
+ _subscriptions.Add(_connection.On(ClientEvents.AttachmentDeleted, (username, message) =>
{
AttachmentDeleted?.Invoke(username, message);
- });
+ }));
- _connection.On(ClientEvents.TypingStarted, (username) =>
+ _subscriptions.Add(_connection.On(ClientEvents.TypingStarted, (username) =>
{
TypingStarted?.Invoke(username);
- });
+ }));
- _connection.On(ClientEvents.TypingEnded, (username) =>
+ _subscriptions.Add(_connection.On(ClientEvents.TypingEnded, (username) =>
{
TypingEnded?.Invoke(username);
- });
+ }));
}
}
}
diff --git a/Softeq.XToolkit.Chat.iOS/StyleHelper.cs b/Softeq.XToolkit.Chat.iOS/StyleHelper.cs
index 0c9fd01..c7aea8c 100644
--- a/Softeq.XToolkit.Chat.iOS/StyleHelper.cs
+++ b/Softeq.XToolkit.Chat.iOS/StyleHelper.cs
@@ -17,7 +17,7 @@ internal static class StyleHelper
public interface IChatIosStyle
{
- UIColor NavigationBarTintColor { get; }
+ UIColor AccentColor { get; }
UIColor ButtonTintColor { get; }
AvatarImageHelpers.AvatarStyles AvatarStyles { get; }
diff --git a/Softeq.XToolkit.Chat.iOS/ViewControllers/AddContactsViewController.cs b/Softeq.XToolkit.Chat.iOS/ViewControllers/AddContactsViewController.cs
index 7636a13..d856699 100644
--- a/Softeq.XToolkit.Chat.iOS/ViewControllers/AddContactsViewController.cs
+++ b/Softeq.XToolkit.Chat.iOS/ViewControllers/AddContactsViewController.cs
@@ -6,6 +6,7 @@
using Softeq.XToolkit.Bindings.iOS;
using Softeq.XToolkit.Chat.iOS.Views;
using Softeq.XToolkit.Chat.ViewModels;
+using Softeq.XToolkit.Common;
using Softeq.XToolkit.WhiteLabel.iOS;
using Softeq.XToolkit.WhiteLabel.iOS.Extensions;
using UIKit;
@@ -66,7 +67,7 @@ private void InitNavigationBar()
CustomNavigationBarItem.SetCommand(
ViewModel.Resources.Done,
- StyleHelper.Style.NavigationBarTintColor,
+ StyleHelper.Style.AccentColor,
ViewModel.DoneCommand,
false);
}
@@ -85,10 +86,11 @@ private void InitSearchMembersTableView()
TableView.RowHeight = DefaultFoundMembersCellHeight;
TableView.RegisterNibForCellReuse(ChatUserViewCell.Nib, ChatUserViewCell.Key);
TableView.TableFooterView = new UIView();
+ TableView.KeyboardDismissMode = UIScrollViewKeyboardDismissMode.Interactive;
var source = new ObservableTableViewSource
{
- DataSource = ViewModel.FoundContacts,
+ DataSource = ViewModel.PaginationViewModel.Items,
BindCellDelegate = (cell, viewModel, index) =>
{
if (cell is ChatUserViewCell memberCell)
@@ -100,6 +102,11 @@ private void InitSearchMembersTableView()
};
TableView.Source = source;
+
+ TableView.Delegate = new ContactsTableViewDelegate(new TaskReference(async () =>
+ {
+ await ViewModel.PaginationViewModel.LoadNextPageAsync();
+ }));
}
private void InitSelectedMembersCollectionView()
@@ -127,5 +134,33 @@ private void ResetSelectedRow()
TableView.DeselectRow(indexPath, false);
}
}
+
+ private class ContactsTableViewDelegate : UITableViewDelegate
+ {
+ private readonly TaskReference _onScrolled;
+
+ private bool _isBusy;
+
+ public ContactsTableViewDelegate(TaskReference onScrolled)
+ {
+ _onScrolled = onScrolled ?? throw new ArgumentNullException(nameof(onScrolled));
+ }
+
+ public override async void Scrolled(UIScrollView scrollView)
+ {
+ var currentOffset = scrollView.ContentOffset.Y;
+ var maximumOffset = scrollView.ContentSize.Height - scrollView.Frame.Size.Height;
+ var deltaOffset = maximumOffset - currentOffset;
+
+ if (deltaOffset < 0 && !_isBusy)
+ {
+ _isBusy = true;
+
+ await _onScrolled.RunAsync();
+
+ _isBusy = false;
+ }
+ }
+ }
}
}
diff --git a/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatMessagesViewController.InputAndKeyboard.cs b/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatMessagesViewController.InputAndKeyboard.cs
index 3c82b34..d277325 100644
--- a/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatMessagesViewController.InputAndKeyboard.cs
+++ b/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatMessagesViewController.InputAndKeyboard.cs
@@ -81,7 +81,6 @@ private void RegisterKeyboardObservers()
{
return;
}
- InputBar.SetInputPlaceholderHidden(true);
});
_textViewEditingEndedObserver = UITextView.Notifications.ObserveTextDidEndEditing((sender, e) =>
@@ -90,7 +89,6 @@ private void RegisterKeyboardObservers()
{
return;
}
- InputBar.SetInputPlaceholderHidden(!string.IsNullOrEmpty(ViewModel.MessageToSendBody));
});
_textViewContentSizeObserver = InputBar.Input.AddObserver(ContentSizeKey, NSKeyValueObservingOptions.OldNew, e =>
diff --git a/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatMessagesViewController.cs b/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatMessagesViewController.cs
index 79923f1..e67ff54 100644
--- a/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatMessagesViewController.cs
+++ b/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatMessagesViewController.cs
@@ -74,8 +74,9 @@ public override void ViewDidLoad()
InputBar.ViewDidLoad(this);
InputBar.SetCommandWithArgs(nameof(InputBar.SendRaised), ViewModel.SendCommand);
-
+ InputBar.SetCommand(nameof(InputBar.PickerWillOpen), new RelayCommand(UnregisterKeyboardObservers));
InputBar.EditingClose.SetCommand(ViewModel.CancelEditingMessageModeCommand);
+ InputBar.EditingClose.SetImage(UIImage.FromBundle(StyleHelper.Style.CloseButtonImageBoundleName), UIControlState.Normal);
ScrollToBottomButton.SetCommand(new RelayCommand(() => ScrollToBottom(true)));
ScrollToBottomButton.SetBackgroundImage(UIImage.FromBundle(StyleHelper.Style.ScrollDownBoundleName), UIControlState.Normal);
@@ -83,10 +84,11 @@ public override void ViewDidLoad()
public override void ViewWillAppear(bool animated)
{
+ RegisterKeyboardObservers();
+
base.ViewWillAppear(animated);
- ViewModel.MessageAddedCommand = new RelayCommand(OnMessageAdded);
- RegisterKeyboardObservers();
+ ViewModel.MessageAddedCommand = new RelayCommand(OnMessageAdded);
}
public override void ViewDidAppear(bool animated)
@@ -142,10 +144,14 @@ protected override void DoAttachBindings()
InputBar.ChangeEditingMode(ViewModel.IsInEditMessageMode);
}));
Bindings.Add(this.SetBinding(() => ViewModel.Messages, () => _dataSourceRef.Target.DataSource));
- Bindings.Add(this.SetBinding(() => ViewModel.ConnectionStatusViewModel).WhenSourceChanges(() =>
+ Bindings.Add(this.SetBinding(() => ViewModel.ConnectionStatusViewModel.ConnectionStatusText).WhenSourceChanges(() =>
{
_customTitleView.Update(ViewModel.ConnectionStatusViewModel);
}));
+ Bindings.Add(this.SetBinding(() => ViewModel.MessageToSendBody).WhenSourceChanges(() =>
+ {
+ InputBar.SetTextPlaceholdervisibility(string.IsNullOrEmpty(ViewModel.MessageToSendBody));
+ }));
}
public override void ObserveValue(NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context)
diff --git a/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatsListViewController.cs b/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatsListViewController.cs
index 8ebacfe..737dca2 100644
--- a/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatsListViewController.cs
+++ b/Softeq.XToolkit.Chat.iOS/ViewControllers/ChatsListViewController.cs
@@ -28,12 +28,9 @@ public override void ViewDidLoad()
{
base.ViewDidLoad();
- // Setup brand color for NavigationBar buttons
- CustomNavigationBar.TintColor = StyleHelper.Style.NavigationBarTintColor;
-
+
_customTitleView = new ConnectionStatusView(CGRect.Empty);
-
- // Setup NavigationBar
+ CustomNavigationBar.TintColor = StyleHelper.Style.AccentColor;
CustomNavigationItem.AddTitleView(_customTitleView);
CustomNavigationItem.SetCommand(UIBarButtonSystemItem.Add, ViewModel.CreateChatCommand, false);
@@ -56,7 +53,7 @@ protected override void DoAttachBindings()
Bindings.Add(this.SetBinding(() => ViewModel.SelectedChat, () => _sourceRef.Target.SelectedItem, BindingMode.TwoWay));
- Bindings.Add(this.SetBinding(() => ViewModel.ConnectionStatusViewModel).WhenSourceChanges(() =>
+ Bindings.Add(this.SetBinding(() => ViewModel.ConnectionStatusViewModel.ConnectionStatusText).WhenSourceChanges(() =>
{
_customTitleView.Update(ViewModel.ConnectionStatusViewModel);
}));
@@ -96,7 +93,7 @@ public override UITableViewRowAction[] EditActionsForRow(UITableView tableView,
{
UITableViewRowAction.Create(
UITableViewRowActionStyle.Default,
- _viewModelRef.Target?.LeaveChatOptionText,
+ _viewModelRef.Target?.LocalizedStrings.Leave,
(row, index) => OnClickLeave(row, index, tableView))
};
@@ -104,7 +101,7 @@ public override UITableViewRowAction[] EditActionsForRow(UITableView tableView,
{
var closeButton = UITableViewRowAction.Create(
UITableViewRowActionStyle.Default,
- _viewModelRef.Target?.DeleteChatOptionText,
+ _viewModelRef.Target?.LocalizedStrings.Delete,
(row, index) => OnClickDelete(row, index, tableView));
closeButton.BackgroundColor = UIColor.Orange;
buttons.Add(closeButton);
diff --git a/Softeq.XToolkit.Chat.iOS/ViewControllers/SelectContactsViewController.cs b/Softeq.XToolkit.Chat.iOS/ViewControllers/SelectContactsViewController.cs
index b249310..19852a6 100644
--- a/Softeq.XToolkit.Chat.iOS/ViewControllers/SelectContactsViewController.cs
+++ b/Softeq.XToolkit.Chat.iOS/ViewControllers/SelectContactsViewController.cs
@@ -35,7 +35,7 @@ public override void ViewDidLoad()
true);
CustomNavigationItem.SetCommand(
ViewModel.ActionButtonName,
- StyleHelper.Style.NavigationBarTintColor,
+ StyleHelper.Style.AccentColor,
new RelayCommand(AddChat),
false);
diff --git a/Softeq.XToolkit.Chat.iOS/Views/ChatDetailsHeaderView.cs b/Softeq.XToolkit.Chat.iOS/Views/ChatDetailsHeaderView.cs
index c171488..c2189e2 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/ChatDetailsHeaderView.cs
+++ b/Softeq.XToolkit.Chat.iOS/Views/ChatDetailsHeaderView.cs
@@ -89,6 +89,9 @@ protected override void Initialize()
ChatAvatarcontainer.ClipsToBounds = true;
EditedChatAvatarImageView.Hidden = true;
+
+ ChangeChatPhotoButton.SetTitleColor(StyleHelper.Style.AccentColor, UIControlState.Normal);
+ AddMembersButton.SetTitleColor(StyleHelper.Style.AccentColor, UIControlState.Normal);
}
}
}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat.iOS/Views/ChatMessageNode.cs b/Softeq.XToolkit.Chat.iOS/Views/ChatMessageNode.cs
index da8761c..04c5d63 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/ChatMessageNode.cs
+++ b/Softeq.XToolkit.Chat.iOS/Views/ChatMessageNode.cs
@@ -66,14 +66,19 @@ public ChatMessageNode(ChatMessageViewModel viewModel, ContextMenuComponent cont
var size = new CGSize(AvatarSize, AvatarSize);
return image.MakeCircularImageWithSize(size);
};
- _avatarImageNode.ContentMode = UIViewContentMode.ScaleAspectFit;
+ _avatarImageNode.ContentMode = UIViewContentMode.ScaleAspectFill;
_avatarImageNode.Hidden = _isMyMessage;
if (!_isMyMessage)
{
_avatarImageNode.LoadImageWithTextPlaceholder(
_viewModelRef.Target.SenderPhotoUrl,
_viewModelRef.Target.SenderName,
- StyleHelper.Style.AvatarStyles);
+ new AvatarImageHelpers.AvatarStyles
+ {
+ BackgroundHexColors = StyleHelper.Style.AvatarStyles.BackgroundHexColors,
+ Font = StyleHelper.Style.AvatarStyles.Font,
+ Size = new System.Drawing.Size((int)AvatarSize, (int)AvatarSize)
+ });
}
_attachmentImageNode.ContentMode = UIViewContentMode.ScaleAspectFit;
diff --git a/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.cs b/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.cs
index 9908eb0..a14761e 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.cs
+++ b/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.cs
@@ -30,6 +30,7 @@ public ChatMessagesInputBarView(CGRect frame) : base(frame) { }
public event EventHandler TopContainersHeightChanged;
public event EventHandler, string)>>> SendRaised;
+ public event EventHandler PickerWillOpen;
public override CGSize IntrinsicContentSize => _cachedIntrinsicContentSize;
@@ -62,11 +63,6 @@ public void UpdateInputHeight(CGSize newSize)
InvalidateIntrinsicContentSize();
}
- public void SetInputPlaceholderHidden(bool isHidden)
- {
- InputTextViewPlaceholder.Hidden = isHidden;
- }
-
public void StartEditing(string originalMessageBody)
{
EditingText.Text = originalMessageBody;
@@ -78,7 +74,6 @@ public void ChangeEditingMode(bool isInEditMessageMode)
var isEditViewContainerHidden = !isInEditMessageMode;
CollapseEditViewContainer(isEditViewContainerHidden);
- SetInputPlaceholderHidden(isInEditMessageMode);
InvokeTopContainersHeightChangedIfNeeded();
InvalidateIntrinsicContentSize();
@@ -95,13 +90,13 @@ public override void InvalidateIntrinsicContentSize()
_cachedIntrinsicContentSize = CalculateIntrinsicContentSize();
}
-
+
public void ViewDidLoad(UIViewController viewController)
{
SendButton.TintColor = StyleHelper.Style.ButtonTintColor;
SendButton.SetImage(UIImage.FromBundle(StyleHelper.Style.SendBundleName), UIControlState.Normal);
SendButton.SetCommand(new RelayCommand(OnRaiseSend));
-
+
AttachImageButton.TintColor = StyleHelper.Style.ButtonTintColor;
AttachImageButton.SetImage(UIImage.FromBundle(StyleHelper.Style.AddImageBundleName), UIControlState.Normal);
AttachImageButton.SetCommand(new RelayCommand(OnAddPhotoClicked));
@@ -122,7 +117,7 @@ public void ViewDidLoad(UIViewController viewController)
EditImageContainerHeightConstraint.Constant = 0;
_simpleImagePicker = new SimpleImagePicker(viewController, Dependencies.IocContainer.Resolve(), false);
- _attachedImageBinding = this.SetBinding(() => _simpleImagePicker.ViewModel.ImageCacheKey).WhenSourceChanges(() =>
+ _attachedImageBinding = this.SetBinding(() => _simpleImagePicker.ViewModel.ImageCacheKey).WhenSourceChanges(() =>
{
if (string.IsNullOrEmpty(_simpleImagePicker.ViewModel.ImageCacheKey))
{
@@ -132,6 +127,12 @@ public void ViewDidLoad(UIViewController viewController)
OpenAttachPanel();
});
+ _simpleImagePicker.SetCommand(nameof(_simpleImagePicker.PickerWillOpen), new RelayCommand(RaisePickerWillOpen));
+ }
+
+ public void SetTextPlaceholdervisibility(bool isVisible)
+ {
+ InputTextViewPlaceholder.Hidden = !isVisible;
}
protected override void Initialize()
@@ -140,6 +141,9 @@ protected override void Initialize()
AutoresizingMask = UIViewAutoresizing.FlexibleHeight;
EditingIndicatorView.Layer.CornerRadius = 2f;
+ EditingIndicatorView.BackgroundColor = StyleHelper.Style.AccentColor;
+
+ EditMessageHeaderLabel.TextColor = StyleHelper.Style.AccentColor;
_editViewContainerInitialHeight = EditViewContainerHeightConstraint.Constant;
UpdateEditViewHeightConstraint();
@@ -173,7 +177,7 @@ private void UpdateEditViewHeightConstraint()
private void InvokeTopContainersHeightChangedIfNeeded()
{
- var changedHeight = EditViewContainerHeightConstraint.Constant
+ var changedHeight = EditViewContainerHeightConstraint.Constant
+ EditImageContainerHeightConstraint.Constant;
if (changedHeight == _cachedHeight)
@@ -212,7 +216,7 @@ private void OnRemovePhotoClicked()
private void OpenAttachPanel()
{
- Execute.BeginOnUIThread(() =>
+ Execute.BeginOnUIThread(() =>
{
var key = _simpleImagePicker.ViewModel.ImageCacheKey;
if (key == _previewImageKey)
@@ -237,9 +241,10 @@ private void OpenAttachPanel()
private void CloseAttachPanel()
{
- Execute.BeginOnUIThread(() =>
+ Execute.BeginOnUIThread(() =>
{
_previewImageKey = null;
+ _simpleImagePicker.ViewModel.ImageCacheKey = null;
AttachedImageView.Image?.Dispose();
AttachedImageView.Image = null;
EditImageContainer.Hidden = true;
@@ -255,5 +260,10 @@ private void OnRaiseSend()
SendRaised?.Invoke(this, new GenericEventArgs, string)>>(parameter));
CloseAttachPanel();
}
+
+ private void RaisePickerWillOpen()
+ {
+ PickerWillOpen?.Invoke(this, EventArgs.Empty);
+ }
}
}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.designer.cs b/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.designer.cs
index 284752b..7712766 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.designer.cs
+++ b/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.designer.cs
@@ -33,6 +33,9 @@ partial class ChatMessagesInputBarView
[Outlet]
UIKit.UILabel EditingText { get; set; }
+ [Outlet]
+ UIKit.UILabel EditMessageHeaderLabel { get; set; }
+
[Outlet]
UIKit.UIView EditViewContainer { get; set; }
@@ -141,6 +144,11 @@ void ReleaseDesignerOutlets ()
TakePhotoButton.Dispose ();
TakePhotoButton = null;
}
+
+ if (EditMessageHeaderLabel != null) {
+ EditMessageHeaderLabel.Dispose ();
+ EditMessageHeaderLabel = null;
+ }
}
}
}
diff --git a/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.xib b/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.xib
index d372e8b..c2a2178 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.xib
+++ b/Softeq.XToolkit.Chat.iOS/Views/ChatMessagesInputBarView.xib
@@ -16,6 +16,7 @@
+
@@ -87,7 +88,6 @@
-
@@ -208,7 +208,4 @@
-
-
-
diff --git a/Softeq.XToolkit.Chat.iOS/Views/ChatSummaryViewCell.cs b/Softeq.XToolkit.Chat.iOS/Views/ChatSummaryViewCell.cs
index 8d018cb..69581cd 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/ChatSummaryViewCell.cs
+++ b/Softeq.XToolkit.Chat.iOS/Views/ChatSummaryViewCell.cs
@@ -73,7 +73,7 @@ public void BindViewModel(ChatSummaryViewModel viewModel)
{
UnreadMessageCountBackground.BackgroundColor = _viewModelRef.Target.IsMuted
? UIColor.FromRGB(180, 180, 180)
- : UIColor.FromRGB(91, 198, 201);
+ : StyleHelper.Style.AccentColor;
}
}));
_bindings.Add(this.SetBinding(() => _viewModelRef.Target.UnreadMessageCount).WhenSourceChanges(() =>
diff --git a/Softeq.XToolkit.Chat.iOS/Views/ChatUserViewCell.cs b/Softeq.XToolkit.Chat.iOS/Views/ChatUserViewCell.cs
index d0428cc..6bc3f07 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/ChatUserViewCell.cs
+++ b/Softeq.XToolkit.Chat.iOS/Views/ChatUserViewCell.cs
@@ -22,6 +22,7 @@ public partial class ChatUserViewCell : UITableViewCell
private readonly List _bindings = new List();
private WeakReferenceEx _viewModelRef;
+ private UITapGestureRecognizer _tapGesture;
static ChatUserViewCell()
{
@@ -51,6 +52,27 @@ public void BindViewModel(ChatUserViewModel viewModel)
_bindings.Add(this.SetBinding(() => _viewModelRef.Target.IsSelected, () => CheckBoxButton.Selected, BindingMode.TwoWay));
_bindings.Add(this.SetBinding(() => _viewModelRef.Target.IsSelectable, () => CheckBoxButton.Hidden)
.ConvertSourceToTarget(x => !x));
+
+ _tapGesture = new UITapGestureRecognizer(() =>
+ {
+ _viewModelRef.Target.IsSelected = !_viewModelRef.Target.IsSelected;
+ })
+ {
+ NumberOfTapsRequired = 1
+ };
+
+ UserInteractionEnabled = true;
+ AddGestureRecognizer(_tapGesture);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ RemoveGestureRecognizer(_tapGesture);
+ }
+
+ base.Dispose(disposing);
}
}
}
diff --git a/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.cs b/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.cs
index 4cdf6dc..afd7c23 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.cs
+++ b/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.cs
@@ -17,6 +17,7 @@ public partial class SelectedMemberViewCell : UICollectionViewCell
public static readonly UINib Nib;
private ChatUserViewModel _memberViewModel;
+ private UITapGestureRecognizer _imageTapGesture;
protected SelectedMemberViewCell(IntPtr handle) : base(handle) { }
@@ -30,10 +31,7 @@ public void BindCell(ChatUserViewModel memberViewModel)
_memberViewModel = memberViewModel;
RemoveMemberBtn.SetBackgroundImage(UIImage.FromBundle(StyleHelper.Style.RemoveAttachBundleName), UIControlState.Normal);
- RemoveMemberBtn.SetCommand(new RelayCommand(() =>
- {
- _memberViewModel.IsSelected = false;
- }));
+ RemoveMemberBtn.SetCommand(new RelayCommand(RemoveSelection));
MemberNameLabel.Text = _memberViewModel.Username;
@@ -42,6 +40,29 @@ public void BindCell(ChatUserViewModel memberViewModel)
_memberViewModel.Username,
StyleHelper.Style.AvatarStyles,
x => x.Transform(new CircleTransformation()));
+
+ _imageTapGesture = new UITapGestureRecognizer(RemoveSelection)
+ {
+ NumberOfTapsRequired = 1
+ };
+
+ MemberPhotoImageView.UserInteractionEnabled = true;
+ MemberPhotoImageView.AddGestureRecognizer(_imageTapGesture);
+ }
+
+ private void RemoveSelection()
+ {
+ _memberViewModel.IsSelected = false;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ MemberPhotoImageView.RemoveGestureRecognizer(_imageTapGesture);
+ }
+
+ base.Dispose(disposing);
}
}
}
diff --git a/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.designer.cs b/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.designer.cs
index 2144e63..40413d2 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.designer.cs
+++ b/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.designer.cs
@@ -9,34 +9,37 @@
namespace Softeq.XToolkit.Chat.iOS.Views
{
- [Register ("SelectedMemberViewCell")]
- partial class SelectedMemberViewCell
- {
- [Outlet]
- UIKit.UILabel MemberNameLabel { get; set; }
+ [Register("SelectedMemberViewCell")]
+ partial class SelectedMemberViewCell
+ {
+ [Outlet]
+ UIKit.UILabel MemberNameLabel { get; set; }
- [Outlet]
- UIKit.UIImageView MemberPhotoImageView { get; set; }
+ [Outlet]
+ UIKit.UIImageView MemberPhotoImageView { get; set; }
- [Outlet]
- UIKit.UIButton RemoveMemberBtn { get; set; }
-
- void ReleaseDesignerOutlets ()
- {
- if (MemberPhotoImageView != null) {
- MemberPhotoImageView.Dispose ();
- MemberPhotoImageView = null;
- }
+ [Outlet]
+ UIKit.UIButton RemoveMemberBtn { get; set; }
- if (RemoveMemberBtn != null) {
- RemoveMemberBtn.Dispose ();
- RemoveMemberBtn = null;
- }
+ void ReleaseDesignerOutlets()
+ {
+ if (MemberNameLabel != null)
+ {
+ MemberNameLabel.Dispose();
+ MemberNameLabel = null;
+ }
- if (MemberNameLabel != null) {
- MemberNameLabel.Dispose ();
- MemberNameLabel = null;
- }
- }
- }
+ if (MemberPhotoImageView != null)
+ {
+ MemberPhotoImageView.Dispose();
+ MemberPhotoImageView = null;
+ }
+
+ if (RemoveMemberBtn != null)
+ {
+ RemoveMemberBtn.Dispose();
+ RemoveMemberBtn = null;
+ }
+ }
+ }
}
diff --git a/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.xib b/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.xib
index 6849dc8..34964b0 100644
--- a/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.xib
+++ b/Softeq.XToolkit.Chat.iOS/Views/SelectedMemberViewCell.xib
@@ -21,8 +21,9 @@
-
+
+
diff --git a/Softeq.XToolkit.Chat/Bootstrapper.cs b/Softeq.XToolkit.Chat/Bootstrapper.cs
index 0a2ac7e..5f81a02 100644
--- a/Softeq.XToolkit.Chat/Bootstrapper.cs
+++ b/Softeq.XToolkit.Chat/Bootstrapper.cs
@@ -3,6 +3,7 @@
using Autofac;
using Softeq.XToolkit.Chat.HttpClient;
+using Softeq.XToolkit.Chat.Interfaces;
using Softeq.XToolkit.Chat.Manager;
using Softeq.XToolkit.Chat.Models.Interfaces;
using Softeq.XToolkit.Chat.SignalRClient;
@@ -21,7 +22,11 @@ public static void Configure(ContainerBuilder containerBuilder)
.InstancePerLifetimeScope();
containerBuilder.RegisterType().As()
.InstancePerLifetimeScope();
- containerBuilder.RegisterType().InstancePerLifetimeScope();
+ containerBuilder.RegisterType()
+ .As()
+ .As()
+ .As()
+ .InstancePerLifetimeScope();
containerBuilder.RegisterType().As().InstancePerLifetimeScope();
containerBuilder.RegisterType().As().InstancePerLifetimeScope();
containerBuilder.RegisterType().As().InstancePerLifetimeScope();
diff --git a/Softeq.XToolkit.Chat/ChatService.cs b/Softeq.XToolkit.Chat/ChatService.cs
index c70195c..a3a1ed6 100644
--- a/Softeq.XToolkit.Chat/ChatService.cs
+++ b/Softeq.XToolkit.Chat/ChatService.cs
@@ -76,22 +76,24 @@ public Task InviteMembersAsync(string chatId, IList participantsIds)
return _socketChatAdapter.InviteMembersAsync(chatId, participantsIds);
}
- public virtual async Task> GetChatsHeadersAsync()
+ public virtual async Task> GetChatsListAsync()
{
- var chats = await _httpChatAdapter.GetChatsHeadersAsync().ConfigureAwait(false);
- if (chats != null)
+ var models = await _httpChatAdapter.GetChatsListAsync().ConfigureAwait(false);
+ if (models == null)
{
- var userId = await GetUserIdAsync().ConfigureAwait(false);
- chats.Apply(x => x.UpdateIsCreatedByMeStatus(userId));
- return chats.ToList();
+ return null;
}
- return null;
+
+ var userId = await GetUserIdAsync().ConfigureAwait(false);
+ models.Apply(x => x.UpdateIsCreatedByMeStatus(userId));
+
+ return models.ToList();
}
public virtual async Task> GetOlderMessagesAsync(string chatId,
- string messageFromId = null,
- DateTimeOffset? messageFromDateTime = null,
- int? count = null)
+ string messageFromId = null,
+ DateTimeOffset? messageFromDateTime = null,
+ int? count = null)
{
var messages = await _httpChatAdapter.GetOlderMessagesAsync(chatId, messageFromId, messageFromDateTime, count)
.ConfigureAwait(false);
@@ -188,11 +190,12 @@ private async Task GetUserIdAsync()
await _semaphoreSlim.WaitAsync().ConfigureAwait(false);
if (string.IsNullOrEmpty(_cachedUserId))
{
- var userSummary = default(ChatUserModel);
+ ChatUserModel userSummary;
do
{
userSummary = await _httpChatAdapter.GetUserSummaryAsync().ConfigureAwait(false);
- } while (string.IsNullOrEmpty(userSummary?.SaasUserId));
+ }
+ while (string.IsNullOrEmpty(userSummary?.SaasUserId));
_cachedUserId = userSummary.SaasUserId;
}
result = _cachedUserId;
diff --git a/Softeq.XToolkit.Chat/InMemoryMessagesCache.cs b/Softeq.XToolkit.Chat/InMemoryMessagesCache.cs
index 68f196c..aa92862 100644
--- a/Softeq.XToolkit.Chat/InMemoryMessagesCache.cs
+++ b/Softeq.XToolkit.Chat/InMemoryMessagesCache.cs
@@ -110,9 +110,16 @@ public void TryDeleteMessage(string chatId, string deletedMessageId)
public ChatMessageModel FindDuplicateMessage(ChatMessageModel message)
{
var chatMessages = GetMessagesCollectionForChat(message.ChannelId);
- return chatMessages.FirstOrDefault(x => (x.Id == null || x.Id == message.Id) &&
- x.Body == message.Body &&
- x.IsMine == message.IsMine);
+ ChatMessageModel chatMessageModel = null;
+
+ lock (chatMessages)
+ {
+ chatMessageModel = chatMessages.FirstOrDefault(x => (x.Id == null || x.Id == message.Id) &&
+ x.Body == message.Body &&
+ x.IsMine == message.IsMine);
+ }
+
+ return chatMessageModel;
}
public void UpdateSentMessage(ChatMessageModel sentMessage, ChatMessageModel deliveredMessage)
diff --git a/Softeq.XToolkit.Chat/Interfaces/IChatConnectionManager.cs b/Softeq.XToolkit.Chat/Interfaces/IChatConnectionManager.cs
new file mode 100644
index 0000000..5172428
--- /dev/null
+++ b/Softeq.XToolkit.Chat/Interfaces/IChatConnectionManager.cs
@@ -0,0 +1,11 @@
+using System;
+using Softeq.XToolkit.Chat.Models.Enum;
+
+namespace Softeq.XToolkit.Chat.Interfaces
+{
+ public interface IChatConnectionManager
+ {
+ IObservable ConnectionStatusChanged { get; }
+ ConnectionStatus ConnectionStatus { get; }
+ }
+}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat/Interfaces/IChatsListManager.cs b/Softeq.XToolkit.Chat/Interfaces/IChatsListManager.cs
new file mode 100644
index 0000000..5210fff
--- /dev/null
+++ b/Softeq.XToolkit.Chat/Interfaces/IChatsListManager.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Softeq.XToolkit.Chat.Models;
+using Softeq.XToolkit.Chat.ViewModels;
+using Softeq.XToolkit.Common.Collections;
+
+namespace Softeq.XToolkit.Chat.Interfaces
+{
+ public interface IChatsListManager
+ {
+ ObservableRangeCollection ChatsCollection { get; }
+
+ Task CreateChatAsync(string chatName, IList participantsIds, string imagePath);
+ Task EditChatAsync(ChatSummaryModel chatSummary);
+ Task CloseChatAsync(string chatId);
+ Task LeaveChatAsync(string chatId);
+
+ Task InviteMembersAsync(string chatId, IList participantsIds);
+ Task> GetChatMembersAsync(string chatId);
+
+ void RefreshChatsListOnBackgroundAsync();
+ }
+}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat/Manager/ChatManager.Chats.cs b/Softeq.XToolkit.Chat/Manager/ChatManager.Chats.cs
index d2d0e83..cd17818 100644
--- a/Softeq.XToolkit.Chat/Manager/ChatManager.Chats.cs
+++ b/Softeq.XToolkit.Chat/Manager/ChatManager.Chats.cs
@@ -5,34 +5,65 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using Softeq.XToolkit.Chat.Interfaces;
using Softeq.XToolkit.Chat.Models;
using Softeq.XToolkit.Chat.ViewModels;
using Softeq.XToolkit.Common.Collections;
-using TaskExtensions = Softeq.XToolkit.Common.Extensions.TaskExtensions;
+using Softeq.XToolkit.Common.Extensions;
namespace Softeq.XToolkit.Chat.Manager
{
- public partial class ChatManager
+ public partial class ChatManager : IChatsListManager
{
- public async Task UpdateChatsListAsync()
+ public void MakeChatActive(string chatId)
{
- var result = await GetChatsListAsync();
+ _activeChatId = chatId;
+ }
+
+ private Task UpdateChatsListFromNetworkAsync()
+ {
+ return UpdateChatsListWithLoader(GetChatsListAsync());
+ }
+
+ private async Task UpdateChatsListWithLoader(Task> loader)
+ {
+ var result = await loader.ConfigureAwait(false);
if (result != null)
{
- ModifyChatsSafely(() => ChatsCollection.ReplaceRange(result.OrderByDescending(x => x.LastUpdateDate)));
+ var orderedChats = result
+ .Select(_viewModelFactoryService.ResolveViewModel)
+ .OrderByDescending(x => x.LastUpdateDate)
+ .ToList();
+
+ ModifyChatsSafely(() =>
+ {
+ ChatsCollection.ReplaceRange(orderedChats);
+ });
}
}
- public void MakeChatActive(string chatId)
+ private async Task> GetChatsListAsync()
{
- _activeChatId = chatId;
+ var models = await _chatService.GetChatsListAsync().ConfigureAwait(false);
+ if (models == null)
+ {
+ return null;
+ }
+
+ await _localCache.Add(ChatsCacheKey, DateTimeOffset.UtcNow, models).ConfigureAwait(false);
+
+ return models;
}
- public async Task> GetChatsListAsync()
+ public void RefreshChatsListOnBackgroundAsync()
{
- var models = await _chatService.GetChatsHeadersAsync().ConfigureAwait(false);
- return models?.Select(_viewModelFactoryService.ResolveViewModel)?.ToList();
+ if (ChatsCollection.Count == 0)
+ {
+ UpdateChatsListWithLoader(_localCache.Get>(ChatsCacheKey)).SafeTaskWrapper();
+ }
+
+ UpdateChatsListFromNetworkAsync().SafeTaskWrapper();
}
public async Task CreateChatAsync(string chatName, IList participantsIds, string imagePath)
@@ -59,26 +90,13 @@ public Task InviteMembersAsync(string chatId, IList participantsIds)
return _chatService.InviteMembersAsync(chatId, participantsIds);
}
- public async Task> GetContactsAsync(string nameFilter, int pageNumber, int pageSize)
- {
- var models = await _chatService.GetContactsAsync(nameFilter, pageNumber, pageSize).ConfigureAwait(false);
- if (models == null)
- {
- return new List();
- }
-
- return models.Data
- .Select(_viewModelFactoryService.ResolveViewModel)
- .ToList();
- }
-
public async Task> GetChatMembersAsync(string chatId)
{
var models = await _chatService.GetChatMembersAsync(chatId).ConfigureAwait(false);
- return models?.Select(_viewModelFactoryService.ResolveViewModel)?.ToList();
+ return models?.Select(_viewModelFactoryService.ResolveViewModel).ToList();
}
- internal Task EditChatAsync(ChatSummaryModel chatSummary)
+ public Task EditChatAsync(ChatSummaryModel chatSummary)
{
return _chatService.EditChatAsync(chatSummary);
}
@@ -109,7 +127,7 @@ private void OnChatRemoved(string chatId)
}
});
- TaskExtensions.SafeTaskWrapper(_messagesCache.RemoveMessagesAsync(chatId));
+ _messagesCache.RemoveMessagesAsync(chatId).SafeTaskWrapper();
}
private void ModifyChatsSafely(Action modifyAction)
diff --git a/Softeq.XToolkit.Chat/Manager/ChatManager.Messages.cs b/Softeq.XToolkit.Chat/Manager/ChatManager.Messages.cs
index 3d5a292..a31e08e 100644
--- a/Softeq.XToolkit.Chat/Manager/ChatManager.Messages.cs
+++ b/Softeq.XToolkit.Chat/Manager/ChatManager.Messages.cs
@@ -179,7 +179,7 @@ private ChatMessageViewModel AddLatestMessage(ChatMessageModel messageModel)
if (TryAddChat(new ChatSummaryModel { Id = messageViewModel.ChatId }))
{
- UpdateChatsListAsync();
+ UpdateChatsListFromNetworkAsync();
}
ModifyChatsSafely(() =>
{
diff --git a/Softeq.XToolkit.Chat/Manager/ChatManager.cs b/Softeq.XToolkit.Chat/Manager/ChatManager.cs
index b995104..6316d13 100644
--- a/Softeq.XToolkit.Chat/Manager/ChatManager.cs
+++ b/Softeq.XToolkit.Chat/Manager/ChatManager.cs
@@ -6,6 +6,7 @@
using System.ComponentModel;
using System.Reactive.Subjects;
using System.Threading.Tasks;
+using Softeq.XToolkit.Chat.Interfaces;
using Softeq.XToolkit.Chat.Models;
using Softeq.XToolkit.Chat.Models.Enum;
using Softeq.XToolkit.Chat.Models.Interfaces;
@@ -18,15 +19,18 @@
namespace Softeq.XToolkit.Chat.Manager
{
- public partial class ChatManager
+ public partial class ChatManager : IChatConnectionManager
{
+ private const string ChatsCacheKey = "chat_chats";
+
private readonly IChatService _chatService;
private readonly IMessagesCache _messagesCache;
private readonly IViewModelFactoryService _viewModelFactoryService;
private readonly IUploadImageService _uploadImageService;
+ private readonly ILocalCache _localCache;
private readonly ILogger _logger;
- private readonly List _subscriptions = new List();
+ private readonly IList _subscriptions = new List();
private readonly Subject _messageAdded = new Subject();
private readonly Subject _messageEdited = new Subject();
@@ -44,12 +48,14 @@ public ChatManager(
IMessagesCache messagesCache,
IViewModelFactoryService viewModelFactoryService,
ILogManager logManager,
- IUploadImageService uploadImageService)
+ IUploadImageService uploadImageService,
+ ILocalCache localCache)
{
_chatService = chatService;
_messagesCache = messagesCache;
_viewModelFactoryService = viewModelFactoryService;
_uploadImageService = uploadImageService;
+ _localCache = localCache;
_logger = logManager.GetLogger();
_messagesCache.Init(new Common.TaskReference>(
@@ -68,7 +74,7 @@ public ChatManager(
_subscriptions.Add(_chatService.ConnectionStatusChanged.Subscribe(OnConnectionStatusChanged));
OnConnectionStatusChanged(_chatService.ConnectionStatus);
- Messenger.Default.Register(this, x => ForceReconnect());
+ Messenger.Default.Register(this, x => _chatService.ForceReconnect());
Messenger.Default.Register(this, x => _chatService.ForceDisconnect());
}
@@ -93,11 +99,6 @@ private set
public ObservableRangeCollection ChatsCollection { get; }
= new ObservableRangeCollection();
- public void ForceReconnect()
- {
- _chatService.ForceReconnect();
- }
-
public void Logout()
{
_chatService.Logout();
@@ -128,10 +129,10 @@ private void OnConnectionStatusChanged(SocketConnectionStatus connectionStatus)
private async Task UpdateCacheAsync()
{
ConnectionStatus = ConnectionStatus.Updating;
- await Task.WhenAll(UpdateChatsListAsync(), UpdateMessagesCacheAsync()).ConfigureAwait(false);
+ await Task.WhenAll(UpdateChatsListFromNetworkAsync(), UpdateMessagesCacheAsync()).ConfigureAwait(false);
ConnectionStatus = ConnectionStatus.Online;
}
-
+
private void OnCacheUpdated(
string chatId,
IList addedMessages,
@@ -142,11 +143,23 @@ private void OnCacheUpdated(
{
return;
}
+
var addedMessagesViewModels = CreateMessagesViewModels(addedMessages);
- _messagesBatchAdded.OnNext(addedMessagesViewModels);
- _messagesBatchUpdated.OnNext(updatedMessages);
- _messagesBatchDeleted.OnNext(deletedMessagesIds);
+ if (addedMessagesViewModels.Count > 0)
+ {
+ _messagesBatchAdded.OnNext(addedMessagesViewModels);
+ }
+
+ if (updatedMessages.Count > 0)
+ {
+ _messagesBatchUpdated.OnNext(updatedMessages);
+ }
+
+ if (deletedMessagesIds.Count > 0)
+ {
+ _messagesBatchDeleted.OnNext(deletedMessagesIds);
+ }
}
}
}
diff --git a/Softeq.XToolkit.Chat/MockChatService.cs b/Softeq.XToolkit.Chat/MockChatService.cs
index 732fd75..117b183 100644
--- a/Softeq.XToolkit.Chat/MockChatService.cs
+++ b/Softeq.XToolkit.Chat/MockChatService.cs
@@ -18,7 +18,7 @@ public MockChatService(ISocketChatAdapter socketChatAdapter,
{
}
- public override async Task> GetChatsHeadersAsync()
+ public override async Task> GetChatsListAsync()
{
await Task.Delay(500);
return new List { new ChatSummaryModel { Id = "1", Name = "test" } };
diff --git a/Softeq.XToolkit.Chat/Strategies/Search/CreateChatSearchContactsStrategy.cs b/Softeq.XToolkit.Chat/Strategies/Search/CreateChatSearchContactsStrategy.cs
index 1125973..6aa9423 100644
--- a/Softeq.XToolkit.Chat/Strategies/Search/CreateChatSearchContactsStrategy.cs
+++ b/Softeq.XToolkit.Chat/Strategies/Search/CreateChatSearchContactsStrategy.cs
@@ -1,25 +1,25 @@
// Developed by Softeq Development Corporation
// http://www.softeq.com
-using System.Collections.Generic;
using System.Threading.Tasks;
-using Softeq.XToolkit.Chat.Manager;
-using Softeq.XToolkit.Chat.ViewModels;
+using Softeq.XToolkit.Chat.Models;
+using Softeq.XToolkit.Chat.Models.Interfaces;
+using Softeq.XToolkit.Common.Models;
namespace Softeq.XToolkit.Chat.Strategies.Search
{
public class CreateChatSearchContactsStrategy : ISearchContactsStrategy
{
- private readonly ChatManager _chatManager;
+ private readonly IChatService _chatService;
- public CreateChatSearchContactsStrategy(ChatManager chatManager)
+ public CreateChatSearchContactsStrategy(IChatService chatService)
{
- _chatManager = chatManager;
+ _chatService = chatService;
}
- public Task> Search(string query, int pageNumber, int pageSize)
+ public Task> Search(string query, int pageNumber, int pageSize)
{
- return _chatManager.GetContactsAsync(query, pageNumber, pageSize);
+ return _chatService.GetContactsAsync(query, pageNumber, pageSize);
}
}
}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat/Strategies/Search/ISearchContactsStrategy.cs b/Softeq.XToolkit.Chat/Strategies/Search/ISearchContactsStrategy.cs
index f87199d..49764e6 100644
--- a/Softeq.XToolkit.Chat/Strategies/Search/ISearchContactsStrategy.cs
+++ b/Softeq.XToolkit.Chat/Strategies/Search/ISearchContactsStrategy.cs
@@ -1,14 +1,14 @@
// Developed by Softeq Development Corporation
// http://www.softeq.com
-using System.Collections.Generic;
using System.Threading.Tasks;
-using Softeq.XToolkit.Chat.ViewModels;
+using Softeq.XToolkit.Chat.Models;
+using Softeq.XToolkit.Common.Models;
namespace Softeq.XToolkit.Chat.Strategies.Search
{
public interface ISearchContactsStrategy
{
- Task> Search(string query, int pageNumber, int pageSize);
+ Task> Search(string query, int pageNumber, int pageSize);
}
}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat/Strategies/Search/InviteSearchContactsStrategy.cs b/Softeq.XToolkit.Chat/Strategies/Search/InviteSearchContactsStrategy.cs
index efa4acd..edb6e53 100644
--- a/Softeq.XToolkit.Chat/Strategies/Search/InviteSearchContactsStrategy.cs
+++ b/Softeq.XToolkit.Chat/Strategies/Search/InviteSearchContactsStrategy.cs
@@ -1,41 +1,29 @@
// Developed by Softeq Development Corporation
// http://www.softeq.com
-using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Softeq.XToolkit.Chat.Models;
using Softeq.XToolkit.Chat.Models.Interfaces;
-using Softeq.XToolkit.Chat.ViewModels;
-using Softeq.XToolkit.WhiteLabel.Interfaces;
+using Softeq.XToolkit.Common.Models;
namespace Softeq.XToolkit.Chat.Strategies.Search
{
public class InviteSearchContactsStrategy : ISearchContactsStrategy
{
private readonly IChatService _chatService;
- private readonly IViewModelFactoryService _viewModelFactoryService;
private readonly string _chatId;
public InviteSearchContactsStrategy(
IChatService chatService,
- IViewModelFactoryService viewModelFactoryService,
string chatId)
{
_chatService = chatService;
- _viewModelFactoryService = viewModelFactoryService;
_chatId = chatId;
}
- public async Task> Search(string query, int pageNumber, int pageSize)
+ public Task> Search(string query, int pageNumber, int pageSize)
{
- var models = await _chatService.GetContactsForInviteAsync(_chatId, query, pageNumber, pageSize).ConfigureAwait(false);
-
- if (models == null)
- {
- return new List();
- }
- return models.Data.Select(_viewModelFactoryService.ResolveViewModel).ToList();
+ return _chatService.GetContactsForInviteAsync(_chatId, query, pageNumber, pageSize);
}
}
}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat/ViewModels/AddContactsViewModel.cs b/Softeq.XToolkit.Chat/ViewModels/AddContactsViewModel.cs
index 3aa8210..61affd3 100644
--- a/Softeq.XToolkit.Chat/ViewModels/AddContactsViewModel.cs
+++ b/Softeq.XToolkit.Chat/ViewModels/AddContactsViewModel.cs
@@ -6,12 +6,14 @@
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
+using Softeq.XToolkit.Chat.Models;
using Softeq.XToolkit.Chat.Models.Enum;
using Softeq.XToolkit.Chat.Models.Interfaces;
using Softeq.XToolkit.Chat.Strategies.Search;
using Softeq.XToolkit.Common.Collections;
using Softeq.XToolkit.Common.Command;
using Softeq.XToolkit.Common.Extensions;
+using Softeq.XToolkit.Common.Models;
using Softeq.XToolkit.WhiteLabel.Interfaces;
using Softeq.XToolkit.WhiteLabel.Mvvm;
@@ -27,9 +29,7 @@ public class AddContactParameters
public class AddContactsViewModel : DialogViewModelBase, IViewModelParameter
{
private const int SearchDelayMs = 2000;
- private const string InitialContactSearchQuery = "";
- private const int DefaultSearchResultsPageNumber = 1;
- private const int DefaultSearchResultsPageSize = 20000;
+ private const int DefaultSearchResultsPageSize = 20;
private readonly ICommand _contactSelectedCommand;
@@ -38,10 +38,18 @@ public class AddContactsViewModel : DialogViewModelBase, IViewModelParameter _excludedContacts = new List();
- public AddContactsViewModel(IChatLocalizedStrings chatLocalizedStrings)
+ public AddContactsViewModel(
+ IChatLocalizedStrings chatLocalizedStrings,
+ IViewModelFactoryService viewModelFactoryService)
{
Resources = chatLocalizedStrings;
+ PaginationViewModel = new PaginationViewModel(
+ viewModelFactoryService,
+ SearchLoader,
+ SearchFilter,
+ DefaultSearchResultsPageSize);
+
_contactSelectedCommand = new RelayCommand(SwitchSelectedContact);
SearchContactCommand = new RelayCommand(DoSearch);
CancelCommand = new RelayCommand(() => DialogComponent.CloseCommand.Execute(false));
@@ -68,6 +76,8 @@ public AddContactParameters Parameter
}
}
+ public PaginationViewModel PaginationViewModel { get; }
+
public string Title { get; private set; }
public string ContactNameSearchQuery
@@ -75,25 +85,23 @@ public string ContactNameSearchQuery
get => _contactNameSearchQuery;
set
{
- Set(ref _contactNameSearchQuery, value);
-
- SearchContactCommand.Execute(value);
+ if (Set(ref _contactNameSearchQuery, value))
+ {
+ SearchContactCommand.Execute(value);
+ }
}
}
public ObservableRangeCollection SelectedContacts { get; } =
new ObservableRangeCollection();
- public ObservableRangeCollection FoundContacts { get; } =
- new ObservableRangeCollection();
-
public bool HasSelectedContacts => SelectedContacts.Count > 0;
public override async void OnAppearing()
{
base.OnAppearing();
- await LoadContactsAsync(InitialContactSearchQuery);
+ await PaginationViewModel.LoadFirstPageAsync();
}
private async void DoSearch(string query)
@@ -105,7 +113,7 @@ private async void DoSearch(string query)
{
await Task.Delay(SearchDelayMs, _lastSearchCancelSource.Token);
- await LoadContactsAsync(query);
+ await PaginationViewModel.LoadFirstPageAsync();
}
catch (TaskCanceledException)
{
@@ -113,28 +121,25 @@ private async void DoSearch(string query)
}
}
- private async Task LoadContactsAsync(string query)
+ private Task> SearchLoader(int pageNumber, int pageSize)
+ {
+ return _searchContactsStrategy.Search(_contactNameSearchQuery, pageNumber, pageSize);
+ }
+
+ private IReadOnlyList SearchFilter(IReadOnlyList contacts)
{
- FoundContacts.Clear();
+ var filteredContacts = contacts.Where(x => !SelectedContacts
+ .Concat(_excludedContacts)
+ .Select(c => c.Id)
+ .Contains(x.Id)
+ ).ToList();
- var contacts = await _searchContactsStrategy.Search(query,
- DefaultSearchResultsPageNumber,
- DefaultSearchResultsPageSize).ConfigureAwait(false);
+ ApplySelectionCommand(filteredContacts, true);
- if (contacts != null)
- {
- var filteredContacts = contacts.Where(x => !SelectedContacts
- .Concat(_excludedContacts)
- .Select(c => c.Id)
- .Contains(x.Id)
- ).ToList();
-
- ApplySelectionCommand(filteredContacts);
- FoundContacts.AddRange(filteredContacts);
- }
+ return filteredContacts;
}
- private void ApplySelectionCommand(IEnumerable contacts, bool isSelectable = true)
+ private void ApplySelectionCommand(IEnumerable contacts, bool isSelectable)
{
contacts.Apply(x =>
{
diff --git a/Softeq.XToolkit.Chat/ViewModels/ChatDetailsViewModel.cs b/Softeq.XToolkit.Chat/ViewModels/ChatDetailsViewModel.cs
index a4f25fa..446ee6f 100644
--- a/Softeq.XToolkit.Chat/ViewModels/ChatDetailsViewModel.cs
+++ b/Softeq.XToolkit.Chat/ViewModels/ChatDetailsViewModel.cs
@@ -2,12 +2,11 @@
// http://www.softeq.com
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
-using Softeq.XToolkit.Chat.Manager;
+using Softeq.XToolkit.Chat.Interfaces;
using Softeq.XToolkit.Chat.Models;
using Softeq.XToolkit.Chat.Models.Enum;
using Softeq.XToolkit.Chat.Models.Interfaces;
@@ -18,7 +17,6 @@
using Softeq.XToolkit.Chat.Strategies.Search;
using Softeq.XToolkit.Common.Extensions;
using Softeq.XToolkit.WhiteLabel;
-using Softeq.XToolkit.WhiteLabel.Interfaces;
using Softeq.XToolkit.WhiteLabel.Model;
using Softeq.XToolkit.WhiteLabel.Threading;
@@ -26,32 +24,29 @@ namespace Softeq.XToolkit.Chat.ViewModels
{
public class ChatDetailsViewModel : ViewModelBase
{
- private readonly ChatManager _chatManager;
+ private readonly IChatsListManager _chatsListManager;
private readonly IPageNavigationService _pageNavigationService;
private readonly IFormatService _formatService;
private readonly IUploadImageService _uploadImageService;
private readonly IDialogsService _dialogsService;
private readonly IChatService _chatService;
- private readonly IViewModelFactoryService _viewModelFactoryService;
public ChatDetailsViewModel(
- ChatManager chatManager,
+ IChatsListManager chatsListManager,
IPageNavigationService pageNavigationService,
IChatLocalizedStrings localizedStrings,
IFormatService formatService,
IUploadImageService uploadImageService,
IDialogsService dialogsService,
- IChatService chatService,
- IViewModelFactoryService viewModelFactoryService)
+ IChatService chatService)
{
- _chatManager = chatManager;
+ _chatsListManager = chatsListManager;
_pageNavigationService = pageNavigationService;
LocalizedStrings = localizedStrings;
_formatService = formatService;
_uploadImageService = uploadImageService;
_dialogsService = dialogsService;
_chatService = chatService;
- _viewModelFactoryService = viewModelFactoryService;
AddMembersCommand = new RelayCommand(AddMembers);
BackCommand = new RelayCommand(_pageNavigationService.GoBack, () => _pageNavigationService.CanGoBack);
@@ -72,15 +67,13 @@ public ChatDetailsViewModel(
public ICommand BackCommand { get; }
public RelayCommand RemoveMemberAtCommand { get; }
- public IList MenuActions { get; } = new List();
-
public override async void OnAppearing()
{
base.OnAppearing();
Members.Clear();
- var members = await _chatManager.GetChatMembersAsync(Summary.Id);
+ var members = await _chatsListManager.GetChatMembersAsync(Summary.Id);
Members.AddRange(members);
RaisePropertyChanged(nameof(MembersCountText));
}
@@ -130,7 +123,7 @@ public async Task SaveAsync(Func<(Task GetImageTask, string Extension)>
Summary.AvatarUrl = imagePath;
RaisePropertyChanged(nameof(Summary.AvatarUrl));
- await _chatManager.EditChatAsync(Summary).ConfigureAwait(false);
+ await _chatsListManager.EditChatAsync(Summary).ConfigureAwait(false);
}
Execute.BeginOnUIThread(() =>
@@ -146,8 +139,7 @@ private async void AddMembers()
{
SelectedContacts = Members,
SelectionType = SelectedContactsAction.InviteToChat,
- SearchStrategy = new InviteSearchContactsStrategy(_chatService,
- _viewModelFactoryService, Summary.Id)
+ SearchStrategy = new InviteSearchContactsStrategy(_chatService, Summary.Id)
},
new OpenDialogOptions
{
@@ -165,7 +157,7 @@ private async void AddMembers()
try
{
- await _chatManager.InviteMembersAsync(Summary.Id, contactsForInvite);
+ await _chatsListManager.InviteMembersAsync(Summary.Id, contactsForInvite);
}
catch (Exception ex)
{
diff --git a/Softeq.XToolkit.Chat/ViewModels/ChatMessagesViewModel.cs b/Softeq.XToolkit.Chat/ViewModels/ChatMessagesViewModel.cs
index 2f7d702..c841991 100644
--- a/Softeq.XToolkit.Chat/ViewModels/ChatMessagesViewModel.cs
+++ b/Softeq.XToolkit.Chat/ViewModels/ChatMessagesViewModel.cs
@@ -9,7 +9,6 @@
using System.Windows.Input;
using Softeq.XToolkit.Chat.Manager;
using Softeq.XToolkit.Chat.Models;
-using Softeq.XToolkit.Chat.Models.Enum;
using Softeq.XToolkit.Common.Collections;
using Softeq.XToolkit.Common.Command;
using Softeq.XToolkit.Common.EventArguments;
@@ -19,6 +18,7 @@
using Softeq.XToolkit.WhiteLabel.Navigation;
using Softeq.XToolkit.Chat.Models.Interfaces;
using System.IO;
+using Softeq.XToolkit.WhiteLabel.Threading;
namespace Softeq.XToolkit.Chat.ViewModels
{
@@ -31,14 +31,15 @@ public class ChatMessagesViewModel : ViewModelBase, IViewModelParameter _subscriptions = new List();
-
+ private readonly IList _subscriptions = new List();
+
private ChatSummaryViewModel _chatSummaryViewModel;
- private ChatMessageViewModel _messageBeingEdited;
-
+ private ChatMessageViewModel _messageBeingEdited;
+
private bool _areLatestMessagesLoaded;
private string _messageToSendBody = string.Empty;
-
+ private bool _isInEditMessageMode;
+
public ChatMessagesViewModel(
IPageNavigationService pageNavigationService,
IChatLocalizedStrings localizedStrings,
@@ -67,12 +68,9 @@ public ChatSummaryViewModel Parameter
{
_chatSummaryViewModel = value;
RaisePropertyChanged(nameof(ChatName));
-
- // TODO: affected by different ways of register ViewModel on each platform
- ClearMessages();
}
- }
-
+ }
+
public ObservableKeyGroupsCollection Messages { get; }
= new ObservableKeyGroupsCollection(message => message.DateTime.Date,
(x, y) => x.CompareTo(y),
@@ -90,7 +88,11 @@ public string MessageToSendBody
public string EditedMessageOriginalBody => _messageBeingEdited?.Body;
- public bool IsInEditMessageMode { get; private set; }
+ public bool IsInEditMessageMode
+ {
+ get => _isInEditMessageMode;
+ private set => Set(ref _isInEditMessageMode, value);
+ }
public ICommand BackCommand { get; }
public RelayCommand, string)>>> SendCommand { get; }
@@ -129,10 +131,10 @@ public override void OnAppearing()
_subscriptions.Add(_chatManager.MessageDeleted.Subscribe(OnMessageDeleted));
_subscriptions.Add(_chatManager.MessagesBatchAdded.Subscribe(OnMessagesBatchReceived));
_subscriptions.Add(_chatManager.MessagesBatchUpdated.Subscribe(OnMessagesBatchUpdated));
- _subscriptions.Add(_chatManager.MessagesBatchDeleted.Subscribe(OnMessagesBatchDeleted));
- _subscriptions.Add(_chatManager.ConnectionStatusChanged.Subscribe(OnConnectionStatusChanged));
- OnConnectionStatusChanged(_chatManager.ConnectionStatus);
-
+ _subscriptions.Add(_chatManager.MessagesBatchDeleted.Subscribe(OnMessagesBatchDeleted));
+
+ ConnectionStatusViewModel.Initialize(ChatName);
+
if (!_areLatestMessagesLoaded)
{
LoadInitialMessagesAsync().SafeTaskWrapper();
@@ -149,7 +151,9 @@ public override void OnDisappearing()
base.OnDisappearing();
Messages.ItemsChanged -= OnMessagesAddedToCollection;
- _subscriptions.Apply(x => x.Dispose());
+ _subscriptions.Apply(x => x.Dispose());
+
+ ConnectionStatusViewModel.Dispose();
}
public async Task LoadOlderMessagesAsync()
@@ -255,12 +259,6 @@ private void OnMessagesBatchDeleted(IList deletedMessagesIds)
DeleteAllMessages(x => deletedMessagesIds.Contains(x.Id));
}
- private void OnConnectionStatusChanged(ConnectionStatus status)
- {
- ConnectionStatusViewModel.UpdateConnectionStatus(status, ChatName);
- RaisePropertyChanged(nameof(ConnectionStatusViewModel));
- }
-
private void DeleteAllMessages(Func predicate)
{
var messagesToDelete = Messages
@@ -273,23 +271,28 @@ private void DeleteAllMessages(Func predicate)
private async void SendMessageAsync(GenericEventArgs, string)>> e)
{
+ var photoSelector = e?.Value;
var newMessageBody = MessageToSendBody?.Trim();
- if (string.IsNullOrEmpty(newMessageBody))
+
+ if (photoSelector == null && string.IsNullOrEmpty(newMessageBody))
{
return;
}
MessageToSendBody = string.Empty;
- if (IsInEditMessageMode && _messageBeingEdited != null)
+ if (IsInEditMessageMode)
{
- var editedMessageId = _messageBeingEdited.Id;
+ IsInEditMessageMode = false;
+
+ await _chatManager.EditMessageAsync(_messageBeingEdited.Id, newMessageBody).ConfigureAwait(false);
+
CancelEditingMessageMode();
- await _chatManager.EditMessageAsync(editedMessageId, newMessageBody).ConfigureAwait(false);
}
else
{
- await _chatManager.SendMessageAsync(_chatSummaryViewModel.ChatId, newMessageBody, e?.Value).ConfigureAwait(false);
+ await _chatManager.SendMessageAsync(_chatSummaryViewModel.ChatId, newMessageBody, photoSelector)
+ .ConfigureAwait(false);
}
}
@@ -317,24 +320,28 @@ private async void DeleteMessage(ChatMessageViewModel message)
private void EditMessage(ChatMessageViewModel message)
{
- SetIsInEditMessageMode(true, message);
+ SetMessageEditMode(true, message);
}
private void CancelEditingMessageMode()
{
- SetIsInEditMessageMode(false);
+ SetMessageEditMode(false);
}
- private void SetIsInEditMessageMode(bool value, ChatMessageViewModel editedMessage = null)
+ private void SetMessageEditMode(bool value, ChatMessageViewModel editedMessage = null)
{
if (value && editedMessage == null)
{
return;
}
- IsInEditMessageMode = value;
+
_messageBeingEdited = value ? editedMessage : null;
- MessageToSendBody = editedMessage?.Body;
- RaisePropertyChanged(nameof(IsInEditMessageMode));
+
+ Execute.BeginOnUIThread(() =>
+ {
+ MessageToSendBody = editedMessage?.Body;
+ IsInEditMessageMode = value;
+ });
}
}
}
diff --git a/Softeq.XToolkit.Chat/ViewModels/ChatsListViewModel.cs b/Softeq.XToolkit.Chat/ViewModels/ChatsListViewModel.cs
index e9e0b88..eb30914 100644
--- a/Softeq.XToolkit.Chat/ViewModels/ChatsListViewModel.cs
+++ b/Softeq.XToolkit.Chat/ViewModels/ChatsListViewModel.cs
@@ -1,12 +1,9 @@
// Developed by Softeq Development Corporation
// http://www.softeq.com
-using System;
-using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Input;
-using Softeq.XToolkit.Chat.Manager;
-using Softeq.XToolkit.Chat.Models.Enum;
+using Softeq.XToolkit.Chat.Interfaces;
using Softeq.XToolkit.Chat.Models.Interfaces;
using Softeq.XToolkit.Common.Collections;
using Softeq.XToolkit.Common.Command;
@@ -18,32 +15,26 @@ namespace Softeq.XToolkit.Chat.ViewModels
{
public class ChatsListViewModel : ViewModelBase
{
- private readonly IDialogsService _dialogsService;
private readonly IPageNavigationService _pageNavigationService;
- private readonly IChatLocalizedStrings _localizedStrings;
- private readonly ChatManager _chatManager;
-
- private List _subscriptions = new List();
+ private readonly IChatsListManager _chatsListManager;
public ChatsListViewModel(
- IDialogsService dialogsService,
IPageNavigationService pageNavigationService,
IChatLocalizedStrings localizedStrings,
- ChatManager chatManager,
+ IChatsListManager chatsListManager,
ConnectionStatusViewModel connectionStatusViewModel)
{
- _dialogsService = dialogsService;
_pageNavigationService = pageNavigationService;
- _localizedStrings = localizedStrings;
- _chatManager = chatManager;
-
+ _chatsListManager = chatsListManager;
+
+ LocalizedStrings = localizedStrings;
ConnectionStatusViewModel = connectionStatusViewModel;
- Chats = _chatManager.ChatsCollection;
+ Chats = _chatsListManager.ChatsCollection;
CreateChatCommand = new RelayCommand(CreateChat);
- LeaveChatCommand = new RelayCommand((x) => LeaveChatAsync(x).SafeTaskWrapper());
- DeleteChatCommand = new RelayCommand((x) => DeleteChatAsync(x).SafeTaskWrapper());
+ LeaveChatCommand = new RelayCommand(x => LeaveChatAsync(x).SafeTaskWrapper());
+ DeleteChatCommand = new RelayCommand(x => DeleteChatAsync(x).SafeTaskWrapper());
}
public ICommand CreateChatCommand { get; }
@@ -52,38 +43,41 @@ public ChatsListViewModel(
public ObservableRangeCollection Chats { get; }
+ public ConnectionStatusViewModel ConnectionStatusViewModel { get; }
+
+ public IChatLocalizedStrings LocalizedStrings { get; }
+
public ChatSummaryViewModel SelectedChat
{
get => null;
set
{
RaisePropertyChanged();
+
if (value != null)
{
- _pageNavigationService.For().WithParam(x => x.Parameter, value).Navigate();
+ _pageNavigationService
+ .For()
+ .WithParam(x => x.Parameter, value)
+ .Navigate();
}
}
}
- public ConnectionStatusViewModel ConnectionStatusViewModel { get; }
-
- public string DeleteChatOptionText => _localizedStrings.Close;
- public string LeaveChatOptionText => _localizedStrings.Leave;
-
public override void OnAppearing()
{
base.OnAppearing();
- _chatManager.ForceReconnect();
-
- _subscriptions.Add(_chatManager.ConnectionStatusChanged.Subscribe(OnConnectionStatusChanged));
- OnConnectionStatusChanged(_chatManager.ConnectionStatus);
+ ConnectionStatusViewModel.Initialize(LocalizedStrings.ChatsTitle);
+
+ _chatsListManager.RefreshChatsListOnBackgroundAsync();
}
public override void OnDisappearing()
{
base.OnDisappearing();
- _subscriptions.Apply(x => x.Dispose());
+
+ ConnectionStatusViewModel.Dispose();
}
private void CreateChat()
@@ -93,18 +87,12 @@ private void CreateChat()
private Task LeaveChatAsync(ChatSummaryViewModel chatViewModel)
{
- return _chatManager.LeaveChatAsync(chatViewModel.ChatId);
+ return _chatsListManager.LeaveChatAsync(chatViewModel.ChatId);
}
private Task DeleteChatAsync(ChatSummaryViewModel chatViewModel)
{
- return _chatManager.CloseChatAsync(chatViewModel.ChatId);
- }
-
- private void OnConnectionStatusChanged(ConnectionStatus status)
- {
- ConnectionStatusViewModel.UpdateConnectionStatus(status, _localizedStrings.ChatsTitle);
- RaisePropertyChanged(nameof(ConnectionStatusViewModel));
+ return _chatsListManager.CloseChatAsync(chatViewModel.ChatId);
}
}
}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat/ViewModels/ConnectionStatusViewModel.cs b/Softeq.XToolkit.Chat/ViewModels/ConnectionStatusViewModel.cs
index 535da24..316a626 100644
--- a/Softeq.XToolkit.Chat/ViewModels/ConnectionStatusViewModel.cs
+++ b/Softeq.XToolkit.Chat/ViewModels/ConnectionStatusViewModel.cs
@@ -1,32 +1,65 @@
// Developed by Softeq Development Corporation
// http://www.softeq.com
-using System.ComponentModel;
+using System;
+using System.ComponentModel;
+using Softeq.XToolkit.Chat.Exceptions;
+using Softeq.XToolkit.Chat.Interfaces;
using Softeq.XToolkit.Chat.Models.Enum;
using Softeq.XToolkit.Chat.Models.Interfaces;
using Softeq.XToolkit.WhiteLabel.Mvvm;
namespace Softeq.XToolkit.Chat.ViewModels
{
- public class ConnectionStatusViewModel : ObservableObject
+ public class ConnectionStatusViewModel : ObservableObject, IDisposable
{
private readonly IChatLocalizedStrings _localizedStrings;
+ private readonly IChatConnectionManager _chatConnectionManager;
+
+ private IDisposable _connectionStatusChangedSubscription;
+ private string _onlineTextStatus;
+ private string _connectionStatusText;
+ private bool _isOnline;
- public ConnectionStatusViewModel(IChatLocalizedStrings localizedStrings)
+ public ConnectionStatusViewModel(
+ IChatLocalizedStrings localizedStrings,
+ IChatConnectionManager chatConnectionManager)
{
_localizedStrings = localizedStrings;
+ _chatConnectionManager = chatConnectionManager;
}
- public string ConnectionStatusText { get; private set; }
+ public string ConnectionStatusText
+ {
+ get => _connectionStatusText;
+ private set => Set(ref _connectionStatusText, value);
+ }
+
+ public bool IsOnline
+ {
+ get => _isOnline;
+ private set => Set(ref _isOnline, value);
+ }
- public bool IsOnline { get; private set; }
+ public void Initialize(string onlineTextStatus)
+ {
+ _onlineTextStatus = onlineTextStatus ?? throw new ArgumentNullException(nameof(onlineTextStatus));
+ _connectionStatusChangedSubscription = _chatConnectionManager.ConnectionStatusChanged.Subscribe(UpdateConnectionStatus);
- public void UpdateConnectionStatus(ConnectionStatus status, string onlineStatusText)
+ UpdateConnectionStatus(_chatConnectionManager.ConnectionStatus);
+ }
+
+ private void UpdateConnectionStatus(ConnectionStatus status)
{
+ if (_onlineTextStatus == null)
+ {
+ throw new ChatException("Need to call Initialize() method before.");
+ }
+
switch (status)
{
case ConnectionStatus.Online:
- ConnectionStatusText = onlineStatusText;
+ ConnectionStatusText = _onlineTextStatus;
break;
case ConnectionStatus.WaitingForNetwork:
ConnectionStatusText = _localizedStrings.WaitingForNetwork;
@@ -42,9 +75,20 @@ public void UpdateConnectionStatus(ConnectionStatus status, string onlineStatusT
}
IsOnline = status == ConnectionStatus.Online;
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _connectionStatusChangedSubscription?.Dispose();
+ }
+ }
- RaisePropertyChanged(nameof(ConnectionStatusText));
- RaisePropertyChanged(nameof(IsOnline));
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Softeq.XToolkit.Chat/ViewModels/PaginationViewModel.cs b/Softeq.XToolkit.Chat/ViewModels/PaginationViewModel.cs
new file mode 100644
index 0000000..869817c
--- /dev/null
+++ b/Softeq.XToolkit.Chat/ViewModels/PaginationViewModel.cs
@@ -0,0 +1,91 @@
+// Developed by Softeq Development Corporation
+// http://www.softeq.com
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Softeq.XToolkit.Common.Collections;
+using Softeq.XToolkit.Common.Models;
+using Softeq.XToolkit.WhiteLabel.Interfaces;
+using Softeq.XToolkit.WhiteLabel.Mvvm;
+
+namespace Softeq.XToolkit.Chat.ViewModels
+{
+ public class PaginationViewModel
+ where TViewModel : ObservableObject, IViewModelParameter
+ {
+ private readonly IViewModelFactoryService _viewModelFactoryService;
+ private readonly Func>> _loaderAction;
+ private readonly Func, IReadOnlyList> _filterAction;
+ private readonly int _pageSize;
+
+ private int _pageNumber = 1;
+
+ public PaginationViewModel(
+ IViewModelFactoryService viewModelFactory,
+ Func>> loaderAction,
+ Func, IReadOnlyList> filterAction,
+ int pageSize)
+ {
+ _viewModelFactoryService = viewModelFactory ?? throw new ArgumentNullException(nameof(viewModelFactory));
+ _loaderAction = loaderAction ?? throw new ArgumentNullException(nameof(loaderAction));
+ _filterAction = filterAction;
+ _pageSize = pageSize;
+ }
+
+ public ObservableRangeCollection Items { get; } = new ObservableRangeCollection();
+
+ public async Task LoadFirstPageAsync()
+ {
+ _pageNumber = 1;
+
+ var viewModels = await LoadPageAsync(_pageNumber).ConfigureAwait(false);
+
+ Items.ReplaceRange(viewModels);
+ }
+
+ public async Task LoadNextPageAsync()
+ {
+ Interlocked.Increment(ref _pageNumber);
+
+ var viewModels = await LoadPageAsync(_pageNumber).ConfigureAwait(false);
+
+ if (viewModels.Count > 0)
+ {
+ Items.AddRange(viewModels);
+ }
+ else
+ {
+ Interlocked.Decrement(ref _pageNumber);
+ }
+ }
+
+ private async Task> LoadPageAsync(int pageNumber)
+ {
+ var pagingModel = await _loaderAction(pageNumber, _pageSize).ConfigureAwait(false);
+ if (pagingModel == null)
+ {
+ return new List();
+ }
+
+ if (pagingModel.Page == pagingModel.TotalNumberOfPages &&
+ pagingModel.Data.Count == 0)
+ {
+ return new List();
+ }
+
+ var viewModels = pagingModel.Data
+ .Select(_viewModelFactoryService.ResolveViewModel)
+ .ToList();
+
+ if (_filterAction != null)
+ {
+ return _filterAction(viewModels);
+ }
+
+ return viewModels;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Softeq.XToolkit.Chat/ViewModels/SelectContactsViewModel.cs b/Softeq.XToolkit.Chat/ViewModels/SelectContactsViewModel.cs
index 5b0d572..e229de3 100644
--- a/Softeq.XToolkit.Chat/ViewModels/SelectContactsViewModel.cs
+++ b/Softeq.XToolkit.Chat/ViewModels/SelectContactsViewModel.cs
@@ -6,7 +6,7 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
-using Softeq.XToolkit.Chat.Manager;
+using Softeq.XToolkit.Chat.Interfaces;
using Softeq.XToolkit.Chat.Models.Enum;
using Softeq.XToolkit.Chat.Models.Interfaces;
using Softeq.XToolkit.Chat.Strategies.Search;
@@ -21,27 +21,31 @@
namespace Softeq.XToolkit.Chat.ViewModels
{
+ // TODO YP: rename to CreateChatViewModel or merge with ChatDetailsViewModel
public class SelectContactsViewModel : ViewModelBase
{
- private readonly ChatManager _chatManager;
+ private readonly IChatsListManager _chatsListManager;
+ private readonly IChatService _chatService;
private readonly IFormatService _formatService;
private readonly IChatLocalizedStrings _localizedStrings;
private readonly ICommand _memberSelectedCommand;
private readonly IPageNavigationService _pageNavigationService;
private readonly IUploadImageService _uploadImageService;
private readonly IDialogsService _dialogsService;
-
+
private string _chatName;
public SelectContactsViewModel(
- ChatManager chatManager,
+ IChatsListManager chatsListManager,
+ IChatService chatService,
IPageNavigationService pageNavigationService,
IChatLocalizedStrings localizedStrings,
IFormatService formatService,
IUploadImageService uploadImageService,
IDialogsService dialogsService)
{
- _chatManager = chatManager;
+ _chatsListManager = chatsListManager;
+ _chatService = chatService;
_pageNavigationService = pageNavigationService;
_localizedStrings = localizedStrings;
_formatService = formatService;
@@ -94,7 +98,7 @@ private async void OpenDialogForAddMembers()
{
SelectedContacts = Contacts,
SelectionType = SelectedContactsAction.CreateChat,
- SearchStrategy = new CreateChatSearchContactsStrategy(_chatManager)
+ SearchStrategy = new CreateChatSearchContactsStrategy(_chatService)
},
new OpenDialogOptions
{
@@ -113,12 +117,7 @@ private async void OpenDialogForAddMembers()
private async void SaveAsync(Func<(Task GetImageTask, string Extension)> getImageFunc)
{
- if (string.IsNullOrEmpty(ChatName))
- {
- return;
- }
-
- if (IsBusy)
+ if (IsBusy || string.IsNullOrEmpty(ChatName))
{
return;
}
@@ -140,12 +139,12 @@ private async void SaveAsync(Func<(Task GetImageTask, string Extension)>
try
{
var selectedContactsIds = Contacts.Where(x => x.IsSelected).Select(x => x.Id).ToList();
- await _chatManager.CreateChatAsync(ChatName, selectedContactsIds, imagePath).ConfigureAwait(false);
-
+ await _chatsListManager.CreateChatAsync(ChatName, selectedContactsIds, imagePath).ConfigureAwait(false);
+
Execute.BeginOnUIThread(() =>
{
ChatName = string.Empty;
-
+
_pageNavigationService.GoBack();
});
}