Let's move back to the Android implementation. This part is easy, we have already mapped the UI logic to the ChatPresenter
, so let's get straight into building the interface. Add a new file to the Views
folder in the Chat.Droid
project, call it ChatActivity.cs
, and implement the first part:
[Activity(Label = "Chat", ScreenOrientation = ScreenOrientation.Portrait)] public class ChatView : ListActivity, ChatPresenter.IChatView { #region Private Properties private ChatPresenter _presenter; private LinearLayout _scrollViewInnerLayout; private EditText _editText; private long _lastSendClick = 0; private int _width; private float _currentTop; private bool _dialogShown = false; #endregion #region Protected Methods protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); SetContentView(Resource.Layout.ChatView); var metrics = Resources.DisplayMetrics; _width = (int)(( metrics.WidthPixels) / Resources.DisplayMetrics.Density); _scrollViewInnerLayout = FindViewById<LinearLayout> (Resource.Id.scrollViewInnerLayout); _editText = FindViewById<EditText>(Resource.Id.chatField); var sendButton = FindViewById<Button>(Resource.Id.sendButton); sendButton.Touch += HandleSendButton; var app = ChatApplication.GetApplication(this); app.CurrentActivity = this; _presenter = app.Presenter as ChatPresenter; _presenter.SetView(this); app.CurrentActivity = this; } #endregion }
In the OnCreate
function, we are setting the content view to the ChatView
layout. We then retrieve the width of the screen as we need to be able position the x-axis of the chat box to the left or right of the screen, based on whether it was sent/received. We then assign the SendButton's Touch
event to call the HandleSendButton
function. Finally, we retrieve the ChatApplication
object and cast the presenter to a ChatPresenter
, call the SetView
function, and pass the ChatActivity
. Then we set the CurrentActivity
of the ChatApplication
object to the ChatActivity
. Let's also add an override on the OnPause
so we can call ReleaseView
on the ChatPresenter
to remove the OnDataReceived
event from the SignalRClient
. This is the equivalent to the ViewDidUnload
override on a UIViewController
:
protected override void OnPause() { base.OnPause(); if (_presenter != null) { _presenter.ReleaseView(); } }
Now we have to add the IChatView
implementation; CreateChatBox
must be propagated to the main thread as this event will sometimes call this function on a different thread:
#region IChatView implementation public void NotifyChatMessageReceived(string message) { // perform action on UI thread Application.SynchronizationContext.Post(state => { CreateChatBox(true, message); }, null); } #endregion
Now we have to add the IView
implementation, which we can simply copy from the previous activity:
#region IView implementation public void SetErrorMessage(string message) { if (!_dialogShown) { _dialogShown = true; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder .SetTitle("Chat") .SetMessage(message) .SetNeutralButton("Ok", (sender, e) => { _dialogShown = false; }) .Show(); } } public bool IsInProgress { get; set; } #endregion
Before we add the remaining functions, we are going to add another layout for the ChatBoxView
in Android. Add a new file called ChatBoxView.xml
, add it to the Resources | layout folder, and implement the following:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:weightSum="4"> <TextView android:id="@+id/messageTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout>
This is a very simple view which contains a LinearLayout
that contains one TextView
to display the chat message.
Finally, we add the remaining HandleSendButton
and CreateChatBox
functions; they are the same functions as iOS, but use Android objects:
#region Private Methods private void HandleSendButton(object sender, View.TouchEventArgs e) { // multiple-clicking prevention using a threshold of 1000 ms if (SystemClock.ElapsedRealtime() - _lastSendClick < 1000) { return; } _lastSendClick = SystemClock.ElapsedRealtime(); _presenter.SendChat(_editText.Text).ConfigureAwait(false); CreateChatBox(false, _editText.Text); } #endregion #region Public Methods public void CreateChatBox(bool received, string message) { var view = LayoutInflater.Inflate(Resource.Layout.ChatBoxView, null); view.SetX(received ? _width : 0); view.SetY(_currentTop); var messageTextView = view.FindViewById<TextView> (Resource.Id.messageTextView); messageTextView.Text = message; var color = Color.ParseColor(received ? "#4CD964" : "#5AC8FA"); messageTextView.SetBackgroundColor(color); _scrollViewInnerLayout.AddView(view); _currentTop += 60; } #endregion
The HandleSendButton
function will do the exact same: call the presenter function, SendChat
, create a new chatbox, and add it to the ScrollView
. The CreateChatBox
function will use the context's LayoutInflator
and create a new ChatBoxView
. We will then set the x, y, width and height properties, retrieve the TextView
property of the view, and set the Text
property to the message. We then call SetBackgroundColor
on the view and change the background color according to whether it has been sent or received. Finally, we add the new view to the ScrollView
and record the current y-axis value.
18.224.0.25