Skip to content

Commit 6b6a903

Browse files
Merge pull request #635 from Kommunicate-io/development
Release 2.14.2
2 parents a750ee9 + 6da6143 commit 6b6a903

File tree

8 files changed

+194
-4
lines changed

8 files changed

+194
-4
lines changed

kommunicate/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ android {
1818
compileSdk 34
1919
targetSdkVersion 35
2020
versionCode 1
21-
versionName "2.14.1"
21+
versionName "2.14.2"
2222
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
2323
buildConfigField "String", "KOMMUNICATE_VERSION", "\"" + versionName + "\""
2424
buildConfigField "String", "CHAT_SERVER_URL", '"https://chat.kommunicate.io"'

kommunicate/src/main/java/io/kommunicate/Kommunicate.java

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.kommunicate.devkit.api.notification.MobiComPushReceiver;
2424
import io.kommunicate.devkit.api.people.ChannelInfo;
2525
import io.kommunicate.devkit.broadcast.BroadcastService;
26+
import io.kommunicate.devkit.channel.service.ChannelService;
2627
import io.kommunicate.devkit.contact.database.ContactDatabase;
2728
import io.kommunicate.devkit.exception.KommunicateException;
2829

@@ -290,6 +291,164 @@ public static void setInAppNotification(boolean isEnable) {
290291
KmAppSettingPreferences.setInAppNotificationEnable(isEnable);
291292
}
292293

294+
/**
295+
* Universal function to handle Kommunicate login, conversation building, and launching.
296+
*
297+
* @param context The context from which the chat screen will be launched.
298+
* @param appID Application ID. Required if kmUser is null or kmUser.getApplicationId() is not set.
299+
* @param kmUser KMUser containing user details. If null, a visitor user will be created.
300+
* @param kmConversationBuilder Builder used to create a conversation.
301+
* @param shouldMaintainSession Indicates whether to maintain the session when {@code kmUser} is not provided and a random (visitor) user is used for login.
302+
* @param callback Callback to return success (conversation ID) or failure (error message).
303+
* @throws KmException If an unexpected error occurs during initialization or conversation launch.
304+
*/
305+
public static void launchConversationWithUser(
306+
@NotNull Context context,
307+
final String appID,
308+
final KMUser kmUser,
309+
final KmConversationBuilder kmConversationBuilder,
310+
final Boolean shouldMaintainSession,
311+
final KmCallback callback
312+
) throws KmException {
313+
314+
if (callback == null) {
315+
throw new IllegalArgumentException("Callback cannot be null.");
316+
}
317+
318+
final boolean isVisitorUser = (kmUser == null);
319+
320+
// Resolve and validate application ID
321+
String resolvedAppId = resolveAppId(appID, kmUser);
322+
if (resolvedAppId == null || resolvedAppId.isEmpty()) {
323+
callback.onFailure("APP_ID_IS_MISSING");
324+
return;
325+
}
326+
327+
boolean isAppIdSame = initializeKommunicate(context, resolvedAppId);
328+
329+
final KmConversationBuilder conversationBuilder =
330+
(kmConversationBuilder != null) ? kmConversationBuilder : new KmConversationBuilder(context);
331+
332+
// Define post-login action
333+
Runnable proceedAfterLogin = () ->
334+
conversationBuilder.setContext(context).createConversation(new KmCallback() {
335+
@Override
336+
public void onSuccess(Object message) {
337+
openConversationUI(context, message, callback);
338+
}
339+
340+
@Override
341+
public void onFailure(Object error) {
342+
callback.onFailure("CONVERSATION_BUILDING_FAILED: " + error);
343+
}
344+
});
345+
346+
// Login logic
347+
Runnable loginAndProceed = () -> loginUser(context, kmUser, isVisitorUser, proceedAfterLogin, callback);
348+
349+
// Check current login state
350+
try {
351+
String loggedInUserId = ChannelService.getInstance(context).getLoggedInUserId();
352+
String inputUserId = (kmUser != null) ? kmUser.getUserId() : null;
353+
354+
boolean isSameUser = inputUserId != null && inputUserId.equals(loggedInUserId);
355+
boolean shouldSkipLogin = KMUser.isLoggedIn(context) && isAppIdSame && (isSameUser || (isVisitorUser && shouldMaintainSession));
356+
357+
if (shouldSkipLogin) {
358+
proceedAfterLogin.run();
359+
} else {
360+
loginAndProceed.run();
361+
}
362+
} catch (Exception e) {
363+
callback.onFailure("USER_CHECK_FAILED: " + e.getMessage());
364+
}
365+
}
366+
367+
private static void loginUser(Context context, KMUser kmUser, boolean isVisitorUser, Runnable onSuccess, KmCallback callback) {
368+
if (isVisitorUser) {
369+
Kommunicate.loginAsVisitor(context, new KMLoginHandler() {
370+
@Override
371+
public void onSuccess(RegistrationResponse response, Context ctx) {
372+
onSuccess.run();
373+
}
374+
375+
@Override
376+
public void onFailure(RegistrationResponse response, Exception e) {
377+
callback.onFailure("LOGIN_USER_FAILED");
378+
}
379+
});
380+
} else {
381+
try {
382+
Kommunicate.login(context, kmUser, new KMLoginHandler() {
383+
@Override
384+
public void onSuccess(RegistrationResponse response, Context ctx) {
385+
onSuccess.run();
386+
}
387+
388+
@Override
389+
public void onFailure(RegistrationResponse response, Exception e) {
390+
callback.onFailure("LOGIN_USER_FAILED");
391+
}
392+
});
393+
} catch (Exception e) {
394+
callback.onFailure("LOGIN_EXCEPTION: " + e.getMessage());
395+
}
396+
}
397+
}
398+
399+
private static void openConversationUI(Context context, Object message, KmCallback callback) {
400+
try {
401+
int conversationId = Integer.parseInt(String.valueOf(message));
402+
403+
KmConversationHelper.openConversation(context, true, conversationId, new KmCallback() {
404+
@Override
405+
public void onSuccess(Object msg) {
406+
callback.onSuccess(msg);
407+
}
408+
409+
@Override
410+
public void onFailure(Object error) {
411+
callback.onFailure("OPEN_CONVERSATION_FAILED: " + error);
412+
}
413+
});
414+
} catch (NumberFormatException e) {
415+
callback.onFailure("INVALID_CONVERSATION_ID: " + message);
416+
} catch (KmException e) {
417+
callback.onFailure("OPEN_CONVERSATION_EXCEPTION: " + e.getMessage());
418+
}
419+
}
420+
421+
private static String resolveAppId(String appID, KMUser kmUser) {
422+
if (appID != null && !appID.trim().isEmpty()) {
423+
return appID.trim();
424+
}
425+
if (kmUser != null && kmUser.getApplicationId() != null) {
426+
return kmUser.getApplicationId().trim();
427+
}
428+
return null;
429+
}
430+
431+
private static boolean initializeKommunicate(Context context, String applicationID) {
432+
try {
433+
String currentAppKey = KommunicateSettings.getInstance(context).getApplicationKey();
434+
435+
boolean isAppIdChanged = !TextUtils.isEmpty(currentAppKey)
436+
&& !PLACEHOLDER_APP_ID.equals(currentAppKey)
437+
&& !applicationID.equals(currentAppKey);
438+
439+
if (TextUtils.isEmpty(currentAppKey) || PLACEHOLDER_APP_ID.equals(currentAppKey)) {
440+
PrefSettings.getInstance(context).setApplicationKey(applicationID);
441+
}
442+
443+
Kommunicate.init(context, applicationID);
444+
445+
return !isAppIdChanged;
446+
} catch (Exception e) {
447+
Utils.printLog(context, TAG, "Failed to initialize Kommunicate: " + e.getMessage());
448+
return true; // Don't block flow even if init fails
449+
}
450+
}
451+
293452
/**
294453
* To Check the Login status & launch the Pre Chat Lead Collection Screen
295454
*

kommunicate/src/main/java/io/kommunicate/callbacks/KmPluginEventListener.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ public interface KmPluginEventListener {
2020
void onVoiceButtonClick(String action);
2121
void onRatingEmoticonsClick(Integer ratingValue);
2222
void onRateConversationClick();
23+
void onCurrentOpenedConversation(Integer conversationId);
2324
}

kommunicate/src/main/java/io/kommunicate/devkit/api/conversation/Message.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,15 @@ public Message(Parcel in) {
144144
topicId = in.readString();
145145
connected = in.readByte() != 0;
146146
contentType = (short) in.readInt();
147-
metadata = in.readHashMap(String.class.getClassLoader());
147+
int metadataSize = in.readInt();
148+
metadata = new HashMap<>();
149+
for (int i = 0; i < metadataSize; i++) {
150+
String key = in.readString();
151+
String value = in.readString();
152+
if (key != null) {
153+
metadata.put(key, value);
154+
}
155+
}
148156
status = (short) in.readInt();
149157
hidden = in.readByte() != 0;
150158
replyMessage = in.readInt();
@@ -896,7 +904,16 @@ public void writeToParcel(Parcel dest, int flags) {
896904
dest.writeString(topicId);
897905
dest.writeByte((byte) (connected ? 1 : 0));
898906
dest.writeInt(contentType);
899-
dest.writeMap(metadata);
907+
// dest.writeMap(metadata);
908+
if (metadata != null) {
909+
dest.writeInt(metadata.size());
910+
for (Map.Entry<String, String> entry : metadata.entrySet()) {
911+
dest.writeString(entry.getKey());
912+
dest.writeString(entry.getValue());
913+
}
914+
} else {
915+
dest.writeInt(0);
916+
}
900917
dest.writeInt(status);
901918
dest.writeByte((byte) (hidden ? 1 : 0));
902919
dest.writeInt(replyMessage);

kommunicate/src/main/java/io/kommunicate/devkit/broadcast/EventManager.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,12 @@ public void sendOnRateConversationClick() {
231231
kmPluginEventListener.onRateConversationClick();
232232
}
233233
}
234+
235+
public void sendOnCurrentOpenedConversation(Integer conversationID) {
236+
if (kmPluginEventListener != null && conversationID != null) {
237+
kmPluginEventListener.onCurrentOpenedConversation(conversationID);
238+
}
239+
}
234240
private void handleState(Message message) {
235241
if (message != null) {
236242
Bundle bundle = message.getData();

kommunicateui/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ android {
1616
targetSdkVersion 35
1717
minSdkVersion 21
1818
versionCode 1
19-
versionName "2.14.1"
19+
versionName "2.14.2"
2020
buildToolsVersion = '34.0.0'
2121
consumerProguardFiles 'proguard-rules.txt'
2222
vectorDrawables.useSupportLibrary = true

kommunicateui/src/main/java/io/kommunicate/ui/conversation/ConversationUIService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import io.kommunicate.devkit.api.conversation.Message;
3434
import io.kommunicate.devkit.api.conversation.database.MessageDatabaseService;
3535
import io.kommunicate.devkit.broadcast.BroadcastService;
36+
import io.kommunicate.devkit.broadcast.EventManager;
3637
import io.kommunicate.devkit.channel.service.ChannelService;
3738
import io.kommunicate.devkit.contact.AppContactService;
3839
import io.kommunicate.devkit.contact.BaseContactService;
@@ -140,6 +141,7 @@ public ConversationFragment getConversationFragment() {
140141
Integer conversationId = ((ConversationActivity) fragmentActivity).getConversationId();
141142
conversationFragment = getConversationFragment(fragmentActivity, contact, channel, conversationId, null, null, null);
142143
ConversationActivity.addFragment(fragmentActivity, conversationFragment, CONVERSATION_FRAGMENT);
144+
EventManager.getInstance().sendOnCurrentOpenedConversation(conversationId);
143145
}
144146
return conversationFragment;
145147
}
@@ -152,6 +154,7 @@ public void run() {
152154
if (conversationFragment == null) {
153155
conversationFragment = getConversationFragment(fragmentActivity, contact, null, conversationId, searchString, messageSearchString, null);
154156
((MobiComKitActivityInterface) fragmentActivity).addFragment(conversationFragment);
157+
EventManager.getInstance().sendOnCurrentOpenedConversation(conversationId);
155158
} else {
156159
MessageInfoFragment messageInfoFragment = (MessageInfoFragment) UIService.getFragmentByTag(fragmentActivity, ConversationUIService.MESSGAE_INFO_FRAGMENT);
157160
if (messageInfoFragment != null) {
@@ -160,6 +163,7 @@ public void run() {
160163
}
161164
}
162165
conversationFragment.loadConversation(contact, conversationId, messageSearchString);
166+
EventManager.getInstance().sendOnCurrentOpenedConversation(conversationId);
163167
}
164168
}
165169
});
@@ -173,6 +177,7 @@ public void run() {
173177
if (conversationFragment == null) {
174178
conversationFragment = getConversationFragment(fragmentActivity, null, channel, conversationId, searchString, messageSearchString, preFilledMessage);
175179
((MobiComKitActivityInterface) fragmentActivity).addFragment(conversationFragment);
180+
EventManager.getInstance().sendOnCurrentOpenedConversation(conversationId);
176181
} else {
177182
MessageInfoFragment messageInfoFragment = (MessageInfoFragment) UIService.getFragmentByTag(fragmentActivity, ConversationUIService.MESSGAE_INFO_FRAGMENT);
178183
if (messageInfoFragment != null && fragmentActivity.getSupportFragmentManager() != null) {

kommunicateui/src/main/java/io/kommunicate/ui/conversation/activity/ConversationActivity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,7 @@ protected void onCreate(Bundle savedInstanceState) {
464464
conversation = ConversationUIService.getConversationFragment(this, contact, null, currentConversationId, null, null, null);
465465
}
466466
addFragment(this, conversation, ConversationUIService.CONVERSATION_FRAGMENT);
467+
EventManager.getInstance().sendOnCurrentOpenedConversation(currentConversationId);
467468
}
468469
} else {
469470
setSearchListFragment(quickConversationFragment);
@@ -903,6 +904,7 @@ public void run() {
903904
channel = clickedChannel;
904905
conversation = ConversationUIService.getConversationFragment(ConversationActivity.this, null, channel, conversationId, searchString, null, null);
905906
addFragment(ConversationActivity.this, conversation, ConversationUIService.CONVERSATION_FRAGMENT);
907+
EventManager.getInstance().sendOnCurrentOpenedConversation(conversation.getId());
906908
}
907909
});
908910
}

0 commit comments

Comments
 (0)