In my previous post on building a telegram client with react-native (Part 1). I outlined the basic steps in setting up and authenticating your app with Telegram.
In this post, I would be going through the process of displaying the chat list. So let's begin.
Prerequisites
- Setup your project and Authenticated successfully. see post
- A User Interface setup to call the methods required.
In order to display the chat list we would be building upon the Repository Example
Variables
/** This is the client instance created from part 1, which
is used throughout the app. You have the option of
creating a singleton in order to use one instance of
the client or create a static function which returns
the created instance.
But note, the client should not be instantiated more
than once.
**/
private static Client client = null;
Java Method.
/** Limit here is the number of chats to return, do note
telegram also handles the amount of chats to be returned when
appropriate.**/
public void loadChatList(final String limit, Promise promise) {
if (client == null) {
client = Telegram.getClientInstance();
}
/** Here we run a synchronized method to avoid race conditions, situations wherein variables or stores are updated
while being accessed.
Rephrased. Since we are running on a different thread,
we restrict access to the "getMainchatlist" variable while operations are performed on it.
**/
synchronized (ChatHandler.getMainChatList()) {
try {
if (client != null) {
client.send(new TdApi.LoadChats(new TdApi.ChatListMain(), Integer.parseInt(limit) - ChatHandler.getMainChatList().size()), new Client.ResultHandler() {
@Override
public void onResult(TdApi.Object object) throws JSONException {
switch (object.getConstructor()) {
case TdApi.Error.CONSTRUCTOR:
if (((TdApi.Error) object).code == 404) {
synchronized (ChatHandler.getMainChatList()) {
haveFullMainChatList = true;
try {
initChatlist(promise);
} catch (Exception e) {
e.printStackTrace();
promise.reject(e);
}
}
} else if (((TdApi.Error) object).code == 401) { // user unauthorized
Telegram.onAuthorizationStateUpdated(null);
} else {
System.err.println("Receive an error for LoadChats:" + newLine + object);
}
break;
case TdApi.Ok.CONSTRUCTOR:
// chats had already been received through updates, let's retry request
loadChatList(limit, promise);
break;
default:
System.err.println("Receive wrong response from TDLib:" + newLine + object);
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
What the above snippet does in a nutshell is to.
- Check if the client instance is available
- Get the chat-list by calling the TDLIB API "loadchats" with its configurations
- If we receive a 404, this means the chat-list has been processed by TDLIB and then initialize the chat-list.
- In the case of a 401, we restart the authentication process.
Snippet for initialization.
/**
* Handles the conversion to serializable data to be used in react-native
* @throws JSONException
*/
private void initChatlist(Promise promise) throws JSONException {
java.util.Iterator<ChatHandler.OrderedChat> iter = ChatHandler.getMainChatList().iterator();
Gson g = new Gson();
WritableArray params = Arguments.createArray();
DataHandler data = new DataHandler();
for (int i = 0; i < chatLimits && i < ChatHandler.getMainChatList().size(); i++) {
long chatId = iter.next().getChatId();
TdApi.Chat chat = ChatHandler.getChat(chatId);
synchronized (chat) {
JSONObject jo = new JSONObject(g.toJson(chat));
WritableMap wm = data.convertJsonToMap(jo);
params.pushMap(wm);
}
}
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("PopulatedList", params);
}
[Snippet above]
Due to the returned response from TDLIB not being compatible with React-Native, we convert it to JSON with the aid of GSON which is a ggogle library for easy serialization and deserialization of data.
Using the chatId as a key to access each chat, convert it to JSON, store in an array and send back as an event to React-Native
Why we make use of an iterator above is to create a "loopable" sequence as the mainChatlist is made up of a set collection, see below.
private static final NavigableSet<OrderedChat> mainChatList = new TreeSet<>();
Annnnnddddd "OrderedChat"
public static class OrderedChat implements Comparable<OrderedChat> {
final long chatId;
final TdApi.ChatPosition position;
OrderedChat(long chatId, TdApi.ChatPosition position) {
this.chatId = chatId;
this.position = position;
}
public long getChatId() {
return chatId;
}
@Override
public int compareTo(OrderedChat o) {
if (this.position.order != o.position.order) {
return o.position.order < this.position.order ? -1 : 1;
}
if (this.chatId != o.chatId) {
return o.chatId < this.chatId ? -1 : 1;
}
return 0;
}
@Override
public boolean equals(Object obj) {
OrderedChat o = (OrderedChat) obj;
return this.chatId == o.chatId && this.position.order == o.position.order;
}
}
[Snippet Above]
Built upon the repository example, this is done to quote the official page.
The positions of chats in chat lists are managed by TDLib, so the Application only needs to listen to updates that change the chat.positions field, maintain the list of all chats, sorted by the pair (position.order, chat.id) in descending order.
Se'fini und Merci.
External Links
- Twitter: @benny_wayn
- LinkedIn: Ibenge-uforo
- Ongoing Research[5 min]: Social Survey
Top comments (0)