diff --git a/app/build.gradle b/app/build.gradle
index fbb49f8..eb3e668 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,5 +1,7 @@
plugins {
id 'com.android.application'
+ id 'kotlin-parcelize'
+ id 'kotlin-android'
}
android {
@@ -21,20 +23,25 @@ android {
}
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
namespace 'com.xinbida.wukongdemo'
+ kotlinOptions {
+ jvmTarget = '17'
+ }
}
dependencies {
implementation project(':wkim')
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'com.google.android.material:material:1.12.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
implementation 'org.jetbrains:annotations:23.0.0'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.7'
implementation 'com.github.li-xiaojun:XPopup:2.9.19'
implementation 'com.github.bigdongdong:ChatView:2.0' //添加依赖
+ implementation('com.github.bumptech.glide:glide:4.16.0') {
+ transitive = true
+ }
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2e76ab3..b3cce65 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,7 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/xinbida/wukongdemo/Const.kt b/app/src/main/java/com/xinbida/wukongdemo/Const.kt
new file mode 100644
index 0000000..36583df
--- /dev/null
+++ b/app/src/main/java/com/xinbida/wukongdemo/Const.kt
@@ -0,0 +1,8 @@
+package com.xinbida.wukongdemo
+
+class Const {
+ companion object {
+ var uid = ""
+ var token = ""
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xinbida/wukongdemo/ConvAdapter.kt b/app/src/main/java/com/xinbida/wukongdemo/ConvAdapter.kt
new file mode 100644
index 0000000..0414623
--- /dev/null
+++ b/app/src/main/java/com/xinbida/wukongdemo/ConvAdapter.kt
@@ -0,0 +1,61 @@
+package com.xinbida.wukongdemo
+
+import android.content.Intent
+import android.util.Log
+import android.view.View
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.xinbida.wukongim.WKIM
+import com.xinbida.wukongim.entity.WKUIConversationMsg
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+class ConvAdapter :
+ BaseQuickAdapter(R.layout.item_conv_layout) {
+ override fun convert(holder: BaseViewHolder, item: WKUIConversationMsg, payloads: List) {
+ super.convert(holder, item, payloads)
+ val msg = payloads[0] as WKUIConversationMsg
+ if (msg.wkChannel != null) {
+ holder.setText(R.id.nameTV,item.wkChannel.channelName)
+ GlideUtil.showAvatarImg(context, msg.wkChannel.avatar, holder.getView(R.id.avatarIV))
+ }
+ if (msg.wkMsg != null && msg.wkMsg.baseContentMsgModel != null) {
+ val content = msg.wkMsg.baseContentMsgModel.displayContent
+ holder.setText(R.id.contentTV, content)
+ }
+ }
+
+ override fun convert(holder: BaseViewHolder, item: WKUIConversationMsg) {
+ if (item.wkMsg != null && item.wkMsg.baseContentMsgModel != null) {
+ val content = item.wkMsg.baseContentMsgModel.displayContent
+ holder.setText(R.id.contentTV, content)
+ }
+ if (item.unreadCount > 0) {
+ holder.setVisible(R.id.countTV, true)
+ holder.setText(R.id.countTV, "${item.unreadCount}")
+ } else {
+ holder.setVisible(R.id.countTV, false)
+ }
+ holder.setText(R.id.timeTV, getShowTime(item.lastMsgTimestamp * 1000L))
+ if (item.wkChannel != null) {
+ holder.setText(R.id.nameTV,item.wkChannel.channelName)
+ GlideUtil.showAvatarImg(context, item.wkChannel.avatar, holder.getView(R.id.avatarIV))
+ } else {
+ WKIM.getInstance().channelManager.fetchChannelInfo(item.channelID, item.channelType)
+ }
+
+ holder.getView(R.id.contentLayout).setOnClickListener {
+ val intent = Intent(context,MainActivity::class.java)
+ intent.putExtra("channel_id",item.channelID)
+ intent.putExtra("channel_type",item.channelType)
+ intent.putExtra("old_order_seq",item.wkMsg.orderSeq)
+ context.startActivity(intent)
+ }
+ }
+
+ private fun getShowTime(timeStamp: Long): String {
+ val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
+ return sdf.format(Date(timeStamp))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xinbida/wukongdemo/ConversationActivity.kt b/app/src/main/java/com/xinbida/wukongdemo/ConversationActivity.kt
new file mode 100644
index 0000000..4268045
--- /dev/null
+++ b/app/src/main/java/com/xinbida/wukongdemo/ConversationActivity.kt
@@ -0,0 +1,158 @@
+package com.xinbida.wukongdemo
+
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.widget.AppCompatImageView
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.lxj.xpopup.XPopup
+import com.xinbida.wukongdemo.Const.Companion.token
+import com.xinbida.wukongim.WKIM
+import com.xinbida.wukongim.entity.WKChannelType
+import com.xinbida.wukongim.message.type.WKConnectStatus
+
+class ConversationActivity : AppCompatActivity() {
+ private lateinit var recyclerView: RecyclerView
+ private lateinit var adapter: ConvAdapter
+ private lateinit var titleTv: TextView
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.act_conv_layout)
+
+
+
+ initView()
+ initListener()
+ initData()
+
+ WKIM.getInstance().isDebug = true
+ // 初始化
+ WKIM.getInstance().init(this, Const.uid, token)
+ // 连接
+ WKIM.getInstance().connectionManager.connection()
+ }
+
+ private fun initView() {
+ titleTv = findViewById(R.id.titleTv)
+ recyclerView = findViewById(R.id.recyclerView)
+ adapter = ConvAdapter()
+ recyclerView.adapter = adapter
+ recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
+ }
+
+ private fun initListener() {
+ // 监听连接状态
+ WKIM.getInstance().connectionManager.addOnConnectionStatusListener(
+ "conv"
+ ) { code, _ ->
+ Log.e("连接撞头", "$code")
+ when (code) {
+ WKConnectStatus.connecting -> {
+ titleTv.setText(R.string.connecting)
+ }
+
+ WKConnectStatus.fail -> {
+ titleTv.setText(R.string.connect_fail)
+ }
+
+ WKConnectStatus.success -> {
+ titleTv.setText(R.string.connect_success)
+ }
+
+ WKConnectStatus.syncMsg -> {
+ titleTv.setText(R.string.connect_syncing)
+ }
+ WKConnectStatus.noNetwork -> {
+ titleTv.setText(R.string.no_net)
+ }
+ WKConnectStatus.syncCompleted -> {
+ titleTv.setText(R.string.connect_success)
+ }
+ }
+ }
+ // 监听刷新频道资料
+ WKIM.getInstance().channelManager.addOnRefreshChannelInfo(
+ "conv"
+ ) { channel, _ ->
+ for (index in adapter.data.indices) {
+ if (adapter.data[index].channelID == channel?.channelID) {
+ adapter.data[index].wkChannel = channel!!
+ if (recyclerView.scrollState == RecyclerView.SCROLL_STATE_IDLE || (!recyclerView.isComputingLayout)) {
+ recyclerView.post {
+ adapter.notifyItemChanged(index, adapter.data[index])
+ }
+ }
+ break
+ }
+ }
+ }
+
+ WKIM.getInstance().conversationManager.addOnRefreshMsgListener(
+ "conv"
+ ) { uiConversationMsg, _ ->
+ var isAdd = true
+ for (index in adapter.data.indices) {
+ if (adapter.data[index].channelID == uiConversationMsg?.channelID) {
+ isAdd = false
+ adapter.data[index].wkMsg = uiConversationMsg?.wkMsg
+ adapter.data[index].lastMsgSeq =
+ uiConversationMsg?.lastMsgSeq!!
+ adapter.data[index].clientMsgNo =
+ uiConversationMsg.clientMsgNo
+ adapter.data[index].unreadCount =
+ uiConversationMsg.unreadCount
+ adapter.data[index].lastMsgTimestamp =
+ uiConversationMsg.lastMsgTimestamp
+ if (recyclerView.scrollState == RecyclerView.SCROLL_STATE_IDLE || (!recyclerView.isComputingLayout)) {
+ adapter.notifyItemChanged(index)
+ }
+ break
+ }
+ }
+ if (isAdd) {
+ adapter.addData(0, uiConversationMsg!!)
+ recyclerView.scrollToPosition(0)
+ }
+ }
+ findViewById(R.id.addIV).setOnClickListener {
+ showInputChannelIDDialog()
+ }
+ }
+
+ private fun initData() {
+ val all = WKIM.getInstance().conversationManager.all
+ all.sortByDescending { it.lastMsgTimestamp }
+ adapter.setList(all)
+ }
+
+ private fun showInputChannelIDDialog() {
+ XPopup.Builder(this).moveUpToKeyboard(true).autoOpenSoftInput(true)
+ .asCustom(UpdateChannelIDView(
+ this, "", WKChannelType.PERSONAL
+ ) { channelID: String, channelType: Byte ->
+ runOnUiThread {
+ val intent = Intent(this, MainActivity::class.java)
+ intent.putExtra("channel_id", channelID)
+ intent.putExtra("channel_type", channelType)
+ startActivity(intent)
+ }
+
+ }).show()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ // 连接
+ WKIM.getInstance().connectionManager.connection()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ WKIM.getInstance().connectionManager.removeOnConnectionStatusListener("conv")
+ WKIM.getInstance().channelManager.removeRefreshChannelInfo("conv")
+ WKIM.getInstance().conversationManager.removeOnRefreshMsgListener("conv")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xinbida/wukongdemo/GlideUtil.kt b/app/src/main/java/com/xinbida/wukongdemo/GlideUtil.kt
new file mode 100644
index 0000000..4dcdc6e
--- /dev/null
+++ b/app/src/main/java/com/xinbida/wukongdemo/GlideUtil.kt
@@ -0,0 +1,36 @@
+package com.xinbida.wukongdemo
+
+import android.app.Activity
+import android.content.Context
+import android.widget.ImageView
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.engine.DiskCacheStrategy
+import com.bumptech.glide.request.RequestOptions
+import java.lang.ref.WeakReference
+
+class GlideUtil {
+ companion object{
+ fun showAvatarImg(mContext: Context?, url: String?, imageView: ImageView?) {
+ if (mContext != null) {
+ val weakReference = WeakReference(mContext)
+ val context = weakReference.get()
+ if (context is Activity) {
+ if (!context.isDestroyed) {
+ Glide.with(context).load(url).dontAnimate()
+ .apply(normalRequestOption())
+ .into(imageView!!)
+ }
+ }
+ }
+ }
+
+
+ private fun normalRequestOption(): RequestOptions {
+ return RequestOptions()
+ .error(R.drawable.default_view_bg)
+ .placeholder(R.drawable.default_view_bg)
+ .diskCacheStrategy(DiskCacheStrategy.ALL)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xinbida/wukongdemo/HttpUtil.java b/app/src/main/java/com/xinbida/wukongdemo/HttpUtil.java
index 027bb2e..e2c2586 100644
--- a/app/src/main/java/com/xinbida/wukongdemo/HttpUtil.java
+++ b/app/src/main/java/com/xinbida/wukongdemo/HttpUtil.java
@@ -2,10 +2,11 @@ package com.xinbida.wukongdemo;
import android.text.TextUtils;
import android.util.Base64;
+import android.util.Log;
-import com.xinbida.wukongim.WKIM;
-import com.xinbida.wukongim.entity.WKMsg;
-import com.xinbida.wukongim.message.type.WKSendMsgResult;
+import com.xinbida.wukongim.entity.WKSyncChannelMsg;
+import com.xinbida.wukongim.entity.WKSyncRecent;
+import com.xinbida.wukongim.utils.WKLoggerUtils;
import org.json.JSONArray;
import org.json.JSONException;
@@ -21,10 +22,11 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Iterator;
public class HttpUtil {
-// public String apiURL = "https://api.githubim.com";
+ // public String apiURL = "https://api.githubim.com";
public String apiURL = "http://175.27.245.108:15001";
private static class HttpUtilTypeClass {
@@ -103,54 +105,34 @@ public class HttpUtil {
}
}
- public void getHistoryMsg(String loginUID, String channelID, byte channelType, final IMsgResult iMsgResult) {
+ public void getHistoryMsg(String loginUID, String channelID, byte channelType, long startSeq, long endSeq, int limit, int pullMode, final IMsgResult iMsgResult) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("login_uid", loginUID);
jsonObject.put("channel_id", channelID);
jsonObject.put("channel_type", channelType);
- jsonObject.put("start_message_seq", 0);
- jsonObject.put("end_message_seq", 0);
- jsonObject.put("limit", 50);
- jsonObject.put("pull_mode", 1);
+ jsonObject.put("start_message_seq", startSeq);
+ jsonObject.put("end_message_seq", endSeq);
+ jsonObject.put("limit", limit);
+ jsonObject.put("pull_mode", pullMode);
} catch (JSONException e) {
throw new RuntimeException(e);
}
post("/channel/messagesync", jsonObject, (code, data) -> {
if (code == 200) {
try {
- List list = new ArrayList<>();
+ WKSyncChannelMsg msg = new WKSyncChannelMsg();
+ msg.messages = new ArrayList<>();
JSONObject resultJson = new JSONObject(data);
JSONArray jsonArray = resultJson.optJSONArray("messages");
if (jsonArray != null) {
for (int i = 0, size = jsonArray.length(); i < size; i++) {
JSONObject msgJson = jsonArray.optJSONObject(i);
- String from_uid = msgJson.optString("from_uid");
- String client_msg_no = msgJson.optString("client_msg_no");
- String channel_id = msgJson.optString("channel_id");
- byte channel_type = (byte) msgJson.optInt("channel_type");
- long timestamp = msgJson.optLong("timestamp");
- String payload = msgJson.optString("payload");
- byte[] b = Base64.decode(payload, Base64.DEFAULT);
- String content = new String(b);
- WKMsg wkMsg = new WKMsg();
- wkMsg.clientMsgNO = client_msg_no;
- wkMsg.fromUID = from_uid;
- wkMsg.channelID = channel_id;
- wkMsg.channelType = channel_type;
- wkMsg.timestamp = timestamp;
- wkMsg.content = content;
- wkMsg.status = WKSendMsgResult.send_success;
- wkMsg.baseContentMsgModel = WKIM.getInstance().getMsgManager().getMsgContentModel(content);
- int itemType = 0;
- if (!TextUtils.isEmpty(from_uid) && from_uid.equals(loginUID)) {
- itemType = 1;
- }
- UIMessageEntity uiMessageEntity = new UIMessageEntity(wkMsg, itemType);
- list.add(uiMessageEntity);
+ WKSyncRecent recent = getWKSyncRecent(msgJson);
+ msg.messages.add(recent);
}
}
- iMsgResult.onResult(list);
+ iMsgResult.onResult(msg);
} catch (JSONException e) {
throw new RuntimeException(e);
}
@@ -158,11 +140,51 @@ public class HttpUtil {
});
}
+ public WKSyncRecent getWKSyncRecent(JSONObject msgJson) {
+ String from_uid = msgJson.optString("from_uid");
+ String client_msg_no = msgJson.optString("client_msg_no");
+ String channel_id = msgJson.optString("channel_id");
+ byte channel_type = (byte) msgJson.optInt("channel_type");
+ long timestamp = msgJson.optLong("timestamp");
+ String payload = msgJson.optString("payload");
+ byte[] b = Base64.decode(payload, Base64.DEFAULT);
+ String content = new String(b);
+ WKSyncRecent recent = new WKSyncRecent();
+ recent.from_uid = from_uid;
+ recent.message_id = msgJson.optString("message_id");
+ recent.message_seq = msgJson.optInt("message_seq");
+ recent.client_msg_no = client_msg_no;
+ recent.channel_id = channel_id;
+ recent.channel_type = channel_type;
+ recent.timestamp = timestamp;
+ if (!TextUtils.isEmpty(content)) {
+ HashMap hashMap = new HashMap<>();
+ JSONObject jsonObject = getJSON(content);
+ if (jsonObject != null) {
+ Iterator keys = jsonObject.keys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ hashMap.put(key, jsonObject.opt(key));
+ }
+ recent.payload = hashMap;
+ }
+ }
+ return recent;
+ }
+
+ public JSONObject getJSON(String test) {
+ try {
+ return new JSONObject(test);
+ } catch (JSONException ex) {
+ return null;
+ }
+ }
+
public interface IResult {
void onResult(int code, String data);
}
public interface IMsgResult {
- void onResult(List list);
+ void onResult(WKSyncChannelMsg msg);
}
}
diff --git a/app/src/main/java/com/xinbida/wukongdemo/LoginActivity.java b/app/src/main/java/com/xinbida/wukongdemo/LoginActivity.java
index 1b32365..372d4f9 100644
--- a/app/src/main/java/com/xinbida/wukongdemo/LoginActivity.java
+++ b/app/src/main/java/com/xinbida/wukongdemo/LoginActivity.java
@@ -49,11 +49,18 @@ public class LoginActivity extends AppCompatActivity {
}
new Thread(() -> HttpUtil.getInstance().post("/user/token", jsonObject, (code, data) -> {
if (code == 200) {
- Intent intent = new Intent(LoginActivity.this, MainActivity.class);
- intent.putExtra("uid", uid);
- intent.putExtra("token", token);
- startActivity(intent);
- finish();
+ runOnUiThread(()->{
+ Const.Companion.setToken(token);
+ Const.Companion.setUid(uid);
+ Intent intent = new Intent(LoginActivity.this, ConversationActivity.class);
+
+// Intent intent = new Intent(LoginActivity.this, MainActivity.class);
+// intent.putExtra("uid", uid);
+// intent.putExtra("token", token);
+ startActivity(intent);
+ finish();
+ });
+
} else {
runOnUiThread(() -> Toast.makeText(LoginActivity.this, "登录失败【" + code + "】", Toast.LENGTH_SHORT).show());
}
diff --git a/app/src/main/java/com/xinbida/wukongdemo/MainActivity.java b/app/src/main/java/com/xinbida/wukongdemo/MainActivity.java
index 502edb1..4c503c6 100644
--- a/app/src/main/java/com/xinbida/wukongdemo/MainActivity.java
+++ b/app/src/main/java/com/xinbida/wukongdemo/MainActivity.java
@@ -1,6 +1,7 @@
package com.xinbida.wukongdemo;
-import android.content.Context;
+import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
+
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
@@ -8,23 +9,22 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.lxj.xpopup.XPopup;
import com.xinbida.wukongim.WKIM;
import com.xinbida.wukongim.entity.WKChannel;
import com.xinbida.wukongim.entity.WKChannelType;
import com.xinbida.wukongim.entity.WKMsg;
+import com.xinbida.wukongim.interfaces.IGetOrSyncHistoryMsgBack;
import com.xinbida.wukongim.message.type.WKConnectStatus;
import com.xinbida.wukongim.msgmodel.WKTextContent;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import java.util.ArrayList;
+import java.util.List;
public class MainActivity extends AppCompatActivity {
@@ -34,33 +34,61 @@ public class MainActivity extends AppCompatActivity {
private View statusIv;
private String channelID;
private byte channelType;
- private TextView inputChannelIDTV;
private EditText contentEt;
- private String loginUID;
+ private boolean isLoading; // 是否加载历史中
+ private boolean isCanMore; // 是否能加载更多
+ private boolean isCanRefresh = true; // 是否能刷新
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ channelID = getIntent().getStringExtra("channel_id");
+ channelType = getIntent().getByteExtra("channel_type", WKChannelType.PERSONAL);
recyclerView = findViewById(R.id.recycleView);
statusTv = findViewById(R.id.connectionTv);
statusIv = findViewById(R.id.connectionIv);
- inputChannelIDTV = findViewById(R.id.inputChannelIDTV);
contentEt = findViewById(R.id.contentEt);
- loginUID = getIntent().getStringExtra("uid");
- String token = getIntent().getStringExtra("token");
- channelType = WKChannelType.PERSONAL;
adapter = new MessageAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
recyclerView.setAdapter(adapter);
onListener();
- WKIM.getInstance().setDebug(true);
- WKIM.getInstance().init(MainActivity.this, loginUID, token);
+ long orderSeq = getIntent().getLongExtra("old_order_seq", 0);
+ getData(orderSeq, 0, true,true);
+ }
+
+ private void refresh() {
+ if (isLoading) {
+ return;
+ }
+ long orderSeq = adapter.getData().get(0).msg.orderSeq;
+ getData(orderSeq, 0, false,false);
+ }
+
+ private void more() {
+ if (isLoading) {
+ return;
+ }
+ long orderSeq = adapter.getData().get(adapter.getData().size() - 1).msg.orderSeq;
+ getData(orderSeq, 1, false,false);
}
void onListener() {
- inputChannelIDTV.setOnClickListener(v -> showInputChannelIDDialog(MainActivity.this));
-
+ recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ if (newState == SCROLL_STATE_IDLE) {
+ if (!recyclerView.canScrollVertically(1)) { // 到达底部
+ more();
+ } else if (!recyclerView.canScrollVertically(-1)) { // 到达顶部
+ if (isCanRefresh) {
+ refresh();
+ }
+ }
+ }
+ }
+ });
findViewById(R.id.sendBtn).setOnClickListener(v -> {
String content = contentEt.getText().toString();
if (TextUtils.isEmpty(channelID)) {
@@ -71,18 +99,10 @@ public class MainActivity extends AppCompatActivity {
Toast.makeText(this, getString(R.string.input_content), Toast.LENGTH_SHORT).show();
return;
}
-
- WKIM.getInstance().getMsgManager().send(new WKTextContent(content), new WKChannel(channelID,channelType));
+ WKIM.getInstance().getMsgManager().send(new WKTextContent(content), new WKChannel(channelID, channelType));
contentEt.setText("");
});
- adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
- @Override
- public void onItemRangeInserted(int positionStart, int itemCount) {
- super.onItemRangeInserted(positionStart, itemCount);
- recyclerView.scrollToPosition(adapter.getData().size() - 1);
- }
- });
// 连接状态监听
WKIM.getInstance().getConnectionManager().addOnConnectionStatusListener("main_act", (code, reason) -> {
if (code == WKConnectStatus.success) {
@@ -114,7 +134,10 @@ public class MainActivity extends AppCompatActivity {
}
});
// 监听发送消息入库返回
- WKIM.getInstance().getMsgManager().addOnSendMsgCallback("insert_msg", msg -> adapter.addData(new UIMessageEntity(msg, 1)));
+ WKIM.getInstance().getMsgManager().addOnSendMsgCallback("insert_msg", msg ->{
+ adapter.addData(new UIMessageEntity(msg, 1));
+ recyclerView.scrollToPosition(adapter.getData().size() - 1);
+ } );
// 发送消息回执
WKIM.getInstance().getMsgManager().addOnSendMsgAckListener("ack_key", msg -> {
for (int i = 0, size = adapter.getData().size(); i < size; i++) {
@@ -125,18 +148,7 @@ public class MainActivity extends AppCompatActivity {
}
}
});
- WKIM.getInstance().getConnectionManager().addOnGetIpAndPortListener(andPortListener -> new Thread(() -> HttpUtil.getInstance().get("/route", (code, data) -> {
- if (code == 200) {
- try {
- JSONObject jsonObject = new JSONObject(data);
- String tcp_addr = jsonObject.optString("tcp_addr");
- String[] strings = tcp_addr.split(":");
- andPortListener.onGetSocketIpAndPort(strings[0], Integer.parseInt(strings[1]));
- } catch (JSONException e) {
- throw new RuntimeException(e);
- }
- }
- })).start());
+
}
@Override
@@ -152,6 +164,47 @@ public class MainActivity extends AppCompatActivity {
WKIM.getInstance().getConnectionManager().connection();
}
+ private void getData(long oldOrderSeq, int pullMode, boolean contain,boolean isResetData) {
+ WKIM.getInstance().getMsgManager().getOrSyncHistoryMessages(channelID, channelType, oldOrderSeq, contain, pullMode, 20, 0, new IGetOrSyncHistoryMsgBack() {
+
+ @Override
+ public void onSyncing() {
+
+ }
+
+ @Override
+ public void onResult(List msgList) {
+
+ if (msgList.isEmpty()) {
+ if (pullMode == 0) {
+ isCanRefresh = false;
+ }
+ return;
+ }
+ ArrayList list = new ArrayList<>();
+ for (int i = 0, size = msgList.size(); i < size; i++) {
+ int itemType;
+ if (msgList.get(i).fromUID.equals(Const.Companion.getUid())) {
+ itemType = 1;
+ } else {
+ itemType = 0;
+ }
+ UIMessageEntity entity = new UIMessageEntity(msgList.get(i), itemType);
+ list.add(entity);
+ }
+ if (pullMode == 1) {
+ adapter.addData(list);
+ } else {
+ adapter.addData(0, list);
+ }
+ isLoading = false;
+ if (isResetData) {
+ recyclerView.scrollToPosition(adapter.getData().size() - 1);
+ }
+ }
+ });
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
@@ -164,28 +217,4 @@ public class MainActivity extends AppCompatActivity {
WKIM.getInstance().getConnectionManager().removeOnConnectionStatusListener("main_act");
}
- public void showInputChannelIDDialog(Context context) {
- new XPopup.Builder(context).moveUpToKeyboard(true).autoOpenSoftInput(true).asCustom(new UpdateChannelIDView(context, loginUID, channelType, (channelID, channelType) -> {
- runOnUiThread(() -> {
- MainActivity.this.channelType = channelType;
- MainActivity.this.channelID = channelID;
- String chat = getString(R.string.personal_chat);
- if (channelType == WKChannelType.GROUP) {
- chat = getString(R.string.group_chat);
- }
- inputChannelIDTV.setText(chat + "【" + channelID + "】");
- });
- new Thread(() -> HttpUtil.getInstance().getHistoryMsg(loginUID, channelID, channelType, list -> {
- if (list != null && list.size() > 0) {
- runOnUiThread(() -> {
- adapter.setList(list);
- recyclerView.scrollToPosition(adapter.getData().size() - 1);
- });
- } else {
- adapter.setList(new ArrayList<>());
- }
- })).start();
- })).show();
- }
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xinbida/wukongdemo/UIMessageEntity.java b/app/src/main/java/com/xinbida/wukongdemo/UIMessageEntity.java
index d4bbab1..ba1ac4b 100644
--- a/app/src/main/java/com/xinbida/wukongdemo/UIMessageEntity.java
+++ b/app/src/main/java/com/xinbida/wukongdemo/UIMessageEntity.java
@@ -5,7 +5,7 @@ import com.xinbida.wukongim.entity.WKMsg;
class UIMessageEntity implements MultiItemEntity {
public WKMsg msg;
- public int itemType = 1;
+ public int itemType;
UIMessageEntity(WKMsg msg, int itemType) {
this.itemType = itemType;
diff --git a/app/src/main/java/com/xinbida/wukongdemo/WKApplication.kt b/app/src/main/java/com/xinbida/wukongdemo/WKApplication.kt
new file mode 100644
index 0000000..99e627c
--- /dev/null
+++ b/app/src/main/java/com/xinbida/wukongdemo/WKApplication.kt
@@ -0,0 +1,156 @@
+package com.xinbida.wukongdemo
+
+import android.app.Application
+import android.text.TextUtils
+import com.xinbida.wukongim.WKIM
+import com.xinbida.wukongim.entity.WKChannel
+import com.xinbida.wukongim.entity.WKChannelType
+import com.xinbida.wukongim.entity.WKSyncChat
+import com.xinbida.wukongim.entity.WKSyncConvMsg
+import com.xinbida.wukongim.entity.WKSyncRecent
+import com.xinbida.wukongim.interfaces.IGetSocketIpAndPortListener
+import com.xinbida.wukongim.interfaces.ISyncConversationChatBack
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import kotlin.math.abs
+
+class WKApplication : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+ initListener()
+ }
+
+
+ private val avatars = arrayOf(
+ "https://lmg.jj20.com/up/allimg/tx29/06052048151752929.png",
+ "https://pic.imeitou.com/uploads/allimg/2021061715/aqg1wx3nsds.jpg",
+ "https://lmg.jj20.com/up/allimg/tx30/10121138219844229.jpg",
+ "https://lmg.jj20.com/up/allimg/tx30/10121138219844229.jpg",
+ "https://lmg.jj20.com/up/allimg/tx28/430423183653303.jpg",
+ "https://lmg.jj20.com/up/allimg/tx23/520420024834916.jpg",
+ "https://himg.bdimg.com/sys/portraitn/item/public.1.a535a65d.tJe8MgWmP8zJ456B73Kzfg",
+ "https://img2.baidu.com/it/u=3324164588,1070151830&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500",
+ "https://img1.baidu.com/it/u=3916753633,2634890492&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=400",
+ "https://img0.baidu.com/it/u=4210586523,443489101&fm=253&fmt=auto&app=138&f=JPEG?w=304&h=304",
+ "https://img2.baidu.com/it/u=2559320899,1546883787&fm=253&fmt=auto&app=138&f=JPEG?w=441&h=499",
+ "https://img0.baidu.com/it/u=2952429745,3806929819&fm=253&fmt=auto&app=138&f=JPEG?w=380&h=380",
+ "https://img2.baidu.com/it/u=3783923022,668713258&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
+ )
+
+ private fun initListener() {
+ // 连接地址
+ WKIM.getInstance().connectionManager.addOnGetIpAndPortListener { andPortListener: IGetSocketIpAndPortListener ->
+ Thread {
+ HttpUtil.getInstance()["/route", { code: Int, data: String? ->
+ if (code == 200 && !TextUtils.isEmpty(data)) {
+ try {
+ val jsonObject = JSONObject(data)
+ val tcp_addr = jsonObject.optString("tcp_addr")
+ val strings =
+ tcp_addr.split(":".toRegex()).dropLastWhile { it.isEmpty() }
+ .toTypedArray()
+ andPortListener.onGetSocketIpAndPort(
+ strings[0],
+ strings[1].toInt()
+ )
+ } catch (e: JSONException) {
+ throw RuntimeException(e)
+ }
+ }
+ }]
+ }.start()
+ }
+ // 对接频道资料(群信息/用户信息)
+ WKIM.getInstance().channelManager.addOnGetChannelInfoListener { channelId, channelType, _ ->
+ val channel = WKChannel(channelId, channelType)
+ if (channelType == WKChannelType.PERSONAL) {
+ channel.channelName = "单聊${channelId.hashCode()}"
+ } else {
+ channel.channelName = "群聊${channelId.hashCode()}"
+ }
+ val index = (channelId.hashCode()) % (avatars.size )
+ channel.avatar = avatars[abs(index)]
+ // channel.avatar ="https://api.multiavatar.com/${channel.channelID}.png"
+ WKIM.getInstance().channelManager.saveOrUpdateChannel(channel)
+ null
+ }
+
+ // 对接离线最近会话
+ WKIM.getInstance().conversationManager.addOnSyncConversationListener { lastMsgSeqs, msgCount, version, iSyncConvChatBack ->
+ syncConv(
+ lastMsgSeqs,
+ msgCount,
+ version,
+ iSyncConvChatBack
+ )
+ }
+
+ // 对接频道消息
+ WKIM.getInstance().msgManager.addOnSyncChannelMsgListener { channelID, channelType, startMessageSeq, endMessageSeq, limit, pullMode, iSyncChannelMsgBack ->
+ Thread {
+ HttpUtil.getInstance().getHistoryMsg(
+ Const.uid,
+ channelID!!,
+ channelType,
+ startMessageSeq,
+ endMessageSeq,
+ limit,
+ pullMode
+ ) { msg -> iSyncChannelMsgBack?.onBack(msg) }
+ }.start()
+ }
+ }
+
+ private fun syncConv(
+ lastMsgSeqs: String?,
+ msgCount: Int,
+ version: Long,
+ iSyncConvChatBack: ISyncConversationChatBack?
+ ) {
+ val json = JSONObject()
+ json.put("uid", Const.uid)
+ json.put("version", version)
+ json.put("last_msg_seqs", lastMsgSeqs)
+ json.put("msg_count", msgCount)
+ Thread {
+ HttpUtil.getInstance().post(
+ "/conversation/sync", json
+ ) { code, data ->
+ if (code != 200 || TextUtils.isEmpty(data)) {
+ iSyncConvChatBack?.onBack(null)
+ }
+ val arr = JSONArray(data!!)
+ val chat = getWKSyncChat(arr)
+ iSyncConvChatBack?.onBack(chat)
+ }
+ }.start()
+ }
+
+ private fun getWKSyncChat(arr: JSONArray): WKSyncChat {
+ val chat = WKSyncChat()
+ chat.conversations = ArrayList()
+ for (i in 0 until arr.length()) {
+ val json = arr.getJSONObject(i)
+ val convMsg = WKSyncConvMsg()
+ convMsg.channel_id = json.optString("channel_id")
+ convMsg.channel_type = json.optInt("channel_type").toByte()
+ convMsg.unread = json.optInt("unread")
+ convMsg.timestamp = json.optLong("timestamp")
+ convMsg.last_msg_seq = json.optLong("last_msg_seq")
+ convMsg.last_client_msg_no = json.optString("last_client_msg_no")
+ convMsg.version = json.optLong("version")
+ val recents: ArrayList = ArrayList()
+ val msgArr = json.optJSONArray("recents")
+ for (j in 0 until msgArr!!.length()) {
+ val msgJson = msgArr.getJSONObject(j)
+ val recent = HttpUtil.getInstance().getWKSyncRecent(msgJson)
+ recents.add(recent)
+ convMsg.recents = recents
+ }
+ chat.conversations.add(convMsg)
+ }
+ return chat
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/default_view_bg.xml b/app/src/main/res/drawable/default_view_bg.xml
new file mode 100644
index 0000000..57295d5
--- /dev/null
+++ b/app/src/main/res/drawable/default_view_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/act_conv_layout.xml b/app/src/main/res/layout/act_conv_layout.xml
new file mode 100644
index 0000000..073142e
--- /dev/null
+++ b/app/src/main/res/layout/act_conv_layout.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index da7c0c7..bf993a7 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -17,7 +17,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
-
android:layout_weight="1"
android:gravity="center|start">
@@ -38,16 +37,11 @@
android:textStyle="bold" />
-
+ android:src="@mipmap/menu_add" />
+ android:text="@string/send" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_conv_layout.xml b/app/src/main/res/layout/item_conv_layout.xml
new file mode 100644
index 0000000..73899c9
--- /dev/null
+++ b/app/src/main/res/layout/item_conv_layout.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/menu_add.png b/app/src/main/res/mipmap-hdpi/menu_add.png
new file mode 100644
index 0000000..d99f762
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/menu_add.png differ
diff --git a/app/src/main/res/mipmap-mdpi/menu_add.png b/app/src/main/res/mipmap-mdpi/menu_add.png
new file mode 100644
index 0000000..ad20fd0
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/menu_add.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/menu_add.png b/app/src/main/res/mipmap-xhdpi/menu_add.png
new file mode 100644
index 0000000..1c2bd25
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/menu_add.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/menu_add.png b/app/src/main/res/mipmap-xxhdpi/menu_add.png
new file mode 100644
index 0000000..2fdad2d
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/menu_add.png differ
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index 48a7aa1..3177d91 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -6,10 +6,13 @@
Input chat id
Input group id
Input uid
- connect success
- connect failed
- connection…
+ Connect success
+ Connect failed
+ Connection…
+ Sync…
No network
Kicked
Input content
+ Send
+ Input…
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 07fe188..b3e0865 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -9,7 +9,10 @@
连接成功
连接失败
连接中…
+ 同步中…
无网络
被踢
请输入聊天内容
+ 发送
+ 请输入内容
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 153aed5..66d255b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,14 +1,14 @@
import org.gradle.internal.jvm.Jvm
buildscript {
- ext.kotlin_version = '1.8.0'
+ ext.kotlin_version = '1.9.20'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.5.2'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20"
}
}
diff --git a/wkim/src/main/java/com/xinbida/wukongim/manager/MsgManager.java b/wkim/src/main/java/com/xinbida/wukongim/manager/MsgManager.java
index 6d557c1..36b4f50 100644
--- a/wkim/src/main/java/com/xinbida/wukongim/manager/MsgManager.java
+++ b/wkim/src/main/java/com/xinbida/wukongim/manager/MsgManager.java
@@ -1,6 +1,7 @@
package com.xinbida.wukongim.manager;
import android.text.TextUtils;
+import android.util.Log;
import androidx.annotation.NonNull;