Skip to content

Commit d198a57

Browse files
committed
Added an iOS sample project
1 parent 10729de commit d198a57

21 files changed

Lines changed: 1021 additions & 41 deletions

Src/SocketIoClientDotNet.Sample.Xamarin-Android/ChatFragment.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class ChatFragment : Fragment
2323
private readonly Socket socket;
2424
private readonly ChatAdapter adapter;
2525

26-
private List<ChatAdapter.ChatItem> chatItems = new List<ChatAdapter.ChatItem>();
26+
private readonly List<ChatAdapter.ChatItem> chatItems = new List<ChatAdapter.ChatItem>();
2727
private List<string> typingItems = new List<string>();
2828
private bool connected = false;
2929
private bool typing = false;
@@ -36,7 +36,7 @@ public ChatFragment(string username, Socket socket, AlertDialog alert)
3636
this.socket = socket;
3737
this.adapter = new ChatAdapter(chatItems);
3838

39-
AttachSocketEvents(socket, alert);
39+
AttachSocketEvents(alert);
4040
}
4141

4242
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
@@ -66,7 +66,7 @@ public override View OnCreateView(LayoutInflater inflater, ViewGroup container,
6666
return view;
6767
}
6868

69-
private void AttachSocketEvents(Socket socket, AlertDialog alert)
69+
private void AttachSocketEvents(AlertDialog alert)
7070
{
7171
// Whenever the server emits "login", log the login message
7272
socket.On("login", data =>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Foundation;
2+
using UIKit;
3+
4+
namespace SocketIoClientDotNet.Sample.XamariniOS
5+
{
6+
[Register ("AppDelegate")]
7+
public class AppDelegate : UIApplicationDelegate
8+
{
9+
public override UIWindow Window { get; set; }
10+
}
11+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Foundation;
4+
using UIKit;
5+
6+
namespace SocketIoClientDotNet.Sample.XamariniOS
7+
{
8+
public class ChatAdapter : UITableViewDelegate, IUITableViewDataSource
9+
{
10+
private readonly List<ChatAdapter.ChatItem> chatItems;
11+
12+
public ChatAdapter (List<ChatAdapter.ChatItem> chatItems)
13+
{
14+
this.chatItems = chatItems;
15+
}
16+
17+
public nint RowsInSection (UITableView tableView, nint section)
18+
{
19+
return chatItems.Count;
20+
}
21+
22+
public UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
23+
{
24+
var item = chatItems [indexPath.Row];
25+
var cell = item.Username == null
26+
? tableView.DequeueReusableCell ("singleLine")
27+
: tableView.DequeueReusableCell ("titledLine");
28+
29+
if (item.Username == null) {
30+
cell.TextLabel.Text = item.Message;
31+
} else {
32+
cell.TextLabel.Text = item.Username;
33+
cell.DetailTextLabel.Text = item.Message;
34+
}
35+
36+
return cell;
37+
}
38+
39+
public struct ChatItem
40+
{
41+
public ChatItem (string username, string message)
42+
: this ()
43+
{
44+
Username = username;
45+
Message = message;
46+
}
47+
48+
public string Username { get; set; }
49+
50+
public string Message { get; set; }
51+
}
52+
}
53+
}
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using CoreGraphics;
6+
using Foundation;
7+
using UIKit;
8+
9+
using Quobject.SocketIoClientDotNet.Client;
10+
11+
namespace SocketIoClientDotNet.Sample.XamariniOS
12+
{
13+
partial class ChatViewController : UIViewController
14+
{
15+
private const int TypingTimerDelay = 400; // ms
16+
17+
private Socket socket;
18+
private readonly ChatAdapter adapter;
19+
private UITableView chatWindow;
20+
21+
private readonly List<ChatAdapter.ChatItem> chatItems = new List<ChatAdapter.ChatItem> ();
22+
private List<string> typingItems = new List<string> ();
23+
private bool connected = false;
24+
private bool typing = false;
25+
26+
public ChatViewController (IntPtr handle)
27+
: base (handle)
28+
{
29+
adapter = new ChatAdapter (chatItems);
30+
}
31+
32+
public string Username { get; set; }
33+
34+
public override void ViewDidLoad ()
35+
{
36+
base.ViewDidLoad ();
37+
38+
if (socket != null) {
39+
socket.Close ();
40+
}
41+
42+
socket = IO.Socket ("http://chat.socket.io/");
43+
socket.Connect ();
44+
45+
var alert = new UIAlertView ("Log in", "Logging in...", null, null, null);
46+
alert.Show ();
47+
48+
AttachSocketEvents (alert);
49+
50+
// Tell the server your username (login)
51+
socket.Emit ("add user", Username);
52+
53+
entryText.Selected = true;
54+
entryText.Started += (sender, e) => {
55+
if (connected) {
56+
if (!typing) {
57+
typing = true;
58+
socket.Emit ("typing");
59+
}
60+
}
61+
};
62+
entryText.Ended += (sender, e) => {
63+
if (connected) {
64+
if (typing) {
65+
socket.Emit ("stop typing");
66+
typing = false;
67+
}
68+
}
69+
};
70+
sendButton.TouchUpInside += (sender, e) => {
71+
SendMessage ();
72+
socket.Emit ("stop typing");
73+
typing = false;
74+
};
75+
76+
// scroll up when the keyboard appears
77+
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillShowNotification, notification => {
78+
var info = notification.UserInfo;
79+
var kbFrame = (NSValue)info [UIKeyboard.FrameEndUserInfoKey];
80+
var kbDuration = (NSNumber)info [UIKeyboard.AnimationDurationUserInfoKey];
81+
var animationDuration = kbDuration.DoubleValue;
82+
var keyboardFrame = kbFrame.CGRectValue;
83+
84+
nfloat height = keyboardFrame.Size.Height + 8;
85+
86+
entryTextBottom.Constant = height;
87+
sendButtonBottom.Constant = height;
88+
89+
UIView.Animate (animationDuration, () => View.LayoutIfNeeded ());
90+
});
91+
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillHideNotification, notification => {
92+
var info = notification.UserInfo;
93+
var kbDuration = (NSNumber)info [UIKeyboard.AnimationDurationUserInfoKey];
94+
var animationDuration = kbDuration.DoubleValue;
95+
96+
entryTextBottom.Constant = 8;
97+
sendButtonBottom.Constant = 8;
98+
99+
UIView.Animate (animationDuration, () => View.LayoutIfNeeded ());
100+
});
101+
}
102+
103+
public override void PrepareForSegue (UIStoryboardSegue segue, Foundation.NSObject sender)
104+
{
105+
if (segue.Identifier == "chatWindow") {
106+
var tvc = segue.DestinationViewController as UITableViewController;
107+
chatWindow = tvc.TableView;
108+
chatWindow.Delegate = adapter;
109+
chatWindow.DataSource = adapter;
110+
}
111+
112+
base.PrepareForSegue (segue, sender);
113+
}
114+
115+
private void AttachSocketEvents (UIAlertView alert)
116+
{
117+
// Whenever the server emits "login", log the login message
118+
socket.On ("login", data => {
119+
if (alert != null) {
120+
InvokeOnMainThread (() => alert.DismissWithClickedButtonIndex (0, true));
121+
alert = null;
122+
}
123+
124+
var d = Data.FromData (data);
125+
connected = true;
126+
// Display the welcome message
127+
AddMessage ("Welcome to Socket.IO Chat – ", true);
128+
AddParticipantsMessage (d.numUsers);
129+
});
130+
// Whenever the server emits "new message", update the chat body
131+
socket.On ("new message", data => {
132+
var d = Data.FromData (data);
133+
AddMessage (d.message, username: d.username);
134+
});
135+
// Whenever the server emits "user joined", log it in the chat body
136+
socket.On ("user joined", data => {
137+
var d = Data.FromData (data);
138+
AddMessage (d.username + " joined");
139+
AddParticipantsMessage (d.numUsers);
140+
});
141+
// Whenever the server emits "user left", log it in the chat body
142+
socket.On ("user left", data => {
143+
var d = Data.FromData (data);
144+
AddMessage (d.username + " left");
145+
AddParticipantsMessage (d.numUsers);
146+
UpdateChatTyping (d.username, true);
147+
});
148+
// Whenever the server emits "typing", show the typing message
149+
socket.On ("typing", data => {
150+
var d = Data.FromData (data);
151+
UpdateChatTyping (d.username, false);
152+
});
153+
// Whenever the server emits "stop typing", kill the typing message
154+
socket.On ("stop typing", data => {
155+
var d = Data.FromData (data);
156+
UpdateChatTyping (d.username, true);
157+
});
158+
}
159+
160+
private void AddParticipantsMessage (int numUsers)
161+
{
162+
if (numUsers == 1)
163+
AddMessage ("there's 1 participant");
164+
else
165+
AddMessage (string.Format ("there are {0} participants", numUsers));
166+
}
167+
168+
private void SendMessage ()
169+
{
170+
var message = entryText.Text.Trim ();
171+
// if there is a non-empty message and a socket connection
172+
if (!string.IsNullOrEmpty (message) && connected) {
173+
entryText.Text = string.Empty;
174+
AddMessage (message, username: Username);
175+
// tell server to execute "new message" and send along one parameter
176+
socket.Emit ("new message", message);
177+
}
178+
}
179+
180+
private void UpdateChatTyping (string username, bool remove)
181+
{
182+
var updated = false;
183+
if (remove) {
184+
if (typingItems.Contains (username)) {
185+
typingItems.Remove (username);
186+
updated = true;
187+
}
188+
} else {
189+
if (!typingItems.Contains (username)) {
190+
typingItems.Add (username);
191+
updated = true;
192+
}
193+
}
194+
195+
if (updated && typingItems.Count > 0) {
196+
InvokeOnMainThread (() => {
197+
typingText.Hidden = typingItems.Count == 0;
198+
199+
if (typingItems.Count == 1)
200+
typingText.Text = typingItems [0] + " is typing...";
201+
else
202+
typingText.Text = string.Join (", ", typingItems) + " are typing...";
203+
});
204+
}
205+
}
206+
207+
private void AddMessage (string message, bool prepend = false, string username = null)
208+
{
209+
InvokeOnMainThread (() => {
210+
if (prepend)
211+
chatItems.Insert (0, new ChatAdapter.ChatItem (username, message));
212+
else
213+
chatItems.Add (new ChatAdapter.ChatItem (username, message));
214+
215+
chatWindow.ReloadData ();
216+
var lastIndex = NSIndexPath.FromRowSection (chatItems.Count - 1, 0);
217+
chatWindow.ScrollToRow (lastIndex, UITableViewScrollPosition.Bottom, true);
218+
});
219+
}
220+
}
221+
}

Src/SocketIoClientDotNet.Sample.Xamarin-iOS/ChatViewController.designer.cs

Lines changed: 61 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Newtonsoft.Json.Linq;
2+
3+
namespace SocketIoClientDotNet.Sample.XamariniOS
4+
{
5+
public class Data
6+
{
7+
public string username;
8+
public string message;
9+
public int numUsers;
10+
11+
public static Data FromData(object data)
12+
{
13+
var json = data as JToken;
14+
if (json != null)
15+
{
16+
return json.ToObject<Data>();
17+
}
18+
return null;
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)