mirror of
https://github.com/WuKongIM/WuKongIMAndroidSDK
synced 2025-06-06 09:08:33 +00:00
fix:update example
This commit is contained in:
parent
2498c0fca1
commit
954751d2f0
@ -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
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<application
|
||||
android:name=".WKApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_logo"
|
||||
android:label="@string/app_name"
|
||||
@ -23,6 +24,7 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".MainActivity" />
|
||||
<activity android:name="com.xinbida.wukongdemo.ConversationActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
8
app/src/main/java/com/xinbida/wukongdemo/Const.kt
Normal file
8
app/src/main/java/com/xinbida/wukongdemo/Const.kt
Normal file
@ -0,0 +1,8 @@
|
||||
package com.xinbida.wukongdemo
|
||||
|
||||
class Const {
|
||||
companion object {
|
||||
var uid = ""
|
||||
var token = ""
|
||||
}
|
||||
}
|
61
app/src/main/java/com/xinbida/wukongdemo/ConvAdapter.kt
Normal file
61
app/src/main/java/com/xinbida/wukongdemo/ConvAdapter.kt
Normal file
@ -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<WKUIConversationMsg, BaseViewHolder>(R.layout.item_conv_layout) {
|
||||
override fun convert(holder: BaseViewHolder, item: WKUIConversationMsg, payloads: List<Any>) {
|
||||
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<View>(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))
|
||||
}
|
||||
}
|
158
app/src/main/java/com/xinbida/wukongdemo/ConversationActivity.kt
Normal file
158
app/src/main/java/com/xinbida/wukongdemo/ConversationActivity.kt
Normal file
@ -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<AppCompatImageView>(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")
|
||||
}
|
||||
}
|
36
app/src/main/java/com/xinbida/wukongdemo/GlideUtil.kt
Normal file
36
app/src/main/java/com/xinbida/wukongdemo/GlideUtil.kt
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<UIMessageEntity> 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<String, Object> hashMap = new HashMap<>();
|
||||
JSONObject jsonObject = getJSON(content);
|
||||
if (jsonObject != null) {
|
||||
Iterator<String> 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<UIMessageEntity> list);
|
||||
void onResult(WKSyncChannelMsg msg);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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<WKMsg> msgList) {
|
||||
|
||||
if (msgList.isEmpty()) {
|
||||
if (pullMode == 0) {
|
||||
isCanRefresh = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
ArrayList<UIMessageEntity> 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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
156
app/src/main/java/com/xinbida/wukongdemo/WKApplication.kt
Normal file
156
app/src/main/java/com/xinbida/wukongdemo/WKApplication.kt
Normal file
@ -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<WKSyncConvMsg>()
|
||||
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<WKSyncRecent> = 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
|
||||
}
|
||||
}
|
10
app/src/main/res/drawable/default_view_bg.xml
Normal file
10
app/src/main/res/drawable/default_view_bg.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 背景色 -->
|
||||
<solid android:color="#eeeeee" />
|
||||
<!-- 边框色 -->
|
||||
<stroke
|
||||
android:width="0dip"
|
||||
android:color="#eeeeee" />
|
||||
<corners android:radius="0dp" />
|
||||
</shape>
|
38
app/src/main/res/layout/act_conv_layout.xml
Normal file
38
app/src/main/res/layout/act_conv_layout.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@color/purple_500">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/titleTv"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|start"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/addIV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|end"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:src="@mipmap/menu_add" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
@ -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" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/inputChannelIDTV"
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/addIV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginStart="20dp"
|
||||
android:hint="@string/input_uid"
|
||||
android:textColorHint="@color/error"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="16sp" />
|
||||
android:src="@mipmap/menu_add" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
@ -66,13 +60,13 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:hint="请输入内容..."
|
||||
android:hint="@string/input"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/sendBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="发送" />
|
||||
android:text="@string/send" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
78
app/src/main/res/layout/item_conv_layout.xml
Normal file
78
app/src/main/res/layout/item_conv_layout.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="15dp"
|
||||
android:id="@+id/contentLayout"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingEnd="15dp"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/avatarIV"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@color/purple_200" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nameTV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timeTV"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end"
|
||||
android:textColor="@color/nonet"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/contentTV"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:lines="1"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/countTV"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginStart="10dp"
|
||||
android:gravity="end"
|
||||
android:text="1"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
BIN
app/src/main/res/mipmap-hdpi/menu_add.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/menu_add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 148 B |
BIN
app/src/main/res/mipmap-mdpi/menu_add.png
Normal file
BIN
app/src/main/res/mipmap-mdpi/menu_add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 120 B |
BIN
app/src/main/res/mipmap-xhdpi/menu_add.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/menu_add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 140 B |
BIN
app/src/main/res/mipmap-xxhdpi/menu_add.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/menu_add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 188 B |
@ -6,10 +6,13 @@
|
||||
<string name="input_channel_id">Input chat id</string>
|
||||
<string name="input_group_id">Input group id</string>
|
||||
<string name="input_uid">Input uid</string>
|
||||
<string name="connect_success">connect success</string>
|
||||
<string name="connect_fail">connect failed</string>
|
||||
<string name="connecting">connection…</string>
|
||||
<string name="connect_success">Connect success</string>
|
||||
<string name="connect_fail">Connect failed</string>
|
||||
<string name="connecting">Connection…</string>
|
||||
<string name="connect_syncing">Sync…</string>
|
||||
<string name="no_net">No network</string>
|
||||
<string name="other_device_login">Kicked</string>
|
||||
<string name="input_content">Input content</string>
|
||||
<string name="send">Send</string>
|
||||
<string name="input">Input…</string>
|
||||
</resources>
|
||||
|
@ -9,7 +9,10 @@
|
||||
<string name="connect_success">连接成功</string>
|
||||
<string name="connect_fail">连接失败</string>
|
||||
<string name="connecting">连接中…</string>
|
||||
<string name="connect_syncing">同步中…</string>
|
||||
<string name="no_net">无网络</string>
|
||||
<string name="other_device_login">被踢</string>
|
||||
<string name="input_content">请输入聊天内容</string>
|
||||
<string name="send">发送</string>
|
||||
<string name="input">请输入内容</string>
|
||||
</resources>
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.xinbida.wukongim.manager;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user