taomenggo init
56
conversationkit-ui/build.gradle.kts
Normal file
@@ -0,0 +1,56 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
* Use of this source code is governed by a MIT license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 33
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
targetSdk = 33
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
buildConfigField("String", "versionName", "\"9.6.2\"")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
isMinifyEnabled = true
|
||||
isJniDebuggable = false;
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
|
||||
sourceSets["main"].res.srcDirs("src/main/res","src/main/res-fun","src/main/res-normal")
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
namespace = "com.netease.yunxin.kit.conversationkit.ui"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
|
||||
api("com.netease.yunxin.kit.chat:chatkit:9.6.2")
|
||||
api("com.netease.yunxin.kit.common:common-ui:1.2.0")
|
||||
api("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21")
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4")
|
||||
implementation("androidx.appcompat:appcompat:1.4.2")
|
||||
implementation("com.google.android.material:material:1.5.0")
|
||||
implementation("androidx.recyclerview:recyclerview:1.2.1")
|
||||
implementation("com.github.bumptech.glide:glide:4.13.1")
|
||||
|
||||
}
|
||||
|
||||
0
conversationkit-ui/consumer-rules.pro
Normal file
21
conversationkit-ui/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.kts.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
34
conversationkit-ui/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.netease.yunxin.kit.conversationkit.ui"
|
||||
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<application>
|
||||
<provider
|
||||
android:name="com.netease.yunxin.kit.corekit.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.xkit-startup"
|
||||
android:exported="false"
|
||||
tools:node="merge">
|
||||
<meta-data
|
||||
android:name="com.netease.yunxin.kit.conversationkit.ui.ConversationUIService"
|
||||
android:value="xkit.startup" />
|
||||
</provider>
|
||||
<activity android:name=".normal.page.ConversationSelectActivity"
|
||||
android:screenOrientation="portrait" android:exported="false"/>
|
||||
<activity android:name=".normal.page.ConversationActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="false"/>
|
||||
<activity android:name=".fun.page.FunConversationActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="false"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_00.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_01.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_02.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_03.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_04.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_05.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_06.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_07.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_08.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_09.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_10.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_11.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_12.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_13.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_14.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_15.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_16.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_17.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_18.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_19.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_20.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_21.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_22.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_23.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_24.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_25.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_26.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_27.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_28.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_29.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_30.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_31.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_32.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_33.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_34.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_35.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_36.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_37.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_38.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_39.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_40.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_41.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_42.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_43.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_44.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_45.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_46.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_47.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_48.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_49.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_50.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_51.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_52.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_53.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_54.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_55.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_56.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_57.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_58.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_59.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_60.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_61.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_62.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_63.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_64.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_65.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_66.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_67.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/default/emoji_68.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_00.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_01.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_02.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_03.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_04.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_05.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_06.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_07.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_08.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_09.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_10.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_11.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_12.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_13.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_14.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_15.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_16.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_17.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_18.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_19.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_20.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_21.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_22.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_23.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_24.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_25.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_26.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_27.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_28.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_29.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_30.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_31.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_32.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_33.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_34.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_35.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_36.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_37.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_38.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/lele/lele_39.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_00.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_01.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_02.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_03.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_04.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_05.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_06.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_07.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_08.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_09.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_10.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_11.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_12.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_13.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_14.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_15.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_16.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_17.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_18.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_19.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_20.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_21.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_22.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_23.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_24.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_25.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_26.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_27.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_28.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_29.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_30.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_31.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_32.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_33.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_34.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_35.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_36.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_37.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_38.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/taotao/taotao_39.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 30 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_00.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_01.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_02.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_03.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_04.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_05.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_06.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_07.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_08.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_09.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_10.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_11.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_12.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_13.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_14.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_15.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_16.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_17.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_18.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_19.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_20.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_21.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_22.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_23.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_24.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_25.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_26.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_27.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_28.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_29.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_30.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_31.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_32.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_33.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_34.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
conversationkit-ui/src/main/assets/emoji/tlt/tlt_gif_35.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
@@ -0,0 +1,160 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.ImageSpan;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.netease.nim.highavailable.LogUtils;
|
||||
import com.netease.nimlib.sdk.msg.attachment.NetCallAttachment;
|
||||
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum;
|
||||
import com.netease.nimlib.sdk.team.constant.TeamFieldEnum;
|
||||
import com.netease.nimlib.sdk.team.model.UpdateTeamAttachment;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.fun.viewholder.EmojiManager;
|
||||
import com.netease.yunxin.kit.corekit.im.model.AttachmentContent;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class ConversationCustom {
|
||||
|
||||
public String customContentText(Context context, ConversationInfo conversationInfo) {
|
||||
if (conversationInfo != null && context != null) {
|
||||
MsgTypeEnum typeEnum = conversationInfo.getMsgType();
|
||||
switch (typeEnum) {
|
||||
case notification:
|
||||
String result = context.getString(R.string.msg_type_notification);
|
||||
if (conversationInfo.getAttachment() instanceof UpdateTeamAttachment) {
|
||||
UpdateTeamAttachment attachment = (UpdateTeamAttachment) conversationInfo.getAttachment();
|
||||
for (Map.Entry<TeamFieldEnum, Object> field : attachment.getUpdatedFields().entrySet()) {
|
||||
if (field.getKey() == TeamFieldEnum.Announcement && !TextUtils.isEmpty(field.getValue().toString())) {
|
||||
result = String.format(context.getString(R.string.msg_type_notification_announcement), field.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
case text:
|
||||
return conversationInfo.getContent();
|
||||
case audio:
|
||||
return context.getString(R.string.msg_type_audio);
|
||||
case video:
|
||||
return context.getString(R.string.msg_type_video);
|
||||
case tip:
|
||||
return context.getString(R.string.msg_type_tip);
|
||||
case image:
|
||||
return context.getString(R.string.msg_type_image);
|
||||
case file:
|
||||
return context.getString(R.string.msg_type_file);
|
||||
case location:
|
||||
return context.getString(R.string.msg_type_location);
|
||||
case nrtc_netcall:
|
||||
NetCallAttachment attachment = (NetCallAttachment) conversationInfo.getAttachment();
|
||||
int type = attachment.getType();
|
||||
if (type == 1) {
|
||||
return context.getString(R.string.msg_type_rtc_audio);
|
||||
} else {
|
||||
return context.getString(R.string.msg_type_rtc_video);
|
||||
}
|
||||
case custom:
|
||||
String resultcustom = conversationInfo.getContent();
|
||||
if (conversationInfo.getAttachment() instanceof AttachmentContent) {
|
||||
resultcustom = ((AttachmentContent) conversationInfo.getAttachment()).getContent();
|
||||
}
|
||||
return TextUtils.isEmpty(resultcustom) ? context.getString(R.string.msg_type_custom) : resultcustom;
|
||||
default:
|
||||
return context.getString(R.string.msg_type_no_tips);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
//处理会话表情
|
||||
public static final float DEF_SCALE = 0.2f;
|
||||
|
||||
|
||||
public static void identifyExpression(Context context, View textView, String message) {
|
||||
if (message != null && textView != null) {
|
||||
SpannableString spannableString =
|
||||
replaceEmoticons(context, message, DEF_SCALE, ImageSpan.ALIGN_BOTTOM);
|
||||
// int color = context.getResources().getColor(R.color.color_007aff);
|
||||
// identifyAitExpression(context, spannableString, color, message);
|
||||
viewSetText(textView, spannableString);
|
||||
}
|
||||
}
|
||||
|
||||
private static void viewSetText(View textView, SpannableString mSpannableString) {
|
||||
if (textView instanceof TextView) {
|
||||
TextView tv = (TextView) textView;
|
||||
tv.setText(mSpannableString);
|
||||
}
|
||||
}
|
||||
|
||||
private static Drawable getEmotDrawable(Context context, String text, float scale) {
|
||||
Drawable drawable = EmojiManager.getDrawable(context, text);
|
||||
|
||||
// scale
|
||||
if (drawable != null) {
|
||||
String assPath = EmojiManager.getDrawablePath(context, text);
|
||||
if (assPath != null && assPath.contains("tlt_gif_")) {
|
||||
LogUtils.i("XXXX","XXXX:"+assPath);
|
||||
int number = Integer.parseInt(assPath.replace("emoji/tlt/tlt_gif_","").replace(".png",""));
|
||||
if(number>14){
|
||||
int width = (int) (drawable.getIntrinsicWidth() * scale / 2.0f);
|
||||
int height = (int) (drawable.getIntrinsicHeight() * scale / 2.0f);
|
||||
drawable.setBounds(0, 0, width, height);
|
||||
}else{
|
||||
int width = (int) (drawable.getIntrinsicWidth() * scale / 3.8f);
|
||||
int height = (int) (drawable.getIntrinsicHeight() * scale / 3.8f);
|
||||
drawable.setBounds(0, 0, width, height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
if (assPath.contains("default")) {
|
||||
scale = 0.6f;
|
||||
}
|
||||
int width = (int) (drawable.getIntrinsicWidth() * scale);
|
||||
int height = (int) (drawable.getIntrinsicHeight() * scale);
|
||||
drawable.setBounds(0, 0, width, height);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return drawable;
|
||||
}
|
||||
|
||||
private static SpannableString replaceEmoticons(
|
||||
Context context, String value, float scale, int align) {
|
||||
if (TextUtils.isEmpty(value)) {
|
||||
value = "";
|
||||
}
|
||||
|
||||
SpannableString mSpannableString = new SpannableString(value);
|
||||
Matcher matcher = EmojiManager.getPattern().matcher(value);
|
||||
while (matcher.find()) {
|
||||
int start = matcher.start();
|
||||
int end = matcher.end();
|
||||
String emot = value.substring(start, end);
|
||||
Drawable d = getEmotDrawable(context, emot, scale);
|
||||
if (d != null) {
|
||||
ImageSpan span = new ImageSpan(d, align);
|
||||
mSpannableString.setSpan(span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
return mSpannableString;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui;
|
||||
|
||||
public class ConversationKitClient {
|
||||
|
||||
private static ConversationUIConfig sConversationConfig;
|
||||
|
||||
public static void setConversationUIConfig(ConversationUIConfig config) {
|
||||
sConversationConfig = config;
|
||||
}
|
||||
|
||||
public static ConversationUIConfig getConversationUIConfig() {
|
||||
return sConversationConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class ConversationUIConfig {
|
||||
|
||||
public static Integer INT_DEFAULT_NULL = 0;
|
||||
public boolean showTitleBar = true;
|
||||
public boolean showTitleBarLeftIcon = true;
|
||||
public boolean showTitleBarRightIcon = true;
|
||||
public boolean showTitleBarRight2Icon = true;
|
||||
|
||||
public Integer titleBarLeftRes = null;
|
||||
public Integer titleBarRightRes = null;
|
||||
public Integer titleBarRight2Res = null;
|
||||
|
||||
public String titleBarTitle;
|
||||
public Integer titleBarTitleColor = null;
|
||||
|
||||
public Integer itemTitleColor = null;
|
||||
public Integer itemTitleSize = null;
|
||||
public Integer itemContentColor = null;
|
||||
public Integer itemContentSize = null;
|
||||
public Integer itemDateColor = null;
|
||||
public Integer itemDateSize = null;
|
||||
|
||||
public View.OnClickListener titleBarRightClick;
|
||||
|
||||
public View.OnClickListener titleBarRight2Click;
|
||||
|
||||
public View.OnClickListener titleBarLeftClick;
|
||||
public ItemClickListener itemClickListener;
|
||||
public Comparator<ConversationInfo> conversationComparator;
|
||||
public IConversationFactory conversationFactory;
|
||||
public Float avatarCornerRadius = null;
|
||||
public Drawable itemStickTopBackground;
|
||||
public Drawable itemBackground;
|
||||
public ConversationCustom conversationCustom;
|
||||
public IConversationViewLayout customLayout;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui;
|
||||
|
||||
public class ConversationUIConstant {
|
||||
public static final int MAX_TEAM_MEMBER = 200;
|
||||
|
||||
public static final int ERROR_CODE_NETWORK = 415;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.netease.yunxin.kit.chatkit.ChatService;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.fun.page.FunConversationActivity;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.normal.page.ConversationActivity;
|
||||
import com.netease.yunxin.kit.corekit.im.utils.RouterConstant;
|
||||
import com.netease.yunxin.kit.corekit.route.XKitRouter;
|
||||
|
||||
public class ConversationUIService extends ChatService {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getServiceName() {
|
||||
return "ConversationUIKit";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getVersionName() {
|
||||
return BuildConfig.versionName;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ChatService create(@NonNull Context context) {
|
||||
//normal
|
||||
XKitRouter.registerRouter(RouterConstant.PATH_CONVERSATION_PAGE, ConversationActivity.class);
|
||||
|
||||
//fun
|
||||
XKitRouter.registerRouter(
|
||||
RouterConstant.PATH_FUN_CONVERSATION_PAGE, FunConversationActivity.class);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
|
||||
public interface IConversationFactory {
|
||||
//根据会话数据,创建ViewHolder中数据类
|
||||
ConversationBean CreateBean(ConversationInfo info);
|
||||
|
||||
//Adapter获取数据对应的ViewType
|
||||
int getItemViewType(ConversationBean data);
|
||||
|
||||
//创建ViewHolder
|
||||
BaseViewHolder<ConversationBean> createViewHolder(@NonNull ViewGroup parent, int viewType);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui;
|
||||
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.ConversationBaseFragment;
|
||||
|
||||
public interface IConversationViewLayout {
|
||||
void customizeConversationLayout(final ConversationBaseFragment fragment);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
|
||||
public interface ItemClickListener {
|
||||
default boolean onClick(Context context, ConversationBean data, int position) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean onLongClick(Context context, ConversationBean data, int position) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean onAvatarClick(Context context, ConversationBean data, int position) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean onAvatarLongClick(Context context, ConversationBean data, int position) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.netease.yunxin.kit.conversationkit.ui;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class TimeConversationUtils {
|
||||
public static String formatMillisecond(Context mcontext, long timeseconds) {
|
||||
String ret = "";
|
||||
Date srcDate = new Date(timeseconds);
|
||||
try {
|
||||
boolean isChineseLanguage = isChineseLanguage();
|
||||
GregorianCalendar gcCurrent = new GregorianCalendar();
|
||||
gcCurrent.setTime(new Date());
|
||||
int currentYear = gcCurrent.get(1);
|
||||
int currentMonth = gcCurrent.get(2) + 1;
|
||||
int currentDay = gcCurrent.get(5);
|
||||
GregorianCalendar gcSrc = new GregorianCalendar();
|
||||
gcSrc.setTime(srcDate);
|
||||
int srcYear = gcSrc.get(1);
|
||||
int srcMonth = gcSrc.get(2) + 1;
|
||||
int srcDay = gcSrc.get(5);
|
||||
String timeExtraStr = "";
|
||||
timeExtraStr = " " + getTimeHH24Human(srcDate, true);
|
||||
if (currentYear == srcYear) {
|
||||
long currentTimestamp = gcCurrent.getTimeInMillis();
|
||||
long srcTimestamp = gcSrc.getTimeInMillis();
|
||||
long delta = currentTimestamp - srcTimestamp;
|
||||
if (currentMonth == srcMonth && currentDay == srcDay) {
|
||||
ret = getTimeHH24Human(srcDate, false);
|
||||
} else {
|
||||
GregorianCalendar yesterdayDate = new GregorianCalendar();
|
||||
yesterdayDate.add(5, -1);
|
||||
GregorianCalendar beforeYesterdayDate = new GregorianCalendar();
|
||||
beforeYesterdayDate.add(5, -2);
|
||||
if (srcMonth == yesterdayDate.get(2) + 1 && srcDay == yesterdayDate.get(5)) {
|
||||
ret = mcontext.getString(R.string.time_zuotian_txt) + timeExtraStr;
|
||||
}
|
||||
//不用前天
|
||||
// else if (srcMonth == beforeYesterdayDate.get(2) + 1 && srcDay == beforeYesterdayDate.get(5)) {
|
||||
// ret = mcontext.getString(R.string.time_qiantian_txt) + timeExtraStr;
|
||||
// }
|
||||
else {
|
||||
long deltaHour = delta / 3600000L;
|
||||
if (deltaHour < 168L) {
|
||||
String[] weekday = new String[]{"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
|
||||
String weedayDesc = weekday[gcSrc.get(7) - 1];
|
||||
ret = weedayDesc;
|
||||
} else {
|
||||
ret = getTimeString(srcDate, isChineseLanguage() ? "M月d日" : "M/d");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ret = getTimeString(srcDate, isChineseLanguage ? "yy年M月d日" : "yy/M/d") + timeExtraStr;
|
||||
ret = getTimeString(srcDate, isChineseLanguage ? "yyyy年M月d日" : "yyyy/M/d");
|
||||
}
|
||||
} catch (Exception var26) {
|
||||
System.err.println("【DEBUG-getTimeStringAutoShort】计算出错:" + var26.getMessage() + " 【NO】");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static String getTimeString(Date dt, String pattern) {
|
||||
try {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
|
||||
sdf.setTimeZone(TimeZone.getDefault());
|
||||
return sdf.format(dt);
|
||||
} catch (Exception var3) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static String getTimeHH24Human(Date srcDate, boolean timeWithSegmentStr) {
|
||||
String ret = "";
|
||||
|
||||
try {
|
||||
String timePattern = "HH:mm";
|
||||
String timeStr = getTimeString(srcDate, timePattern);
|
||||
// String timeSegmentStr = "";
|
||||
// if (timeWithSegmentStr) {
|
||||
// timeSegmentStr = isChineseLanguage() ? getTimeSegmentStr(timeStr) : "";
|
||||
// }
|
||||
// ret = timeSegmentStr + timeStr;
|
||||
|
||||
ret = timeStr;
|
||||
} catch (Exception var6) {
|
||||
System.err.println("【DEBUG-getTimeHH24Human】计算出错:" + var6.getMessage() + " 【NO】");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static boolean isChineseLanguage() {
|
||||
boolean is = true;
|
||||
|
||||
try {
|
||||
is = Locale.getDefault().getLanguage().equals((new Locale("zh")).getLanguage());
|
||||
} catch (Exception var2) {
|
||||
System.err.println("【DEBUG-isChineseLanguage】" + var2.getMessage());
|
||||
}
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
private static String getTimeSegmentStr(String hh24) {
|
||||
String ret = "";
|
||||
if (hh24 != null && hh24.length() >= 2) {
|
||||
try {
|
||||
int a = Integer.parseInt(hh24.substring(0, 2));
|
||||
if (a >= 0 && a <= 6) {
|
||||
ret = "凌晨";
|
||||
} else if (a > 6 && a <= 12) {
|
||||
ret = "上午";
|
||||
} else if (a > 12 && a <= 13) {
|
||||
ret = "中午";
|
||||
} else if (a > 13 && a <= 18) {
|
||||
ret = "下午";
|
||||
} else if (a > 18 && a <= 24) {
|
||||
ret = "晚上";
|
||||
}
|
||||
} catch (Exception var3) {
|
||||
System.err.println("【DEBUG-getTimeSegmentStr】计算出错:" + var3.getMessage() + " 【NO】");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.common;
|
||||
|
||||
public class ConversationConstant {
|
||||
|
||||
public static final String LIB_TAG = "ConversationKit-UI";
|
||||
|
||||
public static class ViewType {
|
||||
//p2p chat view
|
||||
public static final int CHAT_VIEW = 1;
|
||||
//team chat view
|
||||
public static final int TEAM_VIEW = 2;
|
||||
}
|
||||
|
||||
public static class Action {
|
||||
//action to add or remove stick
|
||||
public static final String ACTION_STICK = "conversation/action/stick";
|
||||
//action to delete conversation
|
||||
public static final String ACTION_DELETE = "conversation/action/delete";
|
||||
public static final String ACTION_HIDE = "conversation/action/hide";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ConversationHelper {
|
||||
|
||||
private static Map<String, Boolean> aitInfo = new HashMap<>();
|
||||
|
||||
public static void updateAitInfo(List<String> sessionIdList, boolean hasAit) {
|
||||
if (sessionIdList != null) {
|
||||
for (String sessionId : sessionIdList) {
|
||||
aitInfo.put(sessionId, hasAit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasAit(String sessionId) {
|
||||
if (aitInfo.containsKey(sessionId)) {
|
||||
return aitInfo.get(sessionId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.common;
|
||||
|
||||
import static com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant.LIB_TAG;
|
||||
|
||||
import android.content.Context;
|
||||
import com.netease.nimlib.sdk.msg.attachment.NotificationAttachment;
|
||||
import com.netease.nimlib.sdk.msg.constant.NotificationType;
|
||||
import com.netease.yunxin.kit.alog.ALog;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationCustom;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationKitClient;
|
||||
|
||||
public class ConversationUtils {
|
||||
|
||||
private static final String TAG = "ConversationUtils";
|
||||
|
||||
private static ConversationCustom custom = new ConversationCustom();
|
||||
|
||||
public static boolean isMineLeave(ConversationInfo conversationInfo) {
|
||||
ALog.d(LIB_TAG, TAG, "isMineLeave");
|
||||
if (conversationInfo.getAttachment() instanceof NotificationAttachment) {
|
||||
NotificationAttachment notify = (NotificationAttachment) conversationInfo.getAttachment();
|
||||
ALog.d(LIB_TAG, TAG, "isMineLeave,notificationType=" + notify.getType());
|
||||
if (notify.getType() == NotificationType.DismissTeam) {
|
||||
return true;
|
||||
}
|
||||
return (notify.getType() == NotificationType.KickMember
|
||||
|| notify.getType() == NotificationType.LeaveTeam)
|
||||
&& conversationInfo.getTeamInfo() != null
|
||||
&& !conversationInfo.getTeamInfo().isMyTeam();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getConversationText(Context context, ConversationInfo conversationInfo) {
|
||||
if (ConversationKitClient.getConversationUIConfig() != null
|
||||
&& ConversationKitClient.getConversationUIConfig().conversationCustom != null) {
|
||||
return ConversationKitClient.getConversationUIConfig()
|
||||
.conversationCustom
|
||||
.customContentText(context, conversationInfo);
|
||||
}
|
||||
return custom.customContentText(context, conversationInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.common;
|
||||
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.yunxin.kit.corekit.im.model.FriendInfo;
|
||||
import com.netease.yunxin.kit.corekit.im.model.UserInfo;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DataUtils {
|
||||
|
||||
public static Map<String, UserInfo> getUserInfoMap(List<UserInfo> data) {
|
||||
if (data == null || data.size() < 1) {
|
||||
return null;
|
||||
}
|
||||
Map<String, UserInfo> result = new HashMap<>();
|
||||
for (int index = 0; index < data.size(); index++) {
|
||||
result.put(data.get(index).getAccount(), data.get(index));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Map<String, FriendInfo> getFriendInfoMap(List<FriendInfo> data) {
|
||||
if (data == null || data.size() < 1) {
|
||||
return null;
|
||||
}
|
||||
Map<String, FriendInfo> result = new HashMap<>();
|
||||
for (int index = 0; index < data.size(); index++) {
|
||||
result.put(data.get(index).getAccount(), data.get(index));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Map<String, Team> getTeamInfoMap(List<Team> data) {
|
||||
if (data == null || data.size() < 1) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Team> result = new HashMap<>();
|
||||
for (int index = 0; index < data.size(); index++) {
|
||||
result.put(data.get(index).getId(), data.get(index));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun;
|
||||
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.CHAT_KRY;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_CONTACT_SELECTOR_MAX_COUNT;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_REMOTE_EXTENSION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_REQUEST_SELECTOR_NAME;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_REQUEST_SELECTOR_NAME_ENABLE;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_SESSION_ID;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_TEAM_CREATED_TIP;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_TEAM_ID;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_CHAT_SEND_TEAM_TIP_ACTION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_FUN_ADD_FRIEND_PAGE;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_FUN_CHAT_TEAM_PAGE;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_FUN_CONTACT_SELECTOR_PAGE;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_FUN_CREATE_ADVANCED_TEAM_ACTION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_FUN_CREATE_NORMAL_TEAM_ACTION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_TEAM_INVITE_ACTION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.REQUEST_CONTACT_SELECTOR_KEY;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.netease.nimlib.sdk.team.model.CreateTeamResult;
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.yunxin.kit.alog.ALog;
|
||||
import com.netease.yunxin.kit.common.ui.photo.TransHelper;
|
||||
import com.netease.yunxin.kit.common.ui.widgets.ContentListPopView;
|
||||
import com.netease.yunxin.kit.common.utils.SizeUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.corekit.route.XKitRouter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** pop menu factory */
|
||||
public final class FunPopItemFactory {
|
||||
private static final String TAG = "PopItemFactory";
|
||||
|
||||
public static ContentListPopView.Item getAddFriendItem(Context context) {
|
||||
LinearLayout.LayoutParams params = getParams(context);
|
||||
return new ContentListPopView.Item.Builder()
|
||||
.configView(
|
||||
getView(context, R.string.add_friend, R.drawable.fun_ic_conversation_add_friend))
|
||||
.configParams(params)
|
||||
.configClickListener(
|
||||
v -> XKitRouter.withKey(PATH_FUN_ADD_FRIEND_PAGE).withContext(context).navigate())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ContentListPopView.Item getCreateAdvancedTeamItem(
|
||||
Context context, int memberLimit) {
|
||||
LinearLayout.LayoutParams params = getParams(context);
|
||||
int requestCode = 1;
|
||||
return new ContentListPopView.Item.Builder()
|
||||
.configView(
|
||||
getView(
|
||||
context, R.string.create_advanced_team, R.drawable.fun_ic_conversation_create_team))
|
||||
.configParams(params)
|
||||
.configClickListener(
|
||||
getClickListener(
|
||||
context, requestCode, PATH_FUN_CREATE_ADVANCED_TEAM_ACTION, memberLimit))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ContentListPopView.Item getCreateGroupTeamItem(Context context, int memberLimit) {
|
||||
LinearLayout.LayoutParams params = getParams(context);
|
||||
int requestCode = 2;
|
||||
return new ContentListPopView.Item.Builder()
|
||||
.configView(
|
||||
getView(
|
||||
context, R.string.create_group_team, R.drawable.fun_ic_conversation_create_team))
|
||||
.configParams(params)
|
||||
.configClickListener(
|
||||
getClickListener(context, requestCode, PATH_FUN_CREATE_NORMAL_TEAM_ACTION, memberLimit))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ContentListPopView.Item getDivideLineItem(Context context) {
|
||||
LinearLayout.LayoutParams params =
|
||||
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, SizeUtils.dp2px(0.5f));
|
||||
params.setMargins(SizeUtils.dp2px(42), 0, 0, 0);
|
||||
return new ContentListPopView.Item.Builder()
|
||||
.configView(getDivideView(context))
|
||||
.configParams(params)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static View.OnClickListener getClickListener(
|
||||
Context context, int requestCode, String createMethod, int memberLimit) {
|
||||
return v ->
|
||||
TransHelper.launchTask(
|
||||
context,
|
||||
requestCode,
|
||||
(activity, integer) -> {
|
||||
XKitRouter.withKey(PATH_FUN_CONTACT_SELECTOR_PAGE)
|
||||
.withParam(KEY_CONTACT_SELECTOR_MAX_COUNT, memberLimit)
|
||||
.withParam(KEY_REQUEST_SELECTOR_NAME_ENABLE, true)
|
||||
.withContext(activity)
|
||||
.withRequestCode(integer)
|
||||
.navigate();
|
||||
return null;
|
||||
},
|
||||
intentResultInfo -> {
|
||||
if (intentResultInfo == null
|
||||
|| !intentResultInfo.getSuccess()
|
||||
|| intentResultInfo.getValue() == null) {
|
||||
return null;
|
||||
}
|
||||
Intent data = intentResultInfo.getValue();
|
||||
ArrayList<String> list = data.getStringArrayListExtra(REQUEST_CONTACT_SELECTOR_KEY);
|
||||
if (list == null || list.isEmpty()) {
|
||||
ALog.e(TAG, "no one was chosen.");
|
||||
return null;
|
||||
}
|
||||
XKitRouter.withKey(createMethod)
|
||||
.withParam(
|
||||
KEY_REQUEST_SELECTOR_NAME,
|
||||
data.getStringArrayListExtra(KEY_REQUEST_SELECTOR_NAME))
|
||||
.navigate(
|
||||
res -> {
|
||||
if (res.getSuccess() && res.getValue() instanceof CreateTeamResult) {
|
||||
Team teamInfo = ((CreateTeamResult) res.getValue()).getTeam();
|
||||
Map<String, Object> map = new HashMap<>(1);
|
||||
map.put(
|
||||
KEY_TEAM_CREATED_TIP,
|
||||
context.getString(R.string.create_advanced_team_success));
|
||||
// 发送创建成功群里提示信息
|
||||
XKitRouter.withKey(PATH_CHAT_SEND_TEAM_TIP_ACTION)
|
||||
.withParam(KEY_SESSION_ID, teamInfo.getId())
|
||||
.withParam(KEY_REMOTE_EXTENSION, map)
|
||||
.navigate();
|
||||
|
||||
// 邀请加入群,处理邀请通知早于创建成功同志
|
||||
XKitRouter.withKey(PATH_TEAM_INVITE_ACTION)
|
||||
.withParam(KEY_TEAM_ID, teamInfo.getId())
|
||||
.withParam(REQUEST_CONTACT_SELECTOR_KEY, list)
|
||||
.navigate();
|
||||
|
||||
//跳转到会话页面
|
||||
XKitRouter.withKey(PATH_FUN_CHAT_TEAM_PAGE)
|
||||
.withContext(context)
|
||||
.withParam(CHAT_KRY, teamInfo)
|
||||
.navigate();
|
||||
|
||||
} else {
|
||||
ALog.e(TAG, "create team failed.");
|
||||
}
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private static View getView(Context context, int txtId, int drawableId) {
|
||||
TextView textView = new TextView(context);
|
||||
textView.setGravity(Gravity.CENTER_VERTICAL);
|
||||
textView.setTextSize(16);
|
||||
textView.setMaxLines(1);
|
||||
textView.setText(txtId);
|
||||
|
||||
int marginSize =
|
||||
(int) context.getResources().getDimension(R.dimen.fun_add_pop_item_margin_right_top);
|
||||
int padding = (int) context.getResources().getDimension(R.dimen.fun_add_pop_item_padding);
|
||||
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
|
||||
if (drawable != null) {
|
||||
drawable.setBounds(padding, 0, marginSize + padding, marginSize);
|
||||
textView.setCompoundDrawables(drawable, null, null, null);
|
||||
}
|
||||
textView.setPadding(
|
||||
(int) context.getResources().getDimension(R.dimen.dimen_8_dp),
|
||||
0,
|
||||
(int) context.getResources().getDimension(R.dimen.dimen_14_dp),
|
||||
0);
|
||||
textView.setMinWidth((int) context.getResources().getDimension(R.dimen.fun_add_pop_item_width));
|
||||
textView.setTextColor(
|
||||
context.getResources().getColor(R.color.fun_conversation_add_pop_text_color));
|
||||
textView.setCompoundDrawablePadding(marginSize);
|
||||
return textView;
|
||||
}
|
||||
|
||||
private static View getDivideView(Context context) {
|
||||
View view = new View(context);
|
||||
view.setBackgroundResource(R.color.color_5a5a5a);
|
||||
return view;
|
||||
}
|
||||
|
||||
private static LinearLayout.LayoutParams getParams(Context context) {
|
||||
return new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
(int) context.getResources().getDimension(R.dimen.fun_add_pop_item_height));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.IConversationFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.FunConversationViewHolderBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.fun.viewholder.FunConversationP2PViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.fun.viewholder.FunConversationTeamViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.interfaces.IConverationSelectorListener;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.corekit.im.utils.RouterConstant;
|
||||
|
||||
/**
|
||||
* conversation view holder factory to create view holder in recyclerview
|
||||
*/
|
||||
public class FunViewHolderFactory implements IConversationFactory {
|
||||
|
||||
public boolean isSelector;
|
||||
public boolean isServices = false;
|
||||
public IConverationSelectorListener listener;
|
||||
|
||||
|
||||
public void setSelector(boolean selector) {
|
||||
isSelector = selector;
|
||||
}
|
||||
|
||||
public void setServices(boolean services) {
|
||||
isServices = services;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConversationBean CreateBean(ConversationInfo info) {
|
||||
ConversationBean bean = new ConversationBean(info);
|
||||
if (info.getSessionType() == SessionTypeEnum.P2P) {
|
||||
return new ConversationBean(
|
||||
info,
|
||||
RouterConstant.PATH_FUN_CHAT_P2P_PAGE,
|
||||
ConversationConstant.ViewType.CHAT_VIEW,
|
||||
RouterConstant.CHAT_ID_KRY,
|
||||
info.getContactId());
|
||||
} else if (info.getSessionType() == SessionTypeEnum.Team
|
||||
|| info.getSessionType() == SessionTypeEnum.SUPER_TEAM) {
|
||||
return new ConversationBean(
|
||||
info,
|
||||
RouterConstant.PATH_FUN_CHAT_TEAM_PAGE,
|
||||
ConversationConstant.ViewType.TEAM_VIEW,
|
||||
RouterConstant.CHAT_ID_KRY,
|
||||
info.getContactId());
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(ConversationBean data) {
|
||||
return data.viewType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseViewHolder<ConversationBean> createViewHolder(
|
||||
@NonNull ViewGroup parent, int viewType) {
|
||||
FunConversationViewHolderBinding binding =
|
||||
FunConversationViewHolderBinding.inflate(
|
||||
LayoutInflater.from(parent.getContext()), parent, false);
|
||||
binding.ivSelector.setVisibility(isSelector ? View.VISIBLE : View.GONE);
|
||||
binding.viewSelectorclick.setVisibility(isSelector ? View.VISIBLE : View.GONE);
|
||||
if (viewType == ConversationConstant.ViewType.TEAM_VIEW) {
|
||||
FunConversationTeamViewHolder teamViewHolder = new FunConversationTeamViewHolder(binding);
|
||||
teamViewHolder.setItemSelectorlistener(listener);
|
||||
return teamViewHolder;
|
||||
} else {
|
||||
FunConversationP2PViewHolder p2PViewHolder = new FunConversationP2PViewHolder(binding);
|
||||
p2PViewHolder.setIsServices(isServices);
|
||||
p2PViewHolder.setItemSelectorlistener(listener);
|
||||
return p2PViewHolder;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setOnSelectorClickListener(IConverationSelectorListener selectorClickListener) {
|
||||
this.listener = selectorClickListener;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun.page;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import com.netease.yunxin.kit.common.ui.activities.BaseActivity;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.FunConversationActivityBinding;
|
||||
|
||||
public class FunConversationActivity extends BaseActivity {
|
||||
|
||||
private FunConversationActivityBinding viewBinding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
changeStatusBarColor(R.color.fun_conversation_page_bg_color);
|
||||
viewBinding = FunConversationActivityBinding.inflate(LayoutInflater.from(this));
|
||||
setContentView(viewBinding.getRoot());
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
FunConversationFragment fragment = new FunConversationFragment();
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.add(R.id.conversation_container, fragment)
|
||||
.commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun.page;
|
||||
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.netease.yunxin.kit.common.ui.widgets.TitleBarView;
|
||||
import com.netease.yunxin.kit.common.utils.SizeUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationKitClient;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationUIConfig;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.FunConversationFragmentBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.fun.FunViewHolderFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.interfaces.IConverationSelectorListener;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.ConversationBaseFragment;
|
||||
|
||||
public class FunConversationFragment extends ConversationBaseFragment {
|
||||
|
||||
|
||||
public static FunConversationFragment getInstance(boolean isselector) {
|
||||
FunConversationFragment fragment = new FunConversationFragment();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean("isSelector", isselector);
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
private FunConversationFragmentBinding viewBinding;
|
||||
private boolean needSelector = false;
|
||||
public IConverationSelectorListener converationSelectorListener;
|
||||
|
||||
@Override
|
||||
public View initViewAndGetRootView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
viewBinding = FunConversationFragmentBinding.inflate(inflater, container, false);
|
||||
Bundle bundle = getArguments();
|
||||
if (bundle != null) {
|
||||
needSelector = bundle.getBoolean("isSelector");
|
||||
}
|
||||
initView();
|
||||
return viewBinding.getRoot();
|
||||
}
|
||||
|
||||
public void setOnItemSelectorListener(IConverationSelectorListener onItemSelectorListener) {
|
||||
this.converationSelectorListener = onItemSelectorListener;
|
||||
}
|
||||
|
||||
|
||||
private void initView() {
|
||||
conversationView = viewBinding.conversationView;
|
||||
titleBarView = viewBinding.titleBar;
|
||||
titleBarView.setVisibility(View.GONE);
|
||||
viewBinding.searchLayout.setVisibility(View.GONE);
|
||||
networkErrorView = viewBinding.errorTv;
|
||||
emptyView = viewBinding.emptyLayout;
|
||||
FunViewHolderFactory funViewHolderFactory = new FunViewHolderFactory();
|
||||
funViewHolderFactory.isSelector = needSelector;
|
||||
funViewHolderFactory.setOnSelectorClickListener(converationSelectorListener);
|
||||
setViewHolderFactory(funViewHolderFactory);
|
||||
// viewBinding.conversationView.addItemDecoration(getItemDecoration());
|
||||
// loadUIConfig();
|
||||
}
|
||||
|
||||
public void refreshView() {
|
||||
|
||||
}
|
||||
|
||||
public RecyclerView.ItemDecoration getItemDecoration() {
|
||||
return new RecyclerView.ItemDecoration() {
|
||||
final int topPadding = SizeUtils.dp2px(0.25f);
|
||||
final int indent = SizeUtils.dp2px(76);
|
||||
|
||||
@Override
|
||||
public void onDrawOver(
|
||||
@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||
int left = parent.getPaddingLeft() + indent;
|
||||
int right = parent.getWidth() - parent.getPaddingRight();
|
||||
|
||||
int childCount = parent.getChildCount();
|
||||
for (int i = 0; i < childCount - 1; i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
int top = child.getBottom() + params.bottomMargin;
|
||||
int bottom = top + topPadding;
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setColor(
|
||||
parent.getResources().getColor(R.color.fun_conversation_item_divide_line_color));
|
||||
canvas.drawRect(left, top, right, bottom, paint);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void loadUIConfig() {
|
||||
if (ConversationKitClient.getConversationUIConfig() == null) {
|
||||
return;
|
||||
}
|
||||
ConversationUIConfig config = ConversationKitClient.getConversationUIConfig();
|
||||
|
||||
viewBinding.titleBar.setLeftImageClick(
|
||||
v -> {
|
||||
if (config.titleBarLeftClick != null) {
|
||||
config.titleBarLeftClick.onClick(v);
|
||||
}
|
||||
});
|
||||
|
||||
if (config.conversationComparator != null) {
|
||||
setComparator(config.conversationComparator);
|
||||
}
|
||||
|
||||
if (config.conversationFactory != null) {
|
||||
setViewHolderFactory(config.conversationFactory);
|
||||
}
|
||||
|
||||
if (!config.showTitleBar) {
|
||||
titleBarView.setVisibility(View.GONE);
|
||||
} else {
|
||||
titleBarView.setVisibility(View.VISIBLE);
|
||||
titleBarView.setHeadImageVisible(config.showTitleBarLeftIcon ? View.VISIBLE : View.GONE);
|
||||
titleBarView.showRightImageView(config.showTitleBarRightIcon);
|
||||
|
||||
if (config.titleBarTitle != null) {
|
||||
titleBarView.setTitle(config.titleBarTitle);
|
||||
}
|
||||
|
||||
if (config.titleBarTitleColor != null) {
|
||||
titleBarView.setTitleColor(config.titleBarTitleColor);
|
||||
}
|
||||
|
||||
if (config.titleBarLeftRes != null) {
|
||||
titleBarView.setLeftImageRes(config.titleBarLeftRes);
|
||||
}
|
||||
|
||||
if (config.titleBarLeftRes != null) {
|
||||
titleBarView.setLeftImageRes(config.titleBarLeftRes);
|
||||
}
|
||||
|
||||
if (config.titleBarRightRes != null) {
|
||||
titleBarView.setRightImageRes(config.titleBarRightRes);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.customLayout != null) {
|
||||
config.customLayout.customizeConversationLayout(this);
|
||||
}
|
||||
}
|
||||
|
||||
public TitleBarView getTitleBar() {
|
||||
return viewBinding.titleBar;
|
||||
}
|
||||
|
||||
public LinearLayout getTopLayout() {
|
||||
return viewBinding.topLayout;
|
||||
}
|
||||
|
||||
public LinearLayout getBodyLayout() {
|
||||
return viewBinding.bodyLayout;
|
||||
}
|
||||
|
||||
public FrameLayout getBottomLayout() {
|
||||
return viewBinding.bottomLayout;
|
||||
}
|
||||
|
||||
public FrameLayout getBodyTopLayout() {
|
||||
return viewBinding.bodyTopLayout;
|
||||
}
|
||||
|
||||
public TextView getErrorTextView() {
|
||||
return viewBinding.errorTv;
|
||||
}
|
||||
|
||||
public void setEmptyViewVisible(int visible) {
|
||||
viewBinding.emptyLayout.setVisibility(visible);
|
||||
}
|
||||
|
||||
public View getEmptyView() {
|
||||
return viewBinding.emptyLayout;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun.page;
|
||||
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.netease.yunxin.kit.common.ui.widgets.TitleBarView;
|
||||
import com.netease.yunxin.kit.common.utils.SizeUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationKitClient;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationUIConfig;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.FunConversationFragmentBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.fun.FunViewHolderFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.interfaces.IConverationSelectorListener;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.ConversationBaseFragment;
|
||||
|
||||
public class FunFriendConversationFragment extends ConversationBaseFragment {
|
||||
|
||||
|
||||
public static FunFriendConversationFragment getInstance(boolean isselector) {
|
||||
FunFriendConversationFragment fragment = new FunFriendConversationFragment();
|
||||
Bundle bundle = new Bundle();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
private FunConversationFragmentBinding viewBinding;
|
||||
private boolean needSelector = false;
|
||||
public IConverationSelectorListener converationSelectorListener;
|
||||
|
||||
@Override
|
||||
public View initViewAndGetRootView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
viewBinding = FunConversationFragmentBinding.inflate(inflater, container, false);
|
||||
initView();
|
||||
return viewBinding.getRoot();
|
||||
}
|
||||
|
||||
public void setOnItemSelectorListener(IConverationSelectorListener onItemSelectorListener) {
|
||||
this.converationSelectorListener = onItemSelectorListener;
|
||||
}
|
||||
|
||||
|
||||
private void initView() {
|
||||
conversationView = viewBinding.conversationView;
|
||||
titleBarView = viewBinding.titleBar;
|
||||
titleBarView.setVisibility(View.GONE);
|
||||
viewBinding.searchLayout.setVisibility(View.GONE);
|
||||
networkErrorView = viewBinding.errorTv;
|
||||
emptyView = viewBinding.emptyLayout;
|
||||
FunViewHolderFactory funViewHolderFactory = new FunViewHolderFactory();
|
||||
funViewHolderFactory.isSelector = false;
|
||||
funViewHolderFactory.setOnSelectorClickListener(converationSelectorListener);
|
||||
setViewHolderFactory(funViewHolderFactory);
|
||||
// viewBinding.conversationView.addItemDecoration(getItemDecoration());
|
||||
// loadUIConfig();
|
||||
}
|
||||
|
||||
public void refreshView() {
|
||||
|
||||
}
|
||||
|
||||
public RecyclerView.ItemDecoration getItemDecoration() {
|
||||
return new RecyclerView.ItemDecoration() {
|
||||
final int topPadding = SizeUtils.dp2px(0.25f);
|
||||
final int indent = SizeUtils.dp2px(76);
|
||||
|
||||
@Override
|
||||
public void onDrawOver(
|
||||
@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||
int left = parent.getPaddingLeft() + indent;
|
||||
int right = parent.getWidth() - parent.getPaddingRight();
|
||||
|
||||
int childCount = parent.getChildCount();
|
||||
for (int i = 0; i < childCount - 1; i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
int top = child.getBottom() + params.bottomMargin;
|
||||
int bottom = top + topPadding;
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setColor(
|
||||
parent.getResources().getColor(R.color.fun_conversation_item_divide_line_color));
|
||||
canvas.drawRect(left, top, right, bottom, paint);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void loadUIConfig() {
|
||||
if (ConversationKitClient.getConversationUIConfig() == null) {
|
||||
return;
|
||||
}
|
||||
ConversationUIConfig config = ConversationKitClient.getConversationUIConfig();
|
||||
|
||||
viewBinding.titleBar.setLeftImageClick(
|
||||
v -> {
|
||||
if (config.titleBarLeftClick != null) {
|
||||
config.titleBarLeftClick.onClick(v);
|
||||
}
|
||||
});
|
||||
|
||||
if (config.conversationComparator != null) {
|
||||
setComparator(config.conversationComparator);
|
||||
}
|
||||
|
||||
if (config.conversationFactory != null) {
|
||||
setViewHolderFactory(config.conversationFactory);
|
||||
}
|
||||
|
||||
if (!config.showTitleBar) {
|
||||
titleBarView.setVisibility(View.GONE);
|
||||
} else {
|
||||
titleBarView.setVisibility(View.VISIBLE);
|
||||
titleBarView.setHeadImageVisible(config.showTitleBarLeftIcon ? View.VISIBLE : View.GONE);
|
||||
titleBarView.showRightImageView(config.showTitleBarRightIcon);
|
||||
|
||||
if (config.titleBarTitle != null) {
|
||||
titleBarView.setTitle(config.titleBarTitle);
|
||||
}
|
||||
|
||||
if (config.titleBarTitleColor != null) {
|
||||
titleBarView.setTitleColor(config.titleBarTitleColor);
|
||||
}
|
||||
|
||||
if (config.titleBarLeftRes != null) {
|
||||
titleBarView.setLeftImageRes(config.titleBarLeftRes);
|
||||
}
|
||||
|
||||
if (config.titleBarLeftRes != null) {
|
||||
titleBarView.setLeftImageRes(config.titleBarLeftRes);
|
||||
}
|
||||
|
||||
if (config.titleBarRightRes != null) {
|
||||
titleBarView.setRightImageRes(config.titleBarRightRes);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.customLayout != null) {
|
||||
config.customLayout.customizeConversationLayout(this);
|
||||
}
|
||||
}
|
||||
|
||||
public TitleBarView getTitleBar() {
|
||||
return viewBinding.titleBar;
|
||||
}
|
||||
|
||||
public LinearLayout getTopLayout() {
|
||||
return viewBinding.topLayout;
|
||||
}
|
||||
|
||||
public LinearLayout getBodyLayout() {
|
||||
return viewBinding.bodyLayout;
|
||||
}
|
||||
|
||||
public FrameLayout getBottomLayout() {
|
||||
return viewBinding.bottomLayout;
|
||||
}
|
||||
|
||||
public FrameLayout getBodyTopLayout() {
|
||||
return viewBinding.bodyTopLayout;
|
||||
}
|
||||
|
||||
public TextView getErrorTextView() {
|
||||
return viewBinding.errorTv;
|
||||
}
|
||||
|
||||
public void setEmptyViewVisible(int visible) {
|
||||
viewBinding.emptyLayout.setVisibility(visible);
|
||||
}
|
||||
|
||||
public View getEmptyView() {
|
||||
return viewBinding.emptyLayout;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun.page;
|
||||
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.netease.yunxin.kit.common.ui.widgets.TitleBarView;
|
||||
import com.netease.yunxin.kit.common.utils.SizeUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationKitClient;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationUIConfig;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.FunConversationFragmentBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.fun.FunViewHolderFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.interfaces.IConverationSelectorListener;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.ConversationBaseFragment;
|
||||
|
||||
public class FunGroupConversationFragment extends ConversationBaseFragment {
|
||||
|
||||
|
||||
public static FunGroupConversationFragment getInstance(boolean isselector) {
|
||||
FunGroupConversationFragment fragment = new FunGroupConversationFragment();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean("isSelector", isselector);
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
private FunConversationFragmentBinding viewBinding;
|
||||
private boolean needSelector = false;
|
||||
public IConverationSelectorListener converationSelectorListener;
|
||||
|
||||
@Override
|
||||
public View initViewAndGetRootView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
viewBinding = FunConversationFragmentBinding.inflate(inflater, container, false);
|
||||
Bundle bundle = getArguments();
|
||||
if (bundle != null) {
|
||||
needSelector = bundle.getBoolean("isSelector");
|
||||
}
|
||||
initView();
|
||||
return viewBinding.getRoot();
|
||||
}
|
||||
|
||||
public void setOnItemSelectorListener(IConverationSelectorListener onItemSelectorListener) {
|
||||
this.converationSelectorListener = onItemSelectorListener;
|
||||
}
|
||||
|
||||
|
||||
private void initView() {
|
||||
conversationView = viewBinding.conversationView;
|
||||
titleBarView = viewBinding.titleBar;
|
||||
titleBarView.setVisibility(View.GONE);
|
||||
viewBinding.searchLayout.setVisibility(View.GONE);
|
||||
networkErrorView = viewBinding.errorTv;
|
||||
emptyView = viewBinding.emptyLayout;
|
||||
FunViewHolderFactory funViewHolderFactory = new FunViewHolderFactory();
|
||||
funViewHolderFactory.isSelector = needSelector;
|
||||
funViewHolderFactory.setOnSelectorClickListener(converationSelectorListener);
|
||||
setViewHolderFactory(funViewHolderFactory);
|
||||
// viewBinding.conversationView.addItemDecoration(getItemDecoration());
|
||||
// loadUIConfig();
|
||||
}
|
||||
|
||||
public void refreshView() {
|
||||
|
||||
}
|
||||
|
||||
public RecyclerView.ItemDecoration getItemDecoration() {
|
||||
return new RecyclerView.ItemDecoration() {
|
||||
final int topPadding = SizeUtils.dp2px(0.25f);
|
||||
final int indent = SizeUtils.dp2px(76);
|
||||
|
||||
@Override
|
||||
public void onDrawOver(
|
||||
@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||
int left = parent.getPaddingLeft() + indent;
|
||||
int right = parent.getWidth() - parent.getPaddingRight();
|
||||
|
||||
int childCount = parent.getChildCount();
|
||||
for (int i = 0; i < childCount - 1; i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
int top = child.getBottom() + params.bottomMargin;
|
||||
int bottom = top + topPadding;
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setColor(
|
||||
parent.getResources().getColor(R.color.fun_conversation_item_divide_line_color));
|
||||
canvas.drawRect(left, top, right, bottom, paint);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void loadUIConfig() {
|
||||
if (ConversationKitClient.getConversationUIConfig() == null) {
|
||||
return;
|
||||
}
|
||||
ConversationUIConfig config = ConversationKitClient.getConversationUIConfig();
|
||||
|
||||
viewBinding.titleBar.setLeftImageClick(
|
||||
v -> {
|
||||
if (config.titleBarLeftClick != null) {
|
||||
config.titleBarLeftClick.onClick(v);
|
||||
}
|
||||
});
|
||||
|
||||
if (config.conversationComparator != null) {
|
||||
setComparator(config.conversationComparator);
|
||||
}
|
||||
|
||||
if (config.conversationFactory != null) {
|
||||
setViewHolderFactory(config.conversationFactory);
|
||||
}
|
||||
|
||||
if (!config.showTitleBar) {
|
||||
titleBarView.setVisibility(View.GONE);
|
||||
} else {
|
||||
titleBarView.setVisibility(View.VISIBLE);
|
||||
titleBarView.setHeadImageVisible(config.showTitleBarLeftIcon ? View.VISIBLE : View.GONE);
|
||||
titleBarView.showRightImageView(config.showTitleBarRightIcon);
|
||||
|
||||
if (config.titleBarTitle != null) {
|
||||
titleBarView.setTitle(config.titleBarTitle);
|
||||
}
|
||||
|
||||
if (config.titleBarTitleColor != null) {
|
||||
titleBarView.setTitleColor(config.titleBarTitleColor);
|
||||
}
|
||||
|
||||
if (config.titleBarLeftRes != null) {
|
||||
titleBarView.setLeftImageRes(config.titleBarLeftRes);
|
||||
}
|
||||
|
||||
if (config.titleBarLeftRes != null) {
|
||||
titleBarView.setLeftImageRes(config.titleBarLeftRes);
|
||||
}
|
||||
|
||||
if (config.titleBarRightRes != null) {
|
||||
titleBarView.setRightImageRes(config.titleBarRightRes);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.customLayout != null) {
|
||||
config.customLayout.customizeConversationLayout(this);
|
||||
}
|
||||
}
|
||||
|
||||
public TitleBarView getTitleBar() {
|
||||
return viewBinding.titleBar;
|
||||
}
|
||||
|
||||
public LinearLayout getTopLayout() {
|
||||
return viewBinding.topLayout;
|
||||
}
|
||||
|
||||
public LinearLayout getBodyLayout() {
|
||||
return viewBinding.bodyLayout;
|
||||
}
|
||||
|
||||
public FrameLayout getBottomLayout() {
|
||||
return viewBinding.bottomLayout;
|
||||
}
|
||||
|
||||
public FrameLayout getBodyTopLayout() {
|
||||
return viewBinding.bodyTopLayout;
|
||||
}
|
||||
|
||||
public TextView getErrorTextView() {
|
||||
return viewBinding.errorTv;
|
||||
}
|
||||
|
||||
public void setEmptyViewVisible(int visible) {
|
||||
viewBinding.emptyLayout.setVisibility(visible);
|
||||
}
|
||||
|
||||
public View getEmptyView() {
|
||||
return viewBinding.emptyLayout;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun.viewholder;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.BitmapFactory.Options;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.collection.LruCache;
|
||||
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
public class EmojiManager {
|
||||
|
||||
private static final String EMOJI_DIR = "emoji/";
|
||||
|
||||
// max cache size
|
||||
private static final int CACHE_MAX_SIZE = 1024;
|
||||
|
||||
private static Pattern pattern;
|
||||
|
||||
// default entries
|
||||
private static final List<Entry> defaultEntries = new ArrayList<>();
|
||||
// text to entry
|
||||
private static final Map<String, Entry> text2entry = new HashMap<>();
|
||||
// asset bitmap cache, key: asset path
|
||||
private static LruCache<String, Bitmap> drawableCache;
|
||||
|
||||
private static WeakReference<Context> sContext;
|
||||
|
||||
public static void init(Context context) {
|
||||
|
||||
sContext = new WeakReference<>(context);
|
||||
|
||||
load(context);
|
||||
|
||||
pattern = makePattern();
|
||||
|
||||
drawableCache =
|
||||
new LruCache<String, Bitmap>(CACHE_MAX_SIZE) {
|
||||
@Override
|
||||
protected void entryRemoved(
|
||||
boolean evicted, @NonNull String key, @NonNull Bitmap oldValue, Bitmap newValue) {
|
||||
if (oldValue != newValue) oldValue.recycle();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Context getContext() {
|
||||
return sContext.get();
|
||||
}
|
||||
|
||||
private static class Entry {
|
||||
String text;
|
||||
String assetPath;
|
||||
|
||||
Entry(String text, String assetPath) {
|
||||
this.text = text;
|
||||
this.assetPath = assetPath;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDisplayCount() {
|
||||
return defaultEntries.size();
|
||||
}
|
||||
|
||||
public static Drawable getDisplayDrawable(Context context, int index) {
|
||||
String text =
|
||||
(index >= 0 && index < defaultEntries.size() ? defaultEntries.get(index).text : null);
|
||||
return text == null ? null : getDrawable(context, text);
|
||||
}
|
||||
|
||||
public static String getDisplayText(int index) {
|
||||
return index >= 0 && index < defaultEntries.size() ? defaultEntries.get(index).text : null;
|
||||
}
|
||||
|
||||
public static Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public static Drawable getDrawable(Context context, String text) {
|
||||
Entry entry = text2entry.get(text);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap cache = drawableCache.get(entry.assetPath);
|
||||
if (cache == null) {
|
||||
cache = loadAssetBitmap(context, entry.assetPath);
|
||||
}
|
||||
return new BitmapDrawable(context.getResources(), cache);
|
||||
}
|
||||
|
||||
public static String getDrawablePath(Context context, String text) {
|
||||
Entry entry = text2entry.get(text);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
return entry.assetPath;
|
||||
}
|
||||
|
||||
private static Pattern makePattern() {
|
||||
return Pattern.compile(patternOfDefault());
|
||||
}
|
||||
|
||||
private static String patternOfDefault() {
|
||||
return "\\[[^\\[]{1,20}\\]";
|
||||
}
|
||||
|
||||
private static Bitmap loadAssetBitmap(Context context, String assetPath) {
|
||||
InputStream is = null;
|
||||
try {
|
||||
Resources resources = context.getResources();
|
||||
Options options = new Options();
|
||||
options.inDensity = DisplayMetrics.DENSITY_HIGH;
|
||||
options.inScreenDensity = resources.getDisplayMetrics().densityDpi;
|
||||
options.inTargetDensity = resources.getDisplayMetrics().densityDpi;
|
||||
is = context.getAssets().open(assetPath);
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(is, new Rect(), options);
|
||||
if (bitmap != null) {
|
||||
drawableCache.put(assetPath, bitmap);
|
||||
}
|
||||
return bitmap;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void load(Context context) {
|
||||
new EntryLoader().load(context);
|
||||
}
|
||||
|
||||
private static class EntryLoader {
|
||||
private String catalog = "";
|
||||
|
||||
void load(Context context) {
|
||||
try {
|
||||
XmlResourceParser xmlParser = context.getResources().getXml(R.xml.emoji);
|
||||
//
|
||||
try {
|
||||
int event = xmlParser.getEventType(); //先获取当前解析器光标在哪
|
||||
while (event != XmlPullParser.END_DOCUMENT) { //如果还没到文档的结束标志,那么就继续往下处理
|
||||
if (event == XmlPullParser.START_TAG) { //一般都是获取标签的属性值,所以在这里数据你需要的数据
|
||||
if (xmlParser.getName().equals("Catalog")) {
|
||||
catalog = xmlParser.getAttributeValue(0);
|
||||
} else if (xmlParser.getName().equals("Emoticon")) {
|
||||
String fileName = xmlParser.getAttributeValue(0);
|
||||
String tag = xmlParser.getAttributeValue(2);
|
||||
Entry entry = new Entry(tag, EMOJI_DIR + catalog + "/" + fileName);
|
||||
|
||||
if (catalog.equals("default")) {
|
||||
defaultEntries.add(entry);
|
||||
if (fileName.startsWith("emoji_"))
|
||||
text2entry.put(entry.text, entry);
|
||||
}
|
||||
|
||||
|
||||
if (catalog.equals("taotao")) {
|
||||
defaultEntries.add(entry);
|
||||
if (fileName.startsWith("taotao_"))
|
||||
text2entry.put(entry.text, entry);
|
||||
}
|
||||
|
||||
|
||||
if (catalog.equals("lele")) {
|
||||
defaultEntries.add(entry);
|
||||
if (fileName.startsWith("lele_"))
|
||||
text2entry.put(entry.text, entry);
|
||||
}
|
||||
|
||||
|
||||
if (catalog.equals("tingting")) {
|
||||
defaultEntries.add(entry);
|
||||
if (fileName.startsWith("tingting_"))
|
||||
text2entry.put(entry.text, entry);
|
||||
}
|
||||
|
||||
if (catalog.equals("tlt")) {
|
||||
defaultEntries.add(entry);
|
||||
if (fileName.startsWith("tlt_"))
|
||||
text2entry.put(entry.text, entry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
event = xmlParser.next(); //将当前解析器光标往下一步移
|
||||
}
|
||||
} catch (XmlPullParserException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun.viewholder;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.ImageSpan;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.netease.nim.highavailable.LogUtils;
|
||||
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum;
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
|
||||
import com.netease.nimlib.sdk.msg.model.IMMessage;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.chatkit.repo.ContactRepo;
|
||||
import com.netease.yunxin.kit.common.ui.utils.TimeFormatUtils;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseBean;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseViewHolder;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.ViewHolderClickListener;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationCustom;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationKitClient;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationUIConfig;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.TimeConversationUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.FunConversationViewHolderBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.interfaces.IConverationSelectorListener;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.corekit.im.IMKitClient;
|
||||
import com.netease.yunxin.kit.corekit.im.custom.CustomAttachment;
|
||||
import com.netease.yunxin.kit.corekit.im.model.FriendInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class FunConversationBaseViewHolder extends BaseViewHolder<ConversationBean> {
|
||||
|
||||
protected FunConversationViewHolderBinding viewBinding;
|
||||
protected Drawable stickTopDrawable;
|
||||
protected Drawable itemDrawable;
|
||||
protected Drawable selectorDrawable;
|
||||
protected Drawable unselectorDrawable;
|
||||
public IConverationSelectorListener itemSelectorlistener;
|
||||
public boolean isServices = false;
|
||||
|
||||
public void setItemSelectorlistener(IConverationSelectorListener itemSelectorlistener) {
|
||||
this.itemSelectorlistener = itemSelectorlistener;
|
||||
}
|
||||
|
||||
public FunConversationBaseViewHolder(@NonNull FunConversationViewHolderBinding binding) {
|
||||
super(binding.getRoot());
|
||||
viewBinding = binding;
|
||||
}
|
||||
|
||||
public void setIsServices(boolean misServices) {
|
||||
isServices = misServices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindData(ConversationBean data, int position) {
|
||||
loadUIConfig();
|
||||
viewBinding.ivSelector.setBackground(data.isSelector ? selectorDrawable : unselectorDrawable);
|
||||
String conversationContent = ConversationUtils.getConversationText(itemView.getContext(), data.infoData);
|
||||
|
||||
if (!TextUtils.isEmpty(conversationContent)) {
|
||||
if (data.infoData.getSessionType() == SessionTypeEnum.Team && data.infoData.getMsgType() != MsgTypeEnum.notification &&
|
||||
(!data.infoData.getFromAccount().equals(IMKitClient.account()))) {
|
||||
//群聊展示 谁谁谁
|
||||
String contactId = data.infoData.getFromAccount();
|
||||
String name = data.infoData.getFromNick();
|
||||
if (ContactRepo.isFriend(contactId)) {
|
||||
FriendInfo friendInfo = ContactRepo.getFriend(contactId);
|
||||
if (friendInfo != null && !TextUtils.isEmpty(friendInfo.getAlias())) {
|
||||
name = friendInfo.getAlias();
|
||||
}
|
||||
}
|
||||
if (conversationContent.equals(viewBinding.getRoot().getContext().getResources().getString(R.string.chat_message_revoke_content))) {
|
||||
conversationContent = (TextUtils.isEmpty(name) ? "" : name + " ") + conversationContent;
|
||||
} else {
|
||||
conversationContent = (TextUtils.isEmpty(name) ? "" : name + ":") + conversationContent;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// viewBinding.messageTv.setText(conversationContent);
|
||||
ConversationCustom.identifyExpression(
|
||||
viewBinding.getRoot().getContext(),
|
||||
viewBinding.messageTv,
|
||||
conversationContent);
|
||||
|
||||
viewBinding.messageTv.setTextColor(viewBinding.getRoot().getContext().getResources().getColor(R.color.fun_conversation_item_sub_title_text_color));
|
||||
viewBinding.timeTv.setText(
|
||||
TimeConversationUtils.formatMillisecond(
|
||||
viewBinding.getRoot().getContext(), data.infoData.getTime()));
|
||||
if (data.getTextdraft() != null) {
|
||||
viewBinding.draftTv.setVisibility(View.VISIBLE);
|
||||
viewBinding.messageTv.setVisibility(View.GONE);
|
||||
viewBinding.draftTvContent.setVisibility(View.VISIBLE);
|
||||
ConversationCustom.identifyExpression(
|
||||
viewBinding.getRoot().getContext(),
|
||||
viewBinding.draftTvContent,
|
||||
data.getTextdraft());
|
||||
} else {
|
||||
viewBinding.draftTv.setVisibility(View.GONE);
|
||||
viewBinding.messageTv.setVisibility(View.VISIBLE);
|
||||
viewBinding.draftTvContent.setVisibility(View.GONE);
|
||||
}
|
||||
if (data.infoData.isStickTop()) {
|
||||
viewBinding.rootLayout.setBackground(stickTopDrawable);
|
||||
} else {
|
||||
viewBinding.rootLayout.setBackground(itemDrawable);
|
||||
}
|
||||
if (data.infoData.getMute()) {
|
||||
viewBinding.muteIv.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
viewBinding.muteIv.setVisibility(View.GONE);
|
||||
}
|
||||
if (data.infoData.getUnreadCount() > 0) {
|
||||
int count = data.infoData.getUnreadCount();
|
||||
String content;
|
||||
if (count >= 100) {
|
||||
content = "99+";
|
||||
} else {
|
||||
content = String.valueOf(count);
|
||||
}
|
||||
if (data.infoData.getMute()) {
|
||||
viewBinding.unreadTv.setBackgroundResource(R.drawable.bg_conversation_dark_dot);
|
||||
} else {
|
||||
viewBinding.unreadTv.setBackgroundResource(R.drawable.bg_conversation_red_dot);
|
||||
}
|
||||
viewBinding.unreadTv.setText(content);
|
||||
viewBinding.unreadTv.setVisibility(View.VISIBLE);
|
||||
Log.i("INFO", "value==" + viewBinding.messageTv.getText().toString());
|
||||
if (data.infoData.getAttachment() instanceof CustomAttachment) {
|
||||
CustomAttachment customAttachment = (CustomAttachment) data.infoData.getAttachment();
|
||||
if (customAttachment.getType() == 1005 || customAttachment.getType() == 1004 || customAttachment.getType() == 1006) {
|
||||
viewBinding.messageTv.setTextColor(Color.parseColor("#ff4e54"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
viewBinding.unreadTv.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// if (data.infoData.getMute()) {
|
||||
// viewBinding.muteIv.setVisibility(View.VISIBLE);
|
||||
//// viewBinding.unreadTv.setVisibility(View.GONE);
|
||||
// } else {
|
||||
//
|
||||
//
|
||||
// }
|
||||
|
||||
viewBinding.getRoot().setOnClickListener(v -> itemListener.onClick(v, data, position));
|
||||
viewBinding.getRoot().setOnLongClickListener(v -> itemListener.onLongClick(v, data, position));
|
||||
viewBinding.avatarView.setOnClickListener(v -> itemListener.onAvatarClick(v, data, position));
|
||||
viewBinding.avatarView.setOnLongClickListener(
|
||||
v -> itemListener.onAvatarLongClick(v, data, position));
|
||||
viewBinding.viewSelectorclick.setOnClickListener(v -> {
|
||||
if (itemSelectorlistener != null) data.setSelector(!data.isSelector);
|
||||
itemSelectorlistener.onSelectorClick(v, data, position);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void loadUIConfig() {
|
||||
itemDrawable =
|
||||
viewBinding
|
||||
.getRoot()
|
||||
.getContext()
|
||||
.getDrawable(R.drawable.fun_conversation_view_holder_selector);
|
||||
stickTopDrawable =
|
||||
viewBinding
|
||||
.getRoot()
|
||||
.getContext()
|
||||
.getDrawable(R.drawable.fun_conversation_view_holder_stick_selector);
|
||||
selectorDrawable =
|
||||
viewBinding
|
||||
.getRoot()
|
||||
.getContext()
|
||||
.getDrawable(R.drawable.fun_ic_selected_conversation);
|
||||
unselectorDrawable =
|
||||
viewBinding
|
||||
.getRoot()
|
||||
.getContext()
|
||||
.getDrawable(R.drawable.fun_ic_unselector_conversation);
|
||||
|
||||
// if (ConversationKitClient.getConversationUIConfig() != null) {
|
||||
// ConversationUIConfig config = ConversationKitClient.getConversationUIConfig();
|
||||
// if (config.itemTitleColor != null) {
|
||||
// viewBinding.nameTv.setTextColor(config.itemTitleColor);
|
||||
// }
|
||||
// if (config.itemTitleSize != null) {
|
||||
// viewBinding.nameTv.setTextSize(config.itemTitleSize);
|
||||
// }
|
||||
//
|
||||
// if (config.itemContentColor != null) {
|
||||
// viewBinding.messageTv.setTextColor(config.itemContentColor);
|
||||
// }
|
||||
// if (config.itemContentSize != null) {
|
||||
// viewBinding.messageTv.setTextSize(config.itemContentSize);
|
||||
// }
|
||||
//
|
||||
// if (config.itemDateColor != null) {
|
||||
// viewBinding.timeTv.setTextColor(config.itemDateColor);
|
||||
// }
|
||||
// if (config.itemDateSize != null) {
|
||||
// viewBinding.timeTv.setTextSize(config.itemDateSize);
|
||||
// }
|
||||
//
|
||||
// if (config.avatarCornerRadius != null) {
|
||||
// viewBinding.avatarView.setCornerRadius(config.avatarCornerRadius);
|
||||
// }
|
||||
// if (config.itemBackground != null) {
|
||||
// itemDrawable = config.itemBackground;
|
||||
// }
|
||||
// if (config.itemStickTopBackground != null) {
|
||||
// stickTopDrawable = config.itemStickTopBackground;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun.viewholder;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.FunConversationViewHolderBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
|
||||
public class FunConversationP2PViewHolder extends FunConversationBaseViewHolder {
|
||||
|
||||
public FunConversationP2PViewHolder(@NonNull FunConversationViewHolderBinding binding) {
|
||||
super(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindData(ConversationBean data, int position) {
|
||||
super.onBindData(data, position);
|
||||
String name = data.infoData.getName();
|
||||
String avatName = data.infoData.getAvatarName();
|
||||
if (TextUtils.isEmpty(data.infoData.getAvatar())) {
|
||||
viewBinding.avatarView.setData(R.drawable.default_head_img, data.infoData.getAvatarName());
|
||||
} else {
|
||||
viewBinding.avatarView.setData(
|
||||
data.infoData.getAvatar(),
|
||||
data.infoData.getAvatarName());
|
||||
}
|
||||
if (data.isServices) {
|
||||
viewBinding.tvMyteamtype.setBackgroundResource(R.drawable.cornor_stroke_6877fe_6dp);
|
||||
viewBinding.tvMyteamtype.setTextColor(viewBinding.getRoot().getContext().getColor(R.color.color_6877fe));
|
||||
viewBinding.tvMyteamtype.setText(viewBinding.getRoot().getContext().getResources().getString(R.string.services_text));
|
||||
viewBinding.tvMyteamtype.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
viewBinding.tvMyteamtype.setVisibility(View.GONE);
|
||||
}
|
||||
viewBinding.aliasTv.setVisibility(View.GONE);
|
||||
if (avatName.equals(name)) {
|
||||
viewBinding.nameTv.setEllipsize(TextUtils.TruncateAt.MIDDLE);
|
||||
viewBinding.nameTv.setText(name);
|
||||
viewBinding.nameTv.setMaxWidth(dip2px(viewBinding.nameTv.getContext(), 120));
|
||||
} else {
|
||||
viewBinding.nameTv.setMaxWidth(dip2px(viewBinding.nameTv.getContext(), 50));
|
||||
viewBinding.nameTv.setEllipsize(TextUtils.TruncateAt.END);
|
||||
viewBinding.aliasTv.setVisibility(View.VISIBLE);
|
||||
viewBinding.nameTv.setText(avatName);
|
||||
viewBinding.aliasTv.setText("(" + name + ")");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int dip2px(Context context, float dpValue) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (dpValue * scale + 0.5f);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.fun.viewholder;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Color;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.yunxin.kit.common.ui.utils.AvatarColor;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationHelper;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.FunConversationViewHolderBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.corekit.im.IMKitClient;
|
||||
|
||||
public class FunConversationTeamViewHolder extends FunConversationBaseViewHolder {
|
||||
|
||||
public FunConversationTeamViewHolder(@NonNull FunConversationViewHolderBinding binding) {
|
||||
super(binding);
|
||||
}
|
||||
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
@Override
|
||||
public void onBindData(ConversationBean data, int position) {
|
||||
super.onBindData(data, position);
|
||||
viewBinding.tvMyteamtype.setVisibility(View.GONE);
|
||||
viewBinding.aliasTv.setVisibility(View.GONE);
|
||||
if (data.infoData.getTeamInfo() != null) {
|
||||
Team teamInfo = data.infoData.getTeamInfo();
|
||||
if (TextUtils.isEmpty(teamInfo.getIcon())) {
|
||||
viewBinding.avatarView.setData(R.drawable.ic_group_defaulthead, "head", 1);
|
||||
} else {
|
||||
viewBinding.avatarView.setData(
|
||||
teamInfo.getIcon(), teamInfo.getName(), AvatarColor.avatarColor(teamInfo.getId()));
|
||||
}
|
||||
viewBinding.nameTv.setText(teamInfo.getName() + "(" + teamInfo.getMemberCount() + ")");
|
||||
if (data.infoData.getTeamInfo().getCreator().equals(IMKitClient.account())) {
|
||||
viewBinding.tvMyteamtype.setBackgroundResource(R.drawable.cornor_6877fe_6dp);
|
||||
viewBinding.tvMyteamtype.setTextColor(Color.parseColor("#ffffffff"));
|
||||
viewBinding.tvMyteamtype.setText(viewBinding.getRoot().getContext().getResources().getString(R.string.mine_text));
|
||||
viewBinding.tvMyteamtype.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
// viewBinding.groupNumber.setVisibility(View.VISIBLE);
|
||||
// viewBinding.groupNumber.setText("(" + teamInfo.getMemberCount() + ")");
|
||||
}
|
||||
if (data.infoData.getUnreadCount() > 0
|
||||
&& ConversationHelper.hasAit(data.infoData.getContactId())) {
|
||||
viewBinding.aitTv.setVisibility(View.VISIBLE);
|
||||
viewBinding.draftTvContent.setVisibility(View.GONE);
|
||||
viewBinding.messageTv.setVisibility(View.VISIBLE);
|
||||
viewBinding.draftTv.setVisibility(View.GONE);
|
||||
} else {
|
||||
viewBinding.aitTv.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.netease.yunxin.kit.conversationkit.ui.interfaces;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
|
||||
|
||||
public interface IConverationSelectorListener {
|
||||
|
||||
void onSelectorClick(View view, ConversationBean data, int position);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.interfaces;
|
||||
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import com.netease.yunxin.kit.common.ui.widgets.TitleBarView;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.view.ConversationView;
|
||||
|
||||
public interface IConversationLayout {
|
||||
|
||||
public TitleBarView getTitleBar();
|
||||
|
||||
public LinearLayout getTopLayout();
|
||||
|
||||
public LinearLayout getBodyLayout();
|
||||
|
||||
public ConversationView getConversationView();
|
||||
|
||||
public FrameLayout getBottomLayout();
|
||||
|
||||
public FrameLayout getBodyTopLayout();
|
||||
|
||||
public TextView getErrorTextView();
|
||||
|
||||
public void setEmptyViewVisible(int visible);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.model;
|
||||
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseBean;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ConversationBean extends BaseBean {
|
||||
private static final String TAG = "ConversationBean";
|
||||
public ConversationInfo infoData;
|
||||
|
||||
public String textdraft;
|
||||
|
||||
public boolean isSelector;
|
||||
|
||||
public boolean isServices;
|
||||
|
||||
public boolean isHide;
|
||||
|
||||
public boolean isSelector() {
|
||||
return isSelector;
|
||||
}
|
||||
|
||||
public boolean isHide() {
|
||||
return isHide;
|
||||
}
|
||||
|
||||
public void setHide(boolean hide) {
|
||||
isHide = hide;
|
||||
}
|
||||
|
||||
public void setSelector(boolean selector) {
|
||||
isSelector = selector;
|
||||
}
|
||||
|
||||
public String getTextdraft() {
|
||||
return textdraft;
|
||||
}
|
||||
|
||||
public void setTextdraft(String textdraft) {
|
||||
this.textdraft = textdraft;
|
||||
}
|
||||
|
||||
public ConversationBean(ConversationInfo data) {
|
||||
infoData = data;
|
||||
}
|
||||
|
||||
public ConversationBean(ConversationInfo data, String router, int viewType) {
|
||||
this(data, router, viewType, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data 会话数据
|
||||
* @param router 会话跳转的路由地址
|
||||
* @param viewType 会话展示的View类型
|
||||
* @param paramKey 跳转需要传递的参数KEY
|
||||
* @param paramValue 跳转需要传递的参数Value
|
||||
*/
|
||||
public ConversationBean(
|
||||
ConversationInfo data, String router, int viewType, String paramKey, Object paramValue) {
|
||||
infoData = data;
|
||||
this.router = router;
|
||||
this.viewType = viewType;
|
||||
this.paramKey = paramKey;
|
||||
this.param = paramValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof ConversationBean)) return false;
|
||||
ConversationBean that = (ConversationBean) o;
|
||||
return Objects.equals(infoData.getContactId(), that.infoData.getContactId())
|
||||
&& Objects.equals(infoData.getSessionType(), that.infoData.getSessionType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(infoData.getContactId(), infoData.getSessionType());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.netease.yunxin.kit.conversationkit.ui.model;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.netease.yunxin.kit.corekit.event.BaseEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DeleteConversionEvent extends BaseEvent {
|
||||
|
||||
public static final String EVENT_TYPE = "UpdateConversionEvent";
|
||||
public List<ConversationBean> conversationBeanList;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getType() {
|
||||
return EVENT_TYPE;
|
||||
}
|
||||
|
||||
|
||||
public List<ConversationBean> getConversationBeanList() {
|
||||
return conversationBeanList;
|
||||
}
|
||||
|
||||
public void setConversationBeanList(List<ConversationBean> conversationBeanList) {
|
||||
this.conversationBeanList = conversationBeanList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal;
|
||||
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.CHAT_KRY;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_CONTACT_SELECTOR_MAX_COUNT;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_REMOTE_EXTENSION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_REQUEST_SELECTOR_NAME;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_REQUEST_SELECTOR_NAME_ENABLE;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_SESSION_ID;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_TEAM_CREATED_TIP;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.KEY_TEAM_ID;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_ADD_FRIEND_PAGE;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_CHAT_SEND_TEAM_TIP_ACTION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_CHAT_TEAM_PAGE;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_CONTACT_SELECTOR_PAGE;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_CREATE_ADVANCED_TEAM_ACTION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_CREATE_NORMAL_TEAM_ACTION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.PATH_TEAM_INVITE_ACTION;
|
||||
import static com.netease.yunxin.kit.corekit.im.utils.RouterConstant.REQUEST_CONTACT_SELECTOR_KEY;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.netease.nimlib.sdk.team.model.CreateTeamResult;
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.yunxin.kit.alog.ALog;
|
||||
import com.netease.yunxin.kit.common.ui.photo.TransHelper;
|
||||
import com.netease.yunxin.kit.common.ui.widgets.ContentListPopView;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.corekit.route.XKitRouter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** pop menu factory */
|
||||
public final class PopItemFactory {
|
||||
private static final String TAG = "PopItemFactory";
|
||||
|
||||
public static ContentListPopView.Item getAddFriendItem(Context context) {
|
||||
LinearLayout.LayoutParams params = getParams(context);
|
||||
params.setMargins(
|
||||
(int) context.getResources().getDimension(R.dimen.pop_text_margin_left),
|
||||
(int) context.getResources().getDimension(R.dimen.pop_text_margin_right_top),
|
||||
0,
|
||||
0);
|
||||
return new ContentListPopView.Item.Builder()
|
||||
.configView(getView(context, R.string.add_friend, R.drawable.ic_conversation_add_friend))
|
||||
.configParams(params)
|
||||
.configClickListener(
|
||||
v -> XKitRouter.withKey(PATH_ADD_FRIEND_PAGE).withContext(context).navigate())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ContentListPopView.Item getCreateAdvancedTeamItem(
|
||||
Context context, int memberLimit) {
|
||||
LinearLayout.LayoutParams params = getParams(context);
|
||||
params.setMargins(
|
||||
(int) context.getResources().getDimension(R.dimen.pop_text_margin_left),
|
||||
0,
|
||||
0,
|
||||
(int) context.getResources().getDimension(R.dimen.pop_text_margin_right_top));
|
||||
int requestCode = 1;
|
||||
return new ContentListPopView.Item.Builder()
|
||||
.configView(
|
||||
getView(
|
||||
context, R.string.create_advanced_team, R.drawable.ic_conversation_advanced_team))
|
||||
.configParams(params)
|
||||
.configClickListener(
|
||||
getClickListener(context, requestCode, PATH_CREATE_ADVANCED_TEAM_ACTION, memberLimit))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ContentListPopView.Item getCreateGroupTeamItem(Context context, int memberLimit) {
|
||||
LinearLayout.LayoutParams params = getParams(context);
|
||||
params.setMargins(
|
||||
(int) context.getResources().getDimension(R.dimen.pop_text_margin_left),
|
||||
0,
|
||||
(int) context.getResources().getDimension(R.dimen.pop_text_margin_right_top),
|
||||
0);
|
||||
int requestCode = 2;
|
||||
return new ContentListPopView.Item.Builder()
|
||||
.configView(
|
||||
getView(context, R.string.create_group_team, R.drawable.ic_conversation_group_team))
|
||||
.configParams(params)
|
||||
.configClickListener(
|
||||
getClickListener(context, requestCode, PATH_CREATE_NORMAL_TEAM_ACTION, memberLimit))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static View.OnClickListener getClickListener(
|
||||
Context context, int requestCode, String createMethod, int memberLimit) {
|
||||
return v ->
|
||||
TransHelper.launchTask(
|
||||
context,
|
||||
requestCode,
|
||||
(activity, integer) -> {
|
||||
XKitRouter.withKey(PATH_CONTACT_SELECTOR_PAGE)
|
||||
.withParam(KEY_CONTACT_SELECTOR_MAX_COUNT, memberLimit)
|
||||
.withParam(KEY_REQUEST_SELECTOR_NAME_ENABLE, true)
|
||||
.withContext(activity)
|
||||
.withRequestCode(integer)
|
||||
.navigate();
|
||||
return null;
|
||||
},
|
||||
intentResultInfo -> {
|
||||
if (intentResultInfo == null
|
||||
|| !intentResultInfo.getSuccess()
|
||||
|| intentResultInfo.getValue() == null) {
|
||||
return null;
|
||||
}
|
||||
Intent data = intentResultInfo.getValue();
|
||||
ArrayList<String> list = data.getStringArrayListExtra(REQUEST_CONTACT_SELECTOR_KEY);
|
||||
if (list == null || list.isEmpty()) {
|
||||
ALog.e(TAG, "no one was chosen.");
|
||||
return null;
|
||||
}
|
||||
XKitRouter.withKey(createMethod)
|
||||
.withParam(
|
||||
KEY_REQUEST_SELECTOR_NAME,
|
||||
data.getStringArrayListExtra(KEY_REQUEST_SELECTOR_NAME))
|
||||
.navigate(
|
||||
res -> {
|
||||
if (res.getSuccess() && res.getValue() instanceof CreateTeamResult) {
|
||||
Team teamInfo = ((CreateTeamResult) res.getValue()).getTeam();
|
||||
Map<String, Object> map = new HashMap<>(1);
|
||||
map.put(
|
||||
KEY_TEAM_CREATED_TIP,
|
||||
context.getString(R.string.create_advanced_team_success));
|
||||
// 发送创建成功群里提示信息
|
||||
XKitRouter.withKey(PATH_CHAT_SEND_TEAM_TIP_ACTION)
|
||||
.withParam(KEY_SESSION_ID, teamInfo.getId())
|
||||
.withParam(KEY_REMOTE_EXTENSION, map)
|
||||
.navigate();
|
||||
|
||||
// 邀请加入群,处理邀请通知早于创建成功同志
|
||||
XKitRouter.withKey(PATH_TEAM_INVITE_ACTION)
|
||||
.withParam(KEY_TEAM_ID, teamInfo.getId())
|
||||
.withParam(REQUEST_CONTACT_SELECTOR_KEY, list)
|
||||
.navigate();
|
||||
|
||||
//跳转到会话页面
|
||||
XKitRouter.withKey(PATH_CHAT_TEAM_PAGE)
|
||||
.withContext(context)
|
||||
.withParam(CHAT_KRY, teamInfo)
|
||||
.navigate();
|
||||
|
||||
} else {
|
||||
ALog.e(TAG, "create team failed.");
|
||||
}
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private static View getView(Context context, int txtId, int drawableId) {
|
||||
TextView textView = new TextView(context);
|
||||
textView.setGravity(Gravity.CENTER_VERTICAL);
|
||||
textView.setTextSize(14);
|
||||
textView.setMaxLines(1);
|
||||
textView.setText(txtId);
|
||||
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
|
||||
if (drawable != null) {
|
||||
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
|
||||
textView.setCompoundDrawables(drawable, null, null, null);
|
||||
}
|
||||
textView.setTextColor(ContextCompat.getColor(context, R.color.color_333333));
|
||||
textView.setCompoundDrawablePadding(
|
||||
(int) context.getResources().getDimension(R.dimen.pop_text_margin_right_top));
|
||||
return textView;
|
||||
}
|
||||
|
||||
private static LinearLayout.LayoutParams getParams(Context context) {
|
||||
return new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
(int) context.getResources().getDimension(R.dimen.pop_item_height));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.IConversationFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.ConversationViewHolderBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.normal.viewholder.ConversationP2PViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.normal.viewholder.ConversationTeamViewHolder;
|
||||
import com.netease.yunxin.kit.corekit.im.utils.RouterConstant;
|
||||
|
||||
/** conversation view holder factory to create view holder in recyclerview */
|
||||
public class ViewHolderFactory implements IConversationFactory {
|
||||
|
||||
@Override
|
||||
public ConversationBean CreateBean(ConversationInfo info) {
|
||||
ConversationBean bean = new ConversationBean(info);
|
||||
if (info.getSessionType() == SessionTypeEnum.P2P) {
|
||||
return new ConversationBean(
|
||||
info,
|
||||
RouterConstant.PATH_CHAT_P2P_PAGE,
|
||||
ConversationConstant.ViewType.CHAT_VIEW,
|
||||
RouterConstant.CHAT_ID_KRY,
|
||||
info.getContactId());
|
||||
} else if (info.getSessionType() == SessionTypeEnum.Team
|
||||
|| info.getSessionType() == SessionTypeEnum.SUPER_TEAM) {
|
||||
return new ConversationBean(
|
||||
info,
|
||||
RouterConstant.PATH_CHAT_TEAM_PAGE,
|
||||
ConversationConstant.ViewType.TEAM_VIEW,
|
||||
RouterConstant.CHAT_ID_KRY,
|
||||
info.getContactId());
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(ConversationBean data) {
|
||||
return data.viewType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseViewHolder<ConversationBean> createViewHolder(
|
||||
@NonNull ViewGroup parent, int viewType) {
|
||||
ConversationViewHolderBinding binding =
|
||||
ConversationViewHolderBinding.inflate(
|
||||
LayoutInflater.from(parent.getContext()), parent, false);
|
||||
if (viewType == ConversationConstant.ViewType.TEAM_VIEW) {
|
||||
return new ConversationTeamViewHolder(binding);
|
||||
} else {
|
||||
return new ConversationP2PViewHolder(binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal.page;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import com.netease.yunxin.kit.common.ui.activities.BaseActivity;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.ConversationActivityBinding;
|
||||
|
||||
public class ConversationActivity extends BaseActivity {
|
||||
|
||||
private ConversationActivityBinding viewBinding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
viewBinding = ConversationActivityBinding.inflate(LayoutInflater.from(this));
|
||||
setContentView(viewBinding.getRoot());
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
ConversationFragment fragment = new ConversationFragment();
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.add(R.id.conversation_container, fragment)
|
||||
.commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal.page;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.netease.yunxin.kit.common.ui.widgets.ContentListPopView;
|
||||
import com.netease.yunxin.kit.common.ui.widgets.TitleBarView;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationKitClient;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationUIConfig;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationUIConstant;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.ConversationFragmentBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.normal.PopItemFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.normal.ViewHolderFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.ConversationBaseFragment;
|
||||
import com.netease.yunxin.kit.corekit.im.utils.RouterConstant;
|
||||
import com.netease.yunxin.kit.corekit.route.XKitRouter;
|
||||
|
||||
/** conversation list fragment show your recent conversation */
|
||||
public class ConversationFragment extends ConversationBaseFragment {
|
||||
|
||||
private final String TAG = "ConversationFragment";
|
||||
protected ConversationFragmentBinding viewBinding;
|
||||
|
||||
@Override
|
||||
public View initViewAndGetRootView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
viewBinding = ConversationFragmentBinding.inflate(inflater, container, false);
|
||||
initView();
|
||||
return viewBinding.getRoot();
|
||||
}
|
||||
|
||||
public void initView() {
|
||||
conversationView = viewBinding.conversationView;
|
||||
titleBarView = viewBinding.titleBar;
|
||||
networkErrorView = viewBinding.errorTv;
|
||||
emptyView = viewBinding.emptyLayout;
|
||||
setViewHolderFactory(new ViewHolderFactory());
|
||||
loadUIConfig();
|
||||
viewBinding.titleBar.setRightImageClick(
|
||||
v -> {
|
||||
if (ConversationKitClient.getConversationUIConfig() != null
|
||||
&& ConversationKitClient.getConversationUIConfig().titleBarRightClick != null) {
|
||||
ConversationKitClient.getConversationUIConfig().titleBarRightClick.onClick(v);
|
||||
return;
|
||||
}
|
||||
Context context = getContext();
|
||||
int memberLimit = ConversationUIConstant.MAX_TEAM_MEMBER;
|
||||
ContentListPopView contentListPopView =
|
||||
new ContentListPopView.Builder(context)
|
||||
.addItem(PopItemFactory.getAddFriendItem(context))
|
||||
.addItem(PopItemFactory.getCreateGroupTeamItem(context, memberLimit))
|
||||
.addItem(PopItemFactory.getCreateAdvancedTeamItem(context, memberLimit))
|
||||
.build();
|
||||
contentListPopView.showAsDropDown(
|
||||
v, (int) requireContext().getResources().getDimension(R.dimen.pop_margin_right), 0);
|
||||
});
|
||||
|
||||
viewBinding.titleBar.setRight2ImageClick(
|
||||
v -> {
|
||||
if (ConversationKitClient.getConversationUIConfig() != null
|
||||
&& ConversationKitClient.getConversationUIConfig().titleBarRight2Click != null) {
|
||||
ConversationKitClient.getConversationUIConfig().titleBarRight2Click.onClick(v);
|
||||
return;
|
||||
}
|
||||
XKitRouter.withKey(RouterConstant.PATH_GLOBAL_SEARCH_PAGE)
|
||||
.withContext(requireContext())
|
||||
.navigate();
|
||||
});
|
||||
}
|
||||
|
||||
private void loadUIConfig() {
|
||||
|
||||
if (ConversationKitClient.getConversationUIConfig() == null) {
|
||||
return;
|
||||
}
|
||||
ConversationUIConfig config = ConversationKitClient.getConversationUIConfig();
|
||||
|
||||
viewBinding.titleBar.setLeftImageClick(
|
||||
v -> {
|
||||
if (config.titleBarLeftClick != null) {
|
||||
config.titleBarLeftClick.onClick(v);
|
||||
}
|
||||
});
|
||||
|
||||
if (config.conversationComparator != null) {
|
||||
setComparator(config.conversationComparator);
|
||||
}
|
||||
|
||||
if (config.conversationFactory != null) {
|
||||
setViewHolderFactory(config.conversationFactory);
|
||||
}
|
||||
|
||||
if (titleBarView != null) {
|
||||
if (!config.showTitleBar) {
|
||||
titleBarView.setVisibility(View.GONE);
|
||||
} else {
|
||||
titleBarView.setVisibility(View.VISIBLE);
|
||||
titleBarView.setHeadImageVisible(config.showTitleBarLeftIcon ? View.VISIBLE : View.GONE);
|
||||
titleBarView.showRight2ImageView(config.showTitleBarRight2Icon);
|
||||
titleBarView.showRightImageView(config.showTitleBarRightIcon);
|
||||
|
||||
if (config.titleBarTitle != null) {
|
||||
titleBarView.setTitle(config.titleBarTitle);
|
||||
}
|
||||
|
||||
if (config.titleBarTitleColor != null) {
|
||||
titleBarView.setTitleColor(config.titleBarTitleColor);
|
||||
}
|
||||
|
||||
if (config.titleBarLeftRes != null) {
|
||||
titleBarView.setLeftImageRes(config.titleBarLeftRes);
|
||||
}
|
||||
|
||||
if (config.titleBarLeftRes != null) {
|
||||
titleBarView.setLeftImageRes(config.titleBarLeftRes);
|
||||
}
|
||||
|
||||
if (config.titleBarRightRes != null) {
|
||||
titleBarView.setRightImageRes(config.titleBarRightRes);
|
||||
}
|
||||
|
||||
if (config.titleBarRight2Res != null) {
|
||||
titleBarView.setRight2ImageRes(config.titleBarRight2Res);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.customLayout != null) {
|
||||
config.customLayout.customizeConversationLayout(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TitleBarView getTitleBar() {
|
||||
return viewBinding.titleBar;
|
||||
}
|
||||
|
||||
public LinearLayout getTopLayout() {
|
||||
return viewBinding.topLayout;
|
||||
}
|
||||
|
||||
public LinearLayout getBodyLayout() {
|
||||
return viewBinding.bodyLayout;
|
||||
}
|
||||
|
||||
public FrameLayout getBottomLayout() {
|
||||
return viewBinding.bottomLayout;
|
||||
}
|
||||
|
||||
public FrameLayout getBodyTopLayout() {
|
||||
return viewBinding.bodyTopLayout;
|
||||
}
|
||||
|
||||
public TextView getErrorTextView() {
|
||||
return viewBinding.errorTv;
|
||||
}
|
||||
|
||||
public void setEmptyViewVisible(int visible) {
|
||||
viewBinding.emptyLayout.setVisibility(visible);
|
||||
}
|
||||
|
||||
public View getEmptyView() {
|
||||
return viewBinding.emptyLayout;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal.page;
|
||||
|
||||
import static com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant.LIB_TAG;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import com.netease.yunxin.kit.alog.ALog;
|
||||
import com.netease.yunxin.kit.common.ui.activities.BaseActivity;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseBean;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.ViewHolderClickListener;
|
||||
import com.netease.yunxin.kit.common.ui.viewmodel.LoadStatus;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.ConversationSelectActivityBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.normal.page.viewmodel.SelectorViewModel;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.interfaces.ILoadListener;
|
||||
import com.netease.yunxin.kit.corekit.im.utils.RouterConstant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
/** conversation select activity to select a conversation */
|
||||
public class ConversationSelectActivity extends BaseActivity implements ILoadListener {
|
||||
private final String TAG = "ConversationSelectActivity";
|
||||
private ConversationSelectActivityBinding viewBinding;
|
||||
private SelectorViewModel viewModel;
|
||||
private HashSet<String> contactIdSet = new HashSet<>();
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ALog.d(LIB_TAG, TAG, "onCreate");
|
||||
viewBinding = ConversationSelectActivityBinding.inflate(LayoutInflater.from(this), null, false);
|
||||
setContentView(viewBinding.getRoot());
|
||||
|
||||
viewBinding.conversationSelectorView.setViewHolderFactory(new SelectorViewHolderFactory());
|
||||
viewBinding.conversationSelectorTitleBar.setActionTextColor(
|
||||
getResources().getColor(R.color.color_666666));
|
||||
viewBinding.conversationSelectorTitleBar.setActionListener(
|
||||
v -> {
|
||||
Intent intent = new Intent();
|
||||
if (contactIdSet.size() > 0) {
|
||||
intent.putExtra(
|
||||
RouterConstant.KEY_CONVERSATION_SELECTOR_KEY,
|
||||
new ArrayList<String>().addAll(contactIdSet));
|
||||
}
|
||||
ALog.d(LIB_TAG, TAG, "ActionListener");
|
||||
|
||||
setResult(RESULT_OK, intent);
|
||||
finish();
|
||||
});
|
||||
viewBinding.conversationSelectorTitleBar.setLeftActionListener(
|
||||
v -> {
|
||||
finish();
|
||||
});
|
||||
viewBinding.conversationSelectorView.setItemClickListener(
|
||||
new ViewHolderClickListener() {
|
||||
@Override
|
||||
public boolean onClick(View v, BaseBean data, int isCheck) {
|
||||
if (data instanceof ConversationBean) {
|
||||
if (isCheck == 1) {
|
||||
contactIdSet.add(((ConversationBean) data).infoData.getContactId());
|
||||
} else {
|
||||
contactIdSet.remove(((ConversationBean) data).infoData.getContactId());
|
||||
}
|
||||
ALog.d(LIB_TAG, TAG, "ItemClickListener,onClick:" + isCheck);
|
||||
updateTitleBar();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v, BaseBean data, int position) {
|
||||
ALog.d(LIB_TAG, TAG, "ItemClickListener,onLongClick");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
viewBinding.conversationSelectorView.setLoadMoreListener(this);
|
||||
|
||||
viewModel = new ViewModelProvider(this).get(SelectorViewModel.class);
|
||||
viewModel
|
||||
.getQueryLiveData()
|
||||
.observe(
|
||||
this,
|
||||
result -> {
|
||||
if (result.getLoadStatus() == LoadStatus.Success) {
|
||||
ALog.d(LIB_TAG, TAG, "QueryLiveData,Success");
|
||||
viewBinding.conversationSelectorView.setData(result.getData());
|
||||
}
|
||||
});
|
||||
|
||||
viewModel.fetchConversation();
|
||||
}
|
||||
|
||||
private void updateTitleBar() {
|
||||
if (contactIdSet.size() < 1) {
|
||||
viewBinding.conversationSelectorTitleBar.setActionText(
|
||||
getResources().getString(R.string.sure_title));
|
||||
viewBinding.conversationSelectorTitleBar.setActionTextColor(
|
||||
getResources().getColor(R.color.color_666666));
|
||||
} else {
|
||||
String text =
|
||||
String.format(getResources().getString(R.string.sure_count_title), contactIdSet.size());
|
||||
viewBinding.conversationSelectorTitleBar.setActionText(text);
|
||||
viewBinding.conversationSelectorTitleBar.setActionTextColor(
|
||||
getResources().getColor(R.color.color_337eff));
|
||||
}
|
||||
}
|
||||
|
||||
public static void start(Context context) {
|
||||
if (context != null) {
|
||||
Intent intent = new Intent(context, ConversationSelectActivity.class);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMore() {
|
||||
return viewModel.hasMore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMore(Object last) {
|
||||
if (last instanceof ConversationBean) {
|
||||
viewModel.loadMore((ConversationBean) last);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal.page;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.SelectorViewHolderLayoutBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.normal.ViewHolderFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.normal.viewholder.SelectorViewHolder;
|
||||
|
||||
/** select fragment or activity view holder factory */
|
||||
class SelectorViewHolderFactory extends ViewHolderFactory {
|
||||
|
||||
@Override
|
||||
public BaseViewHolder<ConversationBean> createViewHolder(
|
||||
@NonNull ViewGroup parent, int viewType) {
|
||||
|
||||
if (viewType == ConversationConstant.ViewType.CHAT_VIEW
|
||||
|| viewType == ConversationConstant.ViewType.TEAM_VIEW) {
|
||||
return new SelectorViewHolder(
|
||||
SelectorViewHolderLayoutBinding.inflate(
|
||||
LayoutInflater.from(parent.getContext()), parent, false));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal.page.viewmodel;
|
||||
|
||||
import static com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant.LIB_TAG;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import com.netease.yunxin.kit.alog.ALog;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.chatkit.repo.ConversationRepo;
|
||||
import com.netease.yunxin.kit.chatkit.repo.ConversationRepoAll;
|
||||
import com.netease.yunxin.kit.common.ui.viewmodel.BaseViewModel;
|
||||
import com.netease.yunxin.kit.common.ui.viewmodel.FetchResult;
|
||||
import com.netease.yunxin.kit.common.ui.viewmodel.LoadStatus;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.IConversationFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.normal.ViewHolderFactory;
|
||||
import com.netease.yunxin.kit.corekit.im.provider.FetchCallback;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** select conversation view model */
|
||||
public class SelectorViewModel extends BaseViewModel {
|
||||
private final String TAG = "SelectorViewModel";
|
||||
|
||||
private final MutableLiveData<FetchResult<List<ConversationBean>>> queryLiveData =
|
||||
new MutableLiveData<>();
|
||||
private IConversationFactory conversationFactory = new ViewHolderFactory();
|
||||
private static final int PAGE_LIMIT = 50;
|
||||
private boolean hasMore = true;
|
||||
|
||||
public MutableLiveData<FetchResult<List<ConversationBean>>> getQueryLiveData() {
|
||||
return queryLiveData;
|
||||
}
|
||||
|
||||
public void fetchConversation() {
|
||||
queryConversation(null);
|
||||
}
|
||||
|
||||
public void loadMore(ConversationBean data) {
|
||||
if (data != null && data.infoData != null) {
|
||||
queryConversation(data.infoData);
|
||||
}
|
||||
}
|
||||
|
||||
public void setConversationFactory(IConversationFactory factory) {
|
||||
this.conversationFactory = factory;
|
||||
}
|
||||
|
||||
private void queryConversation(ConversationInfo data) {
|
||||
ConversationRepoAll.INSTANCE.getSessionList(
|
||||
data,
|
||||
PAGE_LIMIT,
|
||||
new FetchCallback<List<ConversationInfo>>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable List<ConversationInfo> param) {
|
||||
FetchResult<List<ConversationBean>> result = new FetchResult<>(LoadStatus.Success);
|
||||
if (data != null) {
|
||||
result.setLoadStatus(LoadStatus.Finish);
|
||||
}
|
||||
List<ConversationBean> resultData = new ArrayList<>();
|
||||
for (int index = 0; param != null && index < param.size(); index++) {
|
||||
resultData.add(conversationFactory.CreateBean(param.get(index)));
|
||||
ALog.d(
|
||||
LIB_TAG, TAG, "queryConversation,onSuccess:" + param.get(index).getContactId());
|
||||
}
|
||||
hasMore = param != null && param.size() == PAGE_LIMIT;
|
||||
result.setData(resultData);
|
||||
queryLiveData.postValue(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int code) {}
|
||||
|
||||
@Override
|
||||
public void onException(@Nullable Throwable exception) {}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hasMore() {
|
||||
return hasMore;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal.viewholder;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import com.netease.yunxin.kit.common.ui.utils.TimeFormatUtils;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationKitClient;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationUIConfig;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.TimeConversationUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.ConversationViewHolderBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
|
||||
public class ConversationBaseViewHolder extends BaseViewHolder<ConversationBean> {
|
||||
|
||||
protected ConversationViewHolderBinding viewBinding;
|
||||
protected Drawable stickTopDrawable;
|
||||
protected Drawable itemDrawable;
|
||||
|
||||
public ConversationBaseViewHolder(@NonNull ConversationViewHolderBinding binding) {
|
||||
super(binding.getRoot());
|
||||
viewBinding = binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindData(ConversationBean data, int position) {
|
||||
loadUIConfig();
|
||||
|
||||
if (data.infoData.isStickTop()) {
|
||||
viewBinding.rootView.setBackground(stickTopDrawable);
|
||||
} else {
|
||||
viewBinding.rootView.setBackground(itemDrawable);
|
||||
}
|
||||
|
||||
viewBinding.messageTv.setText(
|
||||
ConversationUtils.getConversationText(viewBinding.getRoot().getContext(), data.infoData));
|
||||
viewBinding.timeTv.setText(
|
||||
TimeConversationUtils.formatMillisecond(
|
||||
viewBinding.getRoot().getContext(), data.infoData.getTime()));
|
||||
|
||||
if (data.infoData.getMute()) {
|
||||
viewBinding.muteIv.setVisibility(View.VISIBLE);
|
||||
viewBinding.unreadTv.setVisibility(View.GONE);
|
||||
} else {
|
||||
viewBinding.muteIv.setVisibility(View.GONE);
|
||||
if (data.infoData.getUnreadCount() > 0) {
|
||||
int count = data.infoData.getUnreadCount();
|
||||
String content;
|
||||
if (count >= 100) {
|
||||
content = "99+";
|
||||
} else {
|
||||
content = String.valueOf(count);
|
||||
}
|
||||
viewBinding.unreadTv.setText(content);
|
||||
viewBinding.unreadTv.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
viewBinding.unreadTv.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
viewBinding.contentLayout.setOnClickListener(v -> itemListener.onClick(v, data, position));
|
||||
// viewBinding.contentLayout.setOnLongClickListener(
|
||||
// v -> itemListener.onLongClick(v, data, position));
|
||||
viewBinding.avatarLayout.setOnClickListener(v -> itemListener.onAvatarClick(v, data, position));
|
||||
viewBinding.avatarLayout.setOnLongClickListener(
|
||||
v -> itemListener.onAvatarLongClick(v, data, position));
|
||||
}
|
||||
|
||||
private void loadUIConfig() {
|
||||
itemDrawable =
|
||||
ResourcesCompat.getDrawable(
|
||||
viewBinding.getRoot().getContext().getResources(),
|
||||
R.drawable.conversation_view_holder_selector,
|
||||
null);
|
||||
|
||||
stickTopDrawable =
|
||||
ResourcesCompat.getDrawable(
|
||||
viewBinding.getRoot().getContext().getResources(),
|
||||
R.drawable.conversation_view_holder_stick_selector,
|
||||
null);
|
||||
if (ConversationKitClient.getConversationUIConfig() != null) {
|
||||
ConversationUIConfig config = ConversationKitClient.getConversationUIConfig();
|
||||
if (config.itemTitleColor != null) {
|
||||
viewBinding.nameTv.setTextColor(config.itemTitleColor);
|
||||
}
|
||||
if (config.itemTitleSize != null) {
|
||||
viewBinding.nameTv.setTextSize(config.itemTitleSize);
|
||||
}
|
||||
|
||||
if (config.itemContentColor != null) {
|
||||
viewBinding.messageTv.setTextColor(config.itemContentColor);
|
||||
}
|
||||
if (config.itemContentSize != null) {
|
||||
viewBinding.messageTv.setTextSize(config.itemContentSize);
|
||||
}
|
||||
|
||||
if (config.itemDateColor != null) {
|
||||
viewBinding.timeTv.setTextColor(config.itemDateColor);
|
||||
}
|
||||
if (config.itemDateSize != null) {
|
||||
viewBinding.timeTv.setTextSize(config.itemDateSize);
|
||||
}
|
||||
|
||||
if (config.avatarCornerRadius != null) {
|
||||
viewBinding.avatarView.setCornerRadius(config.avatarCornerRadius);
|
||||
}
|
||||
if (config.itemBackground != null) {
|
||||
itemDrawable = config.itemBackground;
|
||||
}
|
||||
if (config.itemStickTopBackground != null) {
|
||||
stickTopDrawable = config.itemStickTopBackground;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal.viewholder;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.netease.yunxin.kit.common.ui.utils.AvatarColor;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.ConversationViewHolderBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
|
||||
public class ConversationP2PViewHolder extends ConversationBaseViewHolder {
|
||||
public ConversationP2PViewHolder(@NonNull ConversationViewHolderBinding binding) {
|
||||
super(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindData(ConversationBean data, int position) {
|
||||
super.onBindData(data, position);
|
||||
String name = data.infoData.getName();
|
||||
viewBinding.avatarView.setData(
|
||||
data.infoData.getAvatar(),
|
||||
data.infoData.getAvatarName(),
|
||||
AvatarColor.avatarColor(data.infoData.getContactId()));
|
||||
viewBinding.nameTv.setText(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal.viewholder;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.yunxin.kit.common.ui.utils.AvatarColor;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationHelper;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.ConversationViewHolderBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
|
||||
public class ConversationTeamViewHolder extends ConversationBaseViewHolder {
|
||||
|
||||
public ConversationTeamViewHolder(@NonNull ConversationViewHolderBinding binding) {
|
||||
super(binding);
|
||||
}
|
||||
|
||||
@SuppressLint("UseCompatLoadingForDrawables")
|
||||
@Override
|
||||
public void onBindData(ConversationBean data, int position) {
|
||||
super.onBindData(data, position);
|
||||
if (data.infoData.getTeamInfo() != null) {
|
||||
Team teamInfo = data.infoData.getTeamInfo();
|
||||
viewBinding.avatarView.setData(
|
||||
teamInfo.getIcon(), teamInfo.getName(), AvatarColor.avatarColor(teamInfo.getId()));
|
||||
viewBinding.nameTv.setText(teamInfo.getName());
|
||||
}
|
||||
if (ConversationHelper.hasAit(data.infoData.getContactId())
|
||||
&& data.infoData.getUnreadCount() > 0) {
|
||||
viewBinding.aitTv.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
viewBinding.aitTv.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.normal.viewholder;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.netease.yunxin.kit.common.ui.utils.AvatarColor;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.SelectorViewHolderLayoutBinding;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
|
||||
public class SelectorViewHolder extends BaseViewHolder<ConversationBean> {
|
||||
|
||||
private SelectorViewHolderLayoutBinding viewBinding;
|
||||
|
||||
public SelectorViewHolder(@NonNull ViewGroup itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
public SelectorViewHolder(@NonNull SelectorViewHolderLayoutBinding binding) {
|
||||
this(binding.getRoot());
|
||||
viewBinding = binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindData(ConversationBean data, int position) {
|
||||
viewBinding.avatarView.setData(
|
||||
data.infoData.getAvatar(),
|
||||
data.infoData.getName(),
|
||||
AvatarColor.avatarColor(data.infoData.getContactId()));
|
||||
viewBinding.conversationNameTv.setText(data.infoData.getName());
|
||||
viewBinding.rootView.setOnClickListener(
|
||||
v -> {
|
||||
viewBinding.conversationSelectorCb.setChecked(
|
||||
!viewBinding.conversationSelectorCb.isChecked());
|
||||
if (itemListener != null) {
|
||||
int check = viewBinding.conversationSelectorCb.isChecked() ? 1 : 0;
|
||||
itemListener.onClick(v, data, check);
|
||||
}
|
||||
});
|
||||
viewBinding.rootView.setOnLongClickListener(
|
||||
v -> {
|
||||
if (itemListener != null) {
|
||||
return itemListener.onLongClick(v, data, position);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,576 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.page;
|
||||
|
||||
import static com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant.LIB_TAG;
|
||||
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.netease.nimlib.sdk.friend.model.MuteListChangedNotify;
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.yunxin.kit.alog.ALog;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.common.ui.action.ActionItem;
|
||||
import com.netease.yunxin.kit.common.ui.dialog.ListAlertDialog;
|
||||
import com.netease.yunxin.kit.common.ui.fragments.BaseFragment;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseBean;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.ViewHolderClickListener;
|
||||
import com.netease.yunxin.kit.common.ui.viewmodel.FetchResult;
|
||||
import com.netease.yunxin.kit.common.ui.viewmodel.LoadStatus;
|
||||
import com.netease.yunxin.kit.common.ui.widgets.TitleBarView;
|
||||
import com.netease.yunxin.kit.common.utils.NetworkUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationKitClient;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.IConversationFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationHelper;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.interfaces.IConversationCallback;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.interfaces.ILoadListener;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.viewmodel.ConversationViewModel;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.view.ConversationView;
|
||||
import com.netease.yunxin.kit.corekit.im.model.FriendInfo;
|
||||
import com.netease.yunxin.kit.corekit.im.model.UserInfo;
|
||||
import com.netease.yunxin.kit.corekit.route.XKitRouter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* conversation list fragment show your recent conversation
|
||||
*/
|
||||
public abstract class ConversationBaseFragment extends BaseFragment implements ILoadListener {
|
||||
|
||||
private final String TAG = "ConversationFragment";
|
||||
public ConversationViewModel viewModel;
|
||||
private IConversationCallback conversationCallback;
|
||||
|
||||
private Observer<FetchResult<List<ConversationBean>>> changeObserver;
|
||||
private Observer<FetchResult<ConversationBean>> stickObserver;
|
||||
private Observer<FetchResult<List<UserInfo>>> userInfoObserver;
|
||||
private Observer<FetchResult<List<FriendInfo>>> friendInfoObserver;
|
||||
private Observer<FetchResult<List<Team>>> teamInfoObserver;
|
||||
private Observer<FetchResult<MuteListChangedNotify>> muteObserver;
|
||||
private Observer<FetchResult<String>> addRemoveStickObserver;
|
||||
private Observer<FetchResult<List<String>>> aitObserver;
|
||||
private Observer<FetchResult<Integer>> unreadCountObserver;
|
||||
|
||||
protected IConversationFactory conversationFactory;
|
||||
|
||||
protected ConversationView conversationView;
|
||||
|
||||
protected TitleBarView titleBarView;
|
||||
|
||||
protected View networkErrorView;
|
||||
|
||||
protected View emptyView;
|
||||
|
||||
private long msgUnreadCountTime = 0;
|
||||
|
||||
public final long MSG_UNREAD_COUNT_INTERVAL = 1000;
|
||||
|
||||
private Handler conversationHandler = new Handler();
|
||||
|
||||
public ConversationChangeListener conversationChangeListener;
|
||||
|
||||
public void setConversationChangeListener(ConversationChangeListener listener) {
|
||||
conversationChangeListener = listener;
|
||||
}
|
||||
|
||||
public interface ConversationChangeListener {
|
||||
void onChange(FetchResult<List<ConversationBean>> result);
|
||||
}
|
||||
|
||||
public abstract View initViewAndGetRootView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState);
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
return initViewAndGetRootView(inflater, container, savedInstanceState);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
viewModel = new ViewModelProvider(this).get(ConversationViewModel.class);
|
||||
viewModel.setComparator(conversationComparator);
|
||||
if (conversationFactory != null) {
|
||||
viewModel.setConversationFactory(conversationFactory);
|
||||
}
|
||||
viewModel
|
||||
.getQueryLiveData()
|
||||
.observe(
|
||||
this.getViewLifecycleOwner(),
|
||||
result -> {
|
||||
if (conversationView != null) {
|
||||
if (result.getLoadStatus() == LoadStatus.Success) {
|
||||
conversationView.setData(result.getData());
|
||||
} else if (result.getLoadStatus() == LoadStatus.Finish) {
|
||||
conversationView.addData(result.getData());
|
||||
}
|
||||
|
||||
if (emptyView != null) {
|
||||
if (conversationView.getDataSize() > 0) {
|
||||
emptyView.setVisibility(View.GONE);
|
||||
} else {
|
||||
emptyView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (conversationChangeListener != null) {
|
||||
conversationChangeListener.onChange(result);
|
||||
}
|
||||
doCallback();
|
||||
});
|
||||
initObserver();
|
||||
bindView();
|
||||
if (networkErrorView != null) {
|
||||
NetworkUtils.registerNetworkStatusChangedListener(networkStateListener);
|
||||
}
|
||||
registerObserver();
|
||||
viewModel.fetchConversation();
|
||||
}
|
||||
|
||||
public void bindView() {
|
||||
//设置会话排序Comparator,默认按照置顶和时间优先级进行排序
|
||||
if (conversationView != null) {
|
||||
conversationView.setComparator(conversationComparator);
|
||||
conversationView.setLoadMoreListener(this);
|
||||
conversationView.setItemClickListener(
|
||||
new ViewHolderClickListener() {
|
||||
@Override
|
||||
public boolean onClick(View v, BaseBean data, int position) {
|
||||
boolean result = false;
|
||||
if (ConversationKitClient.getConversationUIConfig() != null
|
||||
&& ConversationKitClient.getConversationUIConfig().itemClickListener != null
|
||||
&& data instanceof ConversationBean) {
|
||||
result =
|
||||
ConversationKitClient.getConversationUIConfig()
|
||||
.itemClickListener
|
||||
.onClick(
|
||||
ConversationBaseFragment.this.getContext(),
|
||||
(ConversationBean) data,
|
||||
position);
|
||||
}
|
||||
if (!result && !TextUtils.isEmpty(data.router)) {
|
||||
XKitRouter.withKey(data.router)
|
||||
.withParam(data.paramKey, data.param)
|
||||
.withContext(ConversationBaseFragment.this.requireContext())
|
||||
.navigate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAvatarClick(View v, BaseBean data, int position) {
|
||||
boolean result = false;
|
||||
if (ConversationKitClient.getConversationUIConfig() != null
|
||||
&& ConversationKitClient.getConversationUIConfig().itemClickListener != null
|
||||
&& data instanceof ConversationBean) {
|
||||
result =
|
||||
ConversationKitClient.getConversationUIConfig()
|
||||
.itemClickListener
|
||||
.onAvatarClick(
|
||||
ConversationBaseFragment.this.getContext(),
|
||||
(ConversationBean) data,
|
||||
position);
|
||||
}
|
||||
if (!result) {
|
||||
XKitRouter.withKey(data.router)
|
||||
.withParam(data.paramKey, data.param)
|
||||
.withContext(ConversationBaseFragment.this.requireContext())
|
||||
.navigate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v, BaseBean data, int position) {
|
||||
boolean result = false;
|
||||
if (ConversationKitClient.getConversationUIConfig() != null
|
||||
&& ConversationKitClient.getConversationUIConfig().itemClickListener != null
|
||||
&& data instanceof ConversationBean) {
|
||||
result =
|
||||
ConversationKitClient.getConversationUIConfig()
|
||||
.itemClickListener
|
||||
.onLongClick(
|
||||
ConversationBaseFragment.this.getContext(),
|
||||
(ConversationBean) data,
|
||||
position);
|
||||
}
|
||||
if (!result) {
|
||||
showStickDialog(data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAvatarLongClick(View v, BaseBean data, int position) {
|
||||
boolean result = false;
|
||||
if (ConversationKitClient.getConversationUIConfig() != null
|
||||
&& ConversationKitClient.getConversationUIConfig().itemClickListener != null
|
||||
&& data instanceof ConversationBean) {
|
||||
result =
|
||||
ConversationKitClient.getConversationUIConfig()
|
||||
.itemClickListener
|
||||
.onAvatarLongClick(
|
||||
ConversationBaseFragment.this.getContext(),
|
||||
(ConversationBean) data,
|
||||
position);
|
||||
}
|
||||
if (!result) {
|
||||
showStickDialog(data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewHolderFactory(IConversationFactory factory) {
|
||||
conversationFactory = factory;
|
||||
if (viewModel != null) {
|
||||
viewModel.setConversationFactory(factory);
|
||||
}
|
||||
if (conversationView != null) {
|
||||
conversationView.setViewHolderFactory(factory);
|
||||
}
|
||||
}
|
||||
|
||||
public void setComparator(Comparator<ConversationInfo> comparator) {
|
||||
if (comparator != null) {
|
||||
conversationComparator = comparator;
|
||||
if (viewModel != null) {
|
||||
viewModel.setComparator(
|
||||
ConversationKitClient.getConversationUIConfig().conversationComparator);
|
||||
}
|
||||
|
||||
if (conversationView != null) {
|
||||
conversationView.setComparator(
|
||||
ConversationKitClient.getConversationUIConfig().conversationComparator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initObserver() {
|
||||
changeObserver =
|
||||
result -> {
|
||||
if (conversationView != null) {
|
||||
if (result.getLoadStatus() == LoadStatus.Success) {
|
||||
ALog.d(LIB_TAG, TAG, "ChangeLiveData, Success");
|
||||
for (ConversationBean bean : result.getData()) {
|
||||
if (TextUtils.isEmpty(bean.infoData.getContent())) {
|
||||
result.getData().remove(bean);
|
||||
}
|
||||
}
|
||||
if (result.getData().size() > 0) {
|
||||
conversationView.update(result.getData());
|
||||
}
|
||||
|
||||
} else if (result.getLoadStatus() == LoadStatus.Finish
|
||||
&& result.getType() == FetchResult.FetchType.Remove) {
|
||||
ALog.d(LIB_TAG, TAG, "DeleteLiveData, Success");
|
||||
if (result.getData() == null || result.getData().size() < 1) {
|
||||
conversationView.removeAll();
|
||||
} else {
|
||||
conversationView.remove(result.getData());
|
||||
}
|
||||
}
|
||||
if (emptyView != null) {
|
||||
if (conversationView.getDataSize() > 0) {
|
||||
emptyView.setVisibility(View.GONE);
|
||||
} else {
|
||||
emptyView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (conversationChangeListener != null) {
|
||||
conversationChangeListener.onChange(result);
|
||||
}
|
||||
doCallback();
|
||||
};
|
||||
|
||||
stickObserver =
|
||||
result -> {
|
||||
if (result.getLoadStatus() == LoadStatus.Success && conversationView != null) {
|
||||
ALog.d(LIB_TAG, TAG, "StickLiveData, Success");
|
||||
conversationView.update(result.getData());
|
||||
}
|
||||
doCallback();
|
||||
};
|
||||
|
||||
userInfoObserver =
|
||||
result -> {
|
||||
if (result.getLoadStatus() == LoadStatus.Success && conversationView != null) {
|
||||
ALog.d(LIB_TAG, TAG, "UserInfoLiveData, Success");
|
||||
conversationView.updateUserInfo(result.getData());
|
||||
}
|
||||
};
|
||||
|
||||
friendInfoObserver =
|
||||
result -> {
|
||||
if (result.getLoadStatus() == LoadStatus.Success && conversationView != null) {
|
||||
ALog.d(LIB_TAG, TAG, "FriendInfoLiveData, Success");
|
||||
conversationView.updateFriendInfo(result.getData());
|
||||
}
|
||||
};
|
||||
|
||||
teamInfoObserver =
|
||||
result -> {
|
||||
if (result.getLoadStatus() == LoadStatus.Success && conversationView != null) {
|
||||
ALog.d(LIB_TAG, TAG, "TeamInfoLiveData, Success");
|
||||
conversationView.updateTeamInfo(result.getData());
|
||||
}
|
||||
};
|
||||
|
||||
muteObserver =
|
||||
result -> {
|
||||
if (result.getLoadStatus() == LoadStatus.Success && conversationView != null) {
|
||||
ALog.d(LIB_TAG, TAG, "MuteInfoLiveData, Success");
|
||||
conversationView.updateMuteInfo(result.getData());
|
||||
}
|
||||
};
|
||||
|
||||
aitObserver =
|
||||
result -> {
|
||||
if (result.getLoadStatus() == LoadStatus.Finish) {
|
||||
if (result.getType() == FetchResult.FetchType.Add && conversationView != null) {
|
||||
ALog.d(LIB_TAG, TAG, "AddStickLiveData, Success");
|
||||
ConversationHelper.updateAitInfo(result.getData(), true);
|
||||
conversationView.updateAit(result.getData());
|
||||
} else if (result.getType() == FetchResult.FetchType.Remove
|
||||
&& conversationView != null) {
|
||||
ALog.d(LIB_TAG, TAG, "RemoveStickLiveData, Success");
|
||||
ConversationHelper.updateAitInfo(result.getData(), false);
|
||||
conversationView.updateAit(result.getData());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addRemoveStickObserver =
|
||||
result -> {
|
||||
if (result.getLoadStatus() == LoadStatus.Finish) {
|
||||
if (result.getType() == FetchResult.FetchType.Add && conversationView != null) {
|
||||
ALog.d(LIB_TAG, TAG, "AddStickLiveData, Success");
|
||||
conversationView.addStickTop(result.getData());
|
||||
} else if (result.getType() == FetchResult.FetchType.Remove
|
||||
&& conversationView != null) {
|
||||
ALog.d(LIB_TAG, TAG, "RemoveStickLiveData, Success");
|
||||
conversationView.removeStickTop(result.getData());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
unreadCountObserver =
|
||||
result -> {
|
||||
if (result.getLoadStatus() == LoadStatus.Success) {
|
||||
ALog.d(LIB_TAG, TAG, "unreadCount, Success");
|
||||
if (conversationCallback != null) {
|
||||
conversationCallback.updateUnreadCount(
|
||||
result.getData() == null ? 0 : result.getData());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
if (conversationView != null) {
|
||||
conversationView.setShowTag(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
if (conversationView != null) {
|
||||
conversationView.setShowTag(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerObserver() {
|
||||
viewModel.getChangeLiveData().observeForever(changeObserver);
|
||||
viewModel.getStickLiveData().observeForever(stickObserver);
|
||||
viewModel.getUserInfoLiveData().observeForever(userInfoObserver);
|
||||
viewModel.getFriendInfoLiveData().observeForever(friendInfoObserver);
|
||||
viewModel.getTeamInfoLiveData().observeForever(teamInfoObserver);
|
||||
viewModel.getMuteInfoLiveData().observeForever(muteObserver);
|
||||
viewModel.getAddRemoveStickLiveData().observeForever(addRemoveStickObserver);
|
||||
viewModel.getAitLiveData().observeForever(aitObserver);
|
||||
viewModel.getUnreadCountLiveData().observeForever(unreadCountObserver);
|
||||
}
|
||||
|
||||
private void unregisterObserver() {
|
||||
viewModel.getChangeLiveData().removeObserver(changeObserver);
|
||||
viewModel.getStickLiveData().removeObserver(stickObserver);
|
||||
viewModel.getUserInfoLiveData().removeObserver(userInfoObserver);
|
||||
viewModel.getFriendInfoLiveData().removeObserver(friendInfoObserver);
|
||||
viewModel.getTeamInfoLiveData().removeObserver(teamInfoObserver);
|
||||
viewModel.getMuteInfoLiveData().removeObserver(muteObserver);
|
||||
viewModel.getAddRemoveStickLiveData().removeObserver(addRemoveStickObserver);
|
||||
viewModel.getAitLiveData().removeObserver(aitObserver);
|
||||
viewModel.getUnreadCountLiveData().removeObserver(unreadCountObserver);
|
||||
}
|
||||
|
||||
public void setConversationCallback(IConversationCallback callback) {
|
||||
this.conversationCallback = callback;
|
||||
doCallback();
|
||||
}
|
||||
|
||||
public ConversationViewModel getViewModel() {
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
private void showStickDialog(BaseBean data) {
|
||||
if (data instanceof ConversationBean) {
|
||||
ConversationBean dataBean = (ConversationBean) data;
|
||||
ListAlertDialog alertDialog = new ListAlertDialog();
|
||||
alertDialog.setContent(generateDialogContent(dataBean.infoData.isStickTop()));
|
||||
alertDialog.setTitleVisibility(View.GONE);
|
||||
alertDialog.setDialogWidth(getResources().getDimension(R.dimen.alert_dialog_width));
|
||||
alertDialog.setItemClickListener(
|
||||
action -> {
|
||||
if (TextUtils.equals(action, ConversationConstant.Action.ACTION_DELETE)) {
|
||||
viewModel.deleteConversation(2, dataBean);
|
||||
} else if (TextUtils.equals(action, ConversationConstant.Action.ACTION_HIDE)) {
|
||||
viewModel.deleteConversation(1, dataBean);
|
||||
// if (dataBean.infoData.isStickTop()) {
|
||||
// viewModel.removeStick((ConversationBean) data);
|
||||
// } else {
|
||||
// viewModel.addStickTop((ConversationBean) data);
|
||||
// }
|
||||
}
|
||||
alertDialog.dismiss();
|
||||
});
|
||||
alertDialog.show(getParentFragmentManager());
|
||||
}
|
||||
}
|
||||
|
||||
private Comparator<ConversationInfo> conversationComparator =
|
||||
(bean1, bean2) -> {
|
||||
int result;
|
||||
if (bean1 == null) {
|
||||
result = 1;
|
||||
} else if (bean2 == null) {
|
||||
result = -1;
|
||||
} else if (bean1.isStickTop() == bean2.isStickTop()) {
|
||||
long time = bean1.getTime() - bean2.getTime();
|
||||
result = time == 0L ? 0 : (time > 0 ? -1 : 1);
|
||||
|
||||
} else {
|
||||
result = bean1.isStickTop() ? -1 : 1;
|
||||
}
|
||||
ALog.d(LIB_TAG, TAG, "conversationComparator, result:" + result);
|
||||
return result;
|
||||
};
|
||||
|
||||
protected List<ActionItem> generateDialogContent(boolean isStick) {
|
||||
List<ActionItem> contentList = new ArrayList<>();
|
||||
// ActionItem stick =
|
||||
// new ActionItem(
|
||||
// ConversationConstant.Action.ACTION_STICK,
|
||||
// 0,
|
||||
// (isStick ? R.string.cancel_stick_title : R.string.stick_title));
|
||||
ActionItem hide =
|
||||
new ActionItem(ConversationConstant.Action.ACTION_HIDE, 0, R.string.hide_title);
|
||||
ActionItem delete =
|
||||
new ActionItem(ConversationConstant.Action.ACTION_DELETE, 0, R.string.delete_title);
|
||||
contentList.add(hide);
|
||||
contentList.add(delete);
|
||||
return contentList;
|
||||
}
|
||||
|
||||
private void doCallback() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
ALog.d(LIB_TAG, TAG, "doCallback");
|
||||
if (viewModel != null && currentTime - msgUnreadCountTime > MSG_UNREAD_COUNT_INTERVAL) {
|
||||
msgUnreadCountTime = currentTime;
|
||||
conversationHandler.removeCallbacks(msgUnreadCountRunnable);
|
||||
viewModel.getUnreadCount();
|
||||
ALog.d(LIB_TAG, TAG, "doCallback:getUnreadCount");
|
||||
} else if (viewModel != null && conversationHandler != null) {
|
||||
ALog.d(LIB_TAG, TAG, "doCallback:conversationHandler");
|
||||
conversationHandler.removeCallbacks(msgUnreadCountRunnable);
|
||||
conversationHandler.postDelayed(msgUnreadCountRunnable, MSG_UNREAD_COUNT_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable msgUnreadCountRunnable =
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (viewModel != null) {
|
||||
viewModel.getUnreadCount();
|
||||
ALog.d(LIB_TAG, TAG, "msgUnreadCountRunnable:getUnreadCount");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
if (networkErrorView != null) {
|
||||
NetworkUtils.unregisterNetworkStatusChangedListener(networkStateListener);
|
||||
}
|
||||
unregisterObserver();
|
||||
}
|
||||
|
||||
private final NetworkUtils.NetworkStateListener networkStateListener =
|
||||
new NetworkUtils.NetworkStateListener() {
|
||||
@Override
|
||||
public void onAvailable(NetworkInfo network) {
|
||||
if (networkErrorView == null) {
|
||||
return;
|
||||
}
|
||||
networkErrorView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLost(NetworkInfo network) {
|
||||
if (networkErrorView == null) {
|
||||
return;
|
||||
}
|
||||
networkErrorView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean hasMore() {
|
||||
return viewModel.hasMore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMore(Object last) {
|
||||
if (last instanceof ConversationBean) {
|
||||
viewModel.loadMore((ConversationBean) last);
|
||||
}
|
||||
}
|
||||
|
||||
public ConversationView getConversationView() {
|
||||
return conversationView;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.page;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseViewHolder;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.IConversationFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
|
||||
/** conversation view holder factory to create view holder in recyclerview */
|
||||
public class DefaultViewHolderFactory implements IConversationFactory {
|
||||
|
||||
@Override
|
||||
public ConversationBean CreateBean(ConversationInfo info) {
|
||||
return new ConversationBean(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(ConversationBean data) {
|
||||
return data.viewType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseViewHolder<ConversationBean> createViewHolder(
|
||||
@NonNull ViewGroup parent, int viewType) {
|
||||
return new BaseViewHolder<ConversationBean>(new View(parent.getContext())) {
|
||||
@Override
|
||||
public void onBindData(ConversationBean data, int position) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.page.interfaces;
|
||||
|
||||
/** conversation callback to observer the unread count change */
|
||||
public interface IConversationCallback {
|
||||
|
||||
void updateUnreadCount(int count);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.page.interfaces;
|
||||
|
||||
/** load listener */
|
||||
public interface ILoadListener {
|
||||
|
||||
boolean hasMore();
|
||||
|
||||
void loadMore(Object last);
|
||||
}
|
||||
@@ -0,0 +1,756 @@
|
||||
/*
|
||||
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
* Use of this source code is governed by a MIT license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package com.netease.yunxin.kit.chatkit.repo
|
||||
|
||||
import com.netease.nimlib.sdk.Observer
|
||||
import com.netease.nimlib.sdk.friend.model.MuteListChangedNotify
|
||||
import com.netease.nimlib.sdk.msg.constant.DeleteTypeEnum
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum
|
||||
import com.netease.nimlib.sdk.msg.model.QueryDirectionEnum
|
||||
import com.netease.nimlib.sdk.msg.model.RecentContact
|
||||
import com.netease.nimlib.sdk.msg.model.StickTopSessionInfo
|
||||
import com.netease.nimlib.sdk.team.constant.TeamMessageNotifyTypeEnum
|
||||
import com.netease.nimlib.sdk.team.model.Team
|
||||
import com.netease.yunxin.kit.alog.ALog
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo
|
||||
import com.netease.yunxin.kit.chatkit.utils.ChatKitConstant
|
||||
import com.netease.yunxin.kit.corekit.im.model.EventObserver
|
||||
import com.netease.yunxin.kit.corekit.im.model.UserInfo
|
||||
import com.netease.yunxin.kit.corekit.im.provider.FetchCallback
|
||||
import com.netease.yunxin.kit.corekit.im.provider.FriendObserver
|
||||
import com.netease.yunxin.kit.corekit.im.provider.FriendObserverProvider
|
||||
import com.netease.yunxin.kit.corekit.im.provider.FriendProvider
|
||||
import com.netease.yunxin.kit.corekit.im.provider.MessageObserverProvider
|
||||
import com.netease.yunxin.kit.corekit.im.provider.MessageProvider
|
||||
import com.netease.yunxin.kit.corekit.im.provider.TeamObserverProvider
|
||||
import com.netease.yunxin.kit.corekit.im.provider.TeamProvider
|
||||
import com.netease.yunxin.kit.corekit.im.provider.UserInfoObserver
|
||||
import com.netease.yunxin.kit.corekit.im.provider.UserInfoProvider
|
||||
import com.netease.yunxin.kit.corekit.im.utils.toDispatchInform
|
||||
import com.netease.yunxin.kit.corekit.im.utils.toInform
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
object ConversationRepoAll {
|
||||
|
||||
private const val TAG = "ConversationRepoAll"
|
||||
private const val LIB_TAG = "ConversationKit"
|
||||
|
||||
/**
|
||||
* 查询会话列表,废弃
|
||||
*/
|
||||
|
||||
@JvmStatic
|
||||
fun getSessionList(limit: Int, callback: FetchCallback<List<ConversationInfo>?>) {
|
||||
ALog.d(LIB_TAG, TAG, "getSessionList:$limit")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
MessageProvider.queryRecentConversationList(limit).toDispatchInform(callback) {
|
||||
val conversationList = convertToConversationInfo(it)
|
||||
clearDismissTeamSession(conversationList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有会话列表,把IM本地保存的会话信息全部查询出来。
|
||||
* @param callback 异步查询,查询结果在调用线程回调。查询结果回话类型为P2P,则`ConversationInfo`包含`RecentContact
|
||||
* `和会话对方的`UserInfo`,如果会话类型为Team,则`ConversationInfo`包含`RecentContact`和`Team`信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getAllSessionList(callback: FetchCallback<List<ConversationInfo>?>) {
|
||||
ALog.d(LIB_TAG, TAG, "getAllSessionList")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
MessageProvider.queryAllRecentConversationList().toDispatchInform(callback) {
|
||||
val conversationList = convertToConversationInfo(it)
|
||||
val result = clearDismissTeamSession(conversationList)
|
||||
sortSessionList(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询会话列表,支持传入Comparator对会话列表进行排序,查询更早的会话列表
|
||||
* @param anchor 查询下一页会话列表的起始会话
|
||||
* @param limit 获取本地会话的数量 最大100,超过100修正到100
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSessionList(
|
||||
anchor: ConversationInfo?,
|
||||
limit: Int,
|
||||
comparator: Comparator<ConversationInfo>?,
|
||||
callback: FetchCallback<List<ConversationInfo>?>
|
||||
) {
|
||||
ALog.d(LIB_TAG, TAG, "getContactList:${anchor?.contactId},$limit")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
MessageProvider.queryRecentConversationList(anchor, QueryDirectionEnum.QUERY_OLD, limit)
|
||||
.toDispatchInform(callback) { infoList ->
|
||||
val conversationList = convertToConversationInfo(infoList)
|
||||
val result = clearDismissTeamSession(conversationList)
|
||||
if (comparator != null) {
|
||||
result.sortedWith(comparator)
|
||||
} else {
|
||||
sortSessionList(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询会话列表,排序方式按照置顶会话+最近会话时间进行排序
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSessionList(
|
||||
anchor: ConversationInfo?,
|
||||
limit: Int,
|
||||
callback: FetchCallback<List<ConversationInfo>?>
|
||||
) {
|
||||
ALog.d(LIB_TAG, TAG, "getContactList:${anchor?.contactId},$limit")
|
||||
this.getSessionList(anchor, limit, null, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* 最近会话排序,排序规则置顶>最近消息时间
|
||||
*/
|
||||
fun sortSessionList(conversationList: List<ConversationInfo>): List<ConversationInfo> {
|
||||
if (conversationList.size > 1) {
|
||||
return conversationList.sortedWith(object : Comparator<ConversationInfo> {
|
||||
override fun compare(info1: ConversationInfo?, info2: ConversationInfo?): Int {
|
||||
if (info1 == null) {
|
||||
return 1
|
||||
}
|
||||
if (info2 == null) {
|
||||
return -1
|
||||
}
|
||||
return if (info1.isStickTop == info2.isStickTop) {
|
||||
val time = info1.time - info2.time
|
||||
if (time == 0L) {
|
||||
0
|
||||
} else if (time > 0) {
|
||||
-1
|
||||
} else {
|
||||
1
|
||||
}
|
||||
} else {
|
||||
if (info1.isStickTop) -1 else 1
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return conversationList
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加会话置顶
|
||||
*/
|
||||
@JvmStatic
|
||||
fun addStickTop(
|
||||
sessionId: String,
|
||||
typeEnum: SessionTypeEnum,
|
||||
ext: String? = "",
|
||||
callback: FetchCallback<StickTopSessionInfo>
|
||||
) {
|
||||
ALog.d(LIB_TAG, TAG, "addStickTop:$sessionId")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
MessageProvider.addStickTop(sessionId, typeEnum, ext).toDispatchInform(callback) {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询会话是否置顶
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isStickTop(
|
||||
sessionId: String,
|
||||
typeEnum: SessionTypeEnum
|
||||
): Boolean {
|
||||
ALog.d(LIB_TAG, TAG, "isStickTop:$sessionId")
|
||||
return MessageProvider.isStickSession(sessionId, typeEnum)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询会话是否置顶
|
||||
*/
|
||||
fun isStickTop(sessionId: String, typeEnum: SessionTypeEnum, callback: FetchCallback<Boolean>) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val result = MessageProvider.isStickSession(sessionId, typeEnum)
|
||||
ALog.d(LIB_TAG, TAG, "isStickTop:$result")
|
||||
withContext(Dispatchers.Main) {
|
||||
callback.onSuccess(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除置顶
|
||||
*/
|
||||
@JvmStatic
|
||||
fun removeStickTop(
|
||||
sessionId: String,
|
||||
typeEnum: SessionTypeEnum,
|
||||
ext: String? = "",
|
||||
callback: FetchCallback<Void>?
|
||||
) {
|
||||
ALog.d(LIB_TAG, TAG, "removeStickTop:$sessionId")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
MessageProvider.removeStickTop(sessionId, typeEnum, ext).toDispatchInform(callback) {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除会话
|
||||
*/
|
||||
@JvmStatic
|
||||
fun deleteSession(
|
||||
sessionId: String,
|
||||
typeEnum: SessionTypeEnum,
|
||||
deleteTypeEnum: DeleteTypeEnum,
|
||||
sendAck: Boolean,
|
||||
callback: FetchCallback<Void>?
|
||||
) {
|
||||
ALog.d(LIB_TAG, TAG, "deleteSession:$sessionId,${deleteTypeEnum.value}")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
MessageProvider.deleteConversation(sessionId, typeEnum, deleteTypeEnum, sendAck)
|
||||
.toDispatchInform(callback) {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息未读数
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getMsgUnreadCount(): Int {
|
||||
val result = MessageProvider.getMsgUnreadCount()
|
||||
ALog.d(LIB_TAG, TAG, "getMsgUnreadCount")
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步获取消息未读数
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getMsgUnreadCountAsync(callback: FetchCallback<Int>?) {
|
||||
try {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
ALog.d(LIB_TAG, TAG, "getMsgUnreadCount")
|
||||
val result = MessageProvider.getMsgUnreadCount()
|
||||
withContext(Dispatchers.Main) {
|
||||
callback?.onSuccess(result)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
callback?.onException(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否打开消息提醒
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isNotify(sessionId: String, sessionTypeEnum: SessionTypeEnum): Boolean {
|
||||
var result = false
|
||||
if (sessionTypeEnum == SessionTypeEnum.P2P) {
|
||||
result = FriendProvider.isNotify(sessionId)
|
||||
} else if (sessionTypeEnum == SessionTypeEnum.Team) {
|
||||
result = !TeamProvider.getTeamById(sessionId).isAllMute
|
||||
}
|
||||
ALog.d(ChatKitConstant.LIB_TAG, TAG, "isNotify${sessionId}$result")
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否打开消息提醒
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isNotify(
|
||||
sessionId: String,
|
||||
sessionTypeEnum: SessionTypeEnum,
|
||||
callback: FetchCallback<Boolean>
|
||||
) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
var result = false
|
||||
if (sessionTypeEnum == SessionTypeEnum.P2P) {
|
||||
result = FriendProvider.isNotify(sessionId)
|
||||
} else if (sessionTypeEnum == SessionTypeEnum.Team) {
|
||||
result = !TeamProvider.getTeamById(sessionId).isAllMute
|
||||
}
|
||||
ALog.d(ChatKitConstant.LIB_TAG, TAG, "isNotify${sessionId}$result")
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
callback.onSuccess(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置群消息不提醒
|
||||
*/
|
||||
@Deprecated(message = "user setNotify() to replace")
|
||||
@JvmStatic
|
||||
fun setTeamNotify(teamId: String, mute: Boolean, callback: FetchCallback<Void>?) {
|
||||
ALog.d(LIB_TAG, TAG, "setTeamNotify:$teamId,$mute")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
TeamProvider.muteTeam(
|
||||
teamId,
|
||||
if (mute) TeamMessageNotifyTypeEnum.Mute else TeamMessageNotifyTypeEnum.All
|
||||
).toDispatchInform(callback) { it }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置账号的消息提醒状态
|
||||
*/
|
||||
@JvmStatic
|
||||
fun setNotify(
|
||||
accId: String,
|
||||
sessionTypeEnum: SessionTypeEnum,
|
||||
notify: Boolean,
|
||||
callback: FetchCallback<Void>
|
||||
) {
|
||||
ALog.d(ChatKitConstant.LIB_TAG, TAG, "setNotify${accId}$notify")
|
||||
if (sessionTypeEnum == SessionTypeEnum.P2P) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
FriendProvider.setNotify(accId, notify).toDispatchInform(callback) {
|
||||
it
|
||||
}
|
||||
}
|
||||
} else if (sessionTypeEnum == SessionTypeEnum.Team) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
TeamProvider.muteTeam(
|
||||
accId,
|
||||
if (notify) TeamMessageNotifyTypeEnum.All else TeamMessageNotifyTypeEnum.Mute
|
||||
).toDispatchInform(callback) { it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知置顶变化
|
||||
*/
|
||||
@JvmStatic
|
||||
fun notifyStickTop(
|
||||
accId: String,
|
||||
sessionTypeEnum: SessionTypeEnum
|
||||
) {
|
||||
ALog.d(LIB_TAG, TAG, "notifyStickTop:$accId")
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
MessageProvider.notifyConversationStick(accId, sessionTypeEnum)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有未读消息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun clearAllUnreadCount() {
|
||||
ALog.d(LIB_TAG, TAG, "clearAllUnreadCount")
|
||||
MessageProvider.clearAllUnreadCount()
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话过滤,过滤掉已经删除的会话
|
||||
*/
|
||||
fun clearDismissTeamSession(conversationList: List<ConversationInfo>): List<ConversationInfo> {
|
||||
ALog.d(LIB_TAG, TAG, "filterSession:${conversationList?.size}")
|
||||
val result = arrayListOf<ConversationInfo>()
|
||||
conversationList.map { info ->
|
||||
// if (info.sessionType == SessionTypeEnum.Team &&
|
||||
// (info.teamInfo == null || info.teamInfo?.isMyTeam == false)
|
||||
// ) {
|
||||
// deleteSession(
|
||||
// info.contactId,
|
||||
// info.sessionType,
|
||||
// DeleteTypeEnum.LOCAL_AND_REMOTE,
|
||||
// true,
|
||||
// null
|
||||
// )
|
||||
// } else {
|
||||
// result.add(info)
|
||||
// }
|
||||
result.add(info)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 补充会话信息,会话列表中的个人信息和群组信息都在这里填充
|
||||
*/
|
||||
@JvmStatic
|
||||
suspend fun convertToConversationInfo(infoList: List<RecentContact>?): List<ConversationInfo> {
|
||||
ALog.d(LIB_TAG, TAG, "fillSessionInfo:${infoList?.size}")
|
||||
val teamList = mutableListOf<ConversationInfo>()
|
||||
val p2pList = mutableListOf<ConversationInfo>()
|
||||
val conversationList = mutableListOf<ConversationInfo>()
|
||||
val muteP2pList = FriendProvider.getMuteList()?.toHashSet()
|
||||
infoList?.map { info ->
|
||||
val conversationInfo = ConversationInfo(info)
|
||||
when (info.sessionType) {
|
||||
SessionTypeEnum.P2P -> {
|
||||
if (muteP2pList?.contains(conversationInfo.contactId) == true) {
|
||||
conversationInfo.mute = true
|
||||
}
|
||||
conversationList.add(conversationInfo)
|
||||
p2pList.add(conversationInfo)
|
||||
}
|
||||
|
||||
SessionTypeEnum.Team -> {
|
||||
conversationList.add(conversationInfo)
|
||||
teamList.add(conversationInfo)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
conversationInfo.isStickTop =
|
||||
MessageProvider.isStickSession(info.contactId, info.sessionType)
|
||||
}
|
||||
if (p2pList.size > 0) {
|
||||
fillUserInfo(p2pList)
|
||||
}
|
||||
if (teamList.size > 0) {
|
||||
fillTeamInfo(teamList)
|
||||
}
|
||||
return conversationList
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话信息中,补充用户信息
|
||||
*/
|
||||
@JvmStatic
|
||||
suspend fun fillUserInfo(conversationList: List<ConversationInfo>) {
|
||||
val conversationMap = mutableMapOf<String, ConversationInfo>()
|
||||
val userSet = mutableSetOf<String>()
|
||||
val friendInfoMap = FriendProvider.getFriendList().associateBy {
|
||||
it.account
|
||||
}
|
||||
conversationList.map { info ->
|
||||
info.friendInfo = friendInfoMap[info.contactId]
|
||||
val user = UserInfoProvider.getUserInfo(info.contactId)
|
||||
if (user != null) {
|
||||
info.userInfo = user
|
||||
} else {
|
||||
userSet.add(info.contactId)
|
||||
conversationMap[info.contactId] = info
|
||||
}
|
||||
}
|
||||
if (userSet.isNotEmpty()) {
|
||||
UserInfoProvider.fetchUserInfoCoroutine(userSet.toList())
|
||||
.toInform(object : FetchCallback<List<UserInfo>> {
|
||||
override fun onSuccess(param: List<UserInfo>?) {
|
||||
param?.map {
|
||||
conversationMap[it.account]?.userInfo = it
|
||||
}
|
||||
conversationMap.map {
|
||||
if (it.value.userInfo == null) {
|
||||
it.value.userInfo = UserInfo(it.key, it.key, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailed(code: Int) {
|
||||
ALog.d(LIB_TAG, TAG, "fillUserInfo,fetchUserInfoCoroutine,onFailed:$code")
|
||||
}
|
||||
|
||||
override fun onException(exception: Throwable?) {
|
||||
ALog.d(LIB_TAG, TAG, "fillUserInfo,fetchUserInfoCoroutine:onException")
|
||||
}
|
||||
}) { it }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话信息中,补充群组信息
|
||||
*/
|
||||
@JvmStatic
|
||||
suspend fun fillTeamInfo(conversationList: List<ConversationInfo>) {
|
||||
ALog.d(LIB_TAG, TAG, "fillTeamInfo:${conversationList?.size}")
|
||||
val conversationMap = mutableMapOf<String, ConversationInfo>()
|
||||
val teamSet = mutableSetOf<String>()
|
||||
for (info in conversationList) {
|
||||
teamSet.add(info.contactId)
|
||||
conversationMap[info.contactId] = info
|
||||
}
|
||||
TeamProvider.queryTeamListById(teamSet.toList())
|
||||
.toInform(object : FetchCallback<List<Team>> {
|
||||
override fun onSuccess(param: List<Team>?) {
|
||||
param?.map { team ->
|
||||
conversationMap[team.id]?.teamInfo = team
|
||||
conversationMap[team.id]?.mute =
|
||||
(team.messageNotifyType == TeamMessageNotifyTypeEnum.Mute)
|
||||
}
|
||||
ALog.d(
|
||||
LIB_TAG,
|
||||
TAG,
|
||||
"fillTeamConversationInfo,queryTeamListById,onSuccess:${param?.size}"
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFailed(code: Int) {
|
||||
ALog.d(
|
||||
LIB_TAG,
|
||||
TAG,
|
||||
"fillTeamConversationInfo,queryTeamListById,onFailed:$code"
|
||||
)
|
||||
}
|
||||
|
||||
override fun onException(exception: Throwable?) {
|
||||
ALog.d(LIB_TAG, TAG, "fillTeamConversationInfo,queryTeamListById,onException")
|
||||
}
|
||||
}) { it }
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册会话变化监听器
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "use ConversationObserverRepo.registerSessionChangedObserver() to replace"
|
||||
)
|
||||
@JvmStatic
|
||||
fun registerSessionChangedObserver(
|
||||
observer: EventObserver<List<ConversationInfo>>
|
||||
) {
|
||||
MessageObserverProvider.registerConversationChange(
|
||||
observer.getObserverInnerSuspend(
|
||||
convertCoroutineContext = Dispatchers.IO,
|
||||
convert = { itemList ->
|
||||
convertToConversationInfo(itemList)
|
||||
}
|
||||
),
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消会话变化监听器
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "use ConversationObserverRepo.unregisterSessionChangedObserver() to replace"
|
||||
)
|
||||
@JvmStatic
|
||||
fun unregisterSessionChangedObserver(
|
||||
observer: EventObserver<List<ConversationInfo>>
|
||||
) {
|
||||
MessageObserverProvider.registerConversationChange(
|
||||
observer.getObserverInner(),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册会话删除监听器
|
||||
*/
|
||||
@Deprecated(message = "use ConversationObserverRepo.registerSessionDeleteObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerSessionDeleteObserver(
|
||||
observer: EventObserver<ConversationInfo>
|
||||
) {
|
||||
MessageObserverProvider.registerConversationDelete(
|
||||
observer.getObserverInnerSuspend {
|
||||
it?.let { convertToConversationInfo(arrayListOf(it))[0] }
|
||||
},
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消会话删除监听器
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "use ConversationObserverRepo.unregisterSessionDeleteObserver() to replace"
|
||||
)
|
||||
@JvmStatic
|
||||
fun unregisterSessionDeleteObserver(
|
||||
observer: EventObserver<ConversationInfo>
|
||||
) {
|
||||
MessageObserverProvider.registerConversationDelete(
|
||||
observer.getObserverInner(),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册用户信息变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ContactObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerUserInfoObserver(observer: UserInfoObserver) {
|
||||
UserInfoProvider.registerUserInfoObserver(observer, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消用户信息变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ContactObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun unregisterUserInfoObserver(
|
||||
observer: UserInfoObserver
|
||||
) {
|
||||
UserInfoProvider.registerUserInfoObserver(observer, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册好友信息变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ContactObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerFriendObserver(
|
||||
observer: FriendObserver
|
||||
) {
|
||||
FriendProvider.registerFriendObserver(observer)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消好友信息变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ContactObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun unregisterFriendObserver(
|
||||
observer: FriendObserver
|
||||
) {
|
||||
FriendProvider.unregisterFriendObserver(observer)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册群组移除变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use TeamObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerTeamRemoveObserver(
|
||||
observer: Observer<Team>
|
||||
) {
|
||||
TeamObserverProvider.registerTeamRemoveObserver(observer, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消群组移除变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use TeamObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun unregisterTeamRemoveObserver(
|
||||
observer: Observer<Team>
|
||||
) {
|
||||
TeamObserverProvider.registerTeamRemoveObserver(observer, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册群组信息变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use TeamObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerTeamUpdateObserver(observer: Observer<List<Team>>) {
|
||||
TeamObserverProvider.registerTeamUpdateObserver(observer, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消群组信息变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use TeamObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun unregisterTeamUpdateObserver(observer: Observer<List<Team>>) {
|
||||
TeamObserverProvider.registerTeamUpdateObserver(observer, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册好友消息不提醒变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ContactObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerFriendMuteObserver(observer: Observer<MuteListChangedNotify>) {
|
||||
FriendObserverProvider.registerMuteChangedObserver(observer, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消好友消息不提醒变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ContactObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun unregisterFriendMuteObserver(observer: Observer<MuteListChangedNotify>) {
|
||||
FriendObserverProvider.registerMuteChangedObserver(observer, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册会话置顶变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ConversationObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerAddStickTopObserver(observer: Observer<StickTopSessionInfo>) {
|
||||
MessageObserverProvider.registerConversationAddStick(observer, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消会话置顶变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ConversationObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun unregisterAddStickTopObserver(observer: Observer<StickTopSessionInfo>) {
|
||||
MessageObserverProvider.registerConversationAddStick(observer, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册置顶移除变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ConversationObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerRemoveStickTopObserver(observer: Observer<StickTopSessionInfo>) {
|
||||
MessageObserverProvider.registerConversationRemoveStick(observer, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消置顶移除变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ConversationObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun unregisterRemoveStickTopObserver(observer: Observer<StickTopSessionInfo>) {
|
||||
MessageObserverProvider.registerConversationRemoveStick(observer, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册置顶会话变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ConversationObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerUpdateStickTopObserver(observer: Observer<StickTopSessionInfo>) {
|
||||
MessageObserverProvider.registerConversationUpdateStick(observer, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消置顶会话变化监听器
|
||||
*/
|
||||
@Deprecated(message = "use ConversationObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun unregisterUpdateStickTopObserver(observer: Observer<StickTopSessionInfo>) {
|
||||
MessageObserverProvider.registerConversationUpdateStick(observer, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册置顶会话同步监听器
|
||||
*/
|
||||
@Deprecated(message = "use ConversationObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun registerSyncStickTopObserver(
|
||||
observer: Observer<List<StickTopSessionInfo>>
|
||||
) {
|
||||
MessageObserverProvider.registerConversationSyncStick(observer, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消置顶会话同步监听器
|
||||
*/
|
||||
@Deprecated(message = "use ConversationObserverRepo.registerUserInfoObserver() to replace")
|
||||
@JvmStatic
|
||||
fun unregisterSyncStickTopObserver(
|
||||
observer: Observer<List<StickTopSessionInfo>>
|
||||
) {
|
||||
MessageObserverProvider.registerConversationSyncStick(observer, false)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,672 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.page.viewmodel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.netease.nim.highavailable.LogUtils;
|
||||
import com.netease.nimlib.sdk.NIMClient;
|
||||
import com.netease.nimlib.sdk.Observer;
|
||||
import com.netease.nimlib.sdk.RequestCallbackWrapper;
|
||||
import com.netease.nimlib.sdk.friend.model.MuteListChangedNotify;
|
||||
import com.netease.nimlib.sdk.msg.MsgService;
|
||||
import com.netease.nimlib.sdk.msg.constant.DeleteTypeEnum;
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
|
||||
import com.netease.nimlib.sdk.msg.model.RecentContact;
|
||||
import com.netease.nimlib.sdk.msg.model.StickTopSessionInfo;
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.yunxin.kit.alog.ALog;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.chatkit.repo.ContactObserverRepo;
|
||||
import com.netease.yunxin.kit.chatkit.repo.ContactRepo;
|
||||
import com.netease.yunxin.kit.chatkit.repo.ConversationObserverRepo;
|
||||
import com.netease.yunxin.kit.chatkit.repo.ConversationRepo;
|
||||
import com.netease.yunxin.kit.chatkit.repo.ConversationRepoAll;
|
||||
import com.netease.yunxin.kit.chatkit.repo.TeamObserverRepo;
|
||||
import com.netease.yunxin.kit.common.ui.utils.ToastX;
|
||||
import com.netease.yunxin.kit.common.ui.viewmodel.BaseViewModel;
|
||||
import com.netease.yunxin.kit.common.ui.viewmodel.FetchResult;
|
||||
import com.netease.yunxin.kit.common.ui.viewmodel.LoadStatus;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.ConversationUIConstant;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.IConversationFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.ConversationUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.DeleteConversionEvent;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.DefaultViewHolderFactory;
|
||||
import com.netease.yunxin.kit.corekit.event.EventCenter;
|
||||
import com.netease.yunxin.kit.corekit.event.EventNotify;
|
||||
import com.netease.yunxin.kit.corekit.im.IMKitClient;
|
||||
import com.netease.yunxin.kit.corekit.im.custom.AitEvent;
|
||||
import com.netease.yunxin.kit.corekit.im.custom.AitInfo;
|
||||
import com.netease.yunxin.kit.corekit.im.model.EventObserver;
|
||||
import com.netease.yunxin.kit.corekit.im.model.FriendInfo;
|
||||
import com.netease.yunxin.kit.corekit.im.model.UserInfo;
|
||||
import com.netease.yunxin.kit.corekit.im.provider.FetchCallback;
|
||||
import com.netease.yunxin.kit.corekit.im.provider.FriendChangeType;
|
||||
import com.netease.yunxin.kit.corekit.im.provider.FriendObserver;
|
||||
import com.netease.yunxin.kit.corekit.im.provider.FriendProvider;
|
||||
import com.netease.yunxin.kit.corekit.im.provider.TeamProvider;
|
||||
import com.netease.yunxin.kit.corekit.im.provider.UserInfoObserver;
|
||||
import com.netease.yunxin.kit.corekit.im.provider.UserInfoProvider;
|
||||
import com.netease.yunxin.kit.corekit.im.utils.RouterConstant;
|
||||
import com.netease.yunxin.kit.corekit.route.XKitRouter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* conversation view model to fetch data or operate conversation
|
||||
*/
|
||||
public class ConversationViewModel extends BaseViewModel {
|
||||
|
||||
private final String TAG = "ConversationViewModel";
|
||||
private final String LIB_TAG = "ConversationKit-UI";
|
||||
|
||||
private final MutableLiveData<FetchResult<Integer>> unreadCountLiveData = new MutableLiveData<>();
|
||||
private final MutableLiveData<FetchResult<List<ConversationBean>>> queryLiveData =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveData<FetchResult<List<ConversationBean>>> changeLiveData =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveData<FetchResult<ConversationBean>> stickLiveData =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveData<FetchResult<String>> addRemoveStickLiveData =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveData<FetchResult<List<UserInfo>>> userInfoLiveData =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveData<FetchResult<List<FriendInfo>>> friendInfoLiveData =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveData<FetchResult<List<Team>>> teamInfoLiveData = new MutableLiveData<>();
|
||||
private final MutableLiveData<FetchResult<MuteListChangedNotify>> muteInfoLiveData =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveData<FetchResult<List<String>>> aitLiveData = new MutableLiveData<>();
|
||||
|
||||
private Comparator<ConversationInfo> comparator;
|
||||
private IConversationFactory conversationFactory = new DefaultViewHolderFactory();
|
||||
private static final int PAGE_LIMIT = 50;
|
||||
private boolean hasMore = true;
|
||||
private boolean hasStart = false;
|
||||
|
||||
public ConversationViewModel() {
|
||||
//register observer
|
||||
ConversationObserverRepo.registerSessionChangedObserver(changeObserver);
|
||||
ConversationObserverRepo.registerSessionDeleteObserver(deleteObserver);
|
||||
ContactObserverRepo.registerUserInfoObserver(userInfoObserver);
|
||||
ContactObserverRepo.registerFriendObserver(friendObserver);
|
||||
TeamObserverRepo.registerTeamUpdateObserver(teamUpdateObserver);
|
||||
ConversationObserverRepo.registerNotifyChangeObserver(muteObserver);
|
||||
ConversationObserverRepo.registerAddStickTopObserver(addStickObserver);
|
||||
ConversationObserverRepo.registerRemoveStickTopObserver(removeStickObserver);
|
||||
ConversationObserverRepo.registerSyncStickTopObserver(syncStickObserver);
|
||||
EventNotify<AitEvent> aitNotify =
|
||||
new EventNotify<AitEvent>() {
|
||||
@Override
|
||||
public void onNotify(@NonNull AitEvent message) {
|
||||
AitEvent aitEvent = (AitEvent) message;
|
||||
FetchResult<List<String>> result = new FetchResult<>(LoadStatus.Finish);
|
||||
ALog.d(LIB_TAG, TAG, "aitNotify,onSuccess:" + aitEvent.getEventType().name());
|
||||
if (aitEvent.getEventType() == AitEvent.AitEventType.Arrive
|
||||
|| aitEvent.getEventType() == AitEvent.AitEventType.Load) {
|
||||
result.setFetchType(FetchResult.FetchType.Add);
|
||||
} else {
|
||||
result.setFetchType(FetchResult.FetchType.Remove);
|
||||
}
|
||||
List<AitInfo> aitInfoList = aitEvent.getAitInfoList();
|
||||
List<String> sessionIdList = new ArrayList<>();
|
||||
for (AitInfo info : aitInfoList) {
|
||||
sessionIdList.add(info.getSessionId());
|
||||
}
|
||||
result.setData(sessionIdList);
|
||||
aitLiveData.setValue(result);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getEventType() {
|
||||
return "AitEvent";
|
||||
}
|
||||
};
|
||||
EventCenter.registerEventNotify(aitNotify);
|
||||
}
|
||||
|
||||
/**
|
||||
* comparator to sort conversation list
|
||||
*/
|
||||
public void setComparator(Comparator<ConversationInfo> comparator) {
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* comparator to sort conversation list
|
||||
*/
|
||||
public void setConversationFactory(IConversationFactory factory) {
|
||||
this.conversationFactory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* query unread count live data
|
||||
*/
|
||||
public MutableLiveData<FetchResult<Integer>> getUnreadCountLiveData() {
|
||||
return unreadCountLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* query conversation live data
|
||||
*/
|
||||
public MutableLiveData<FetchResult<List<ConversationBean>>> getQueryLiveData() {
|
||||
return queryLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* conversation change live data
|
||||
*/
|
||||
public MutableLiveData<FetchResult<List<ConversationBean>>> getChangeLiveData() {
|
||||
return changeLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* conversation stick live data
|
||||
*/
|
||||
public MutableLiveData<FetchResult<ConversationBean>> getStickLiveData() {
|
||||
return stickLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* conversation remove stick live data
|
||||
*/
|
||||
public MutableLiveData<FetchResult<String>> getAddRemoveStickLiveData() {
|
||||
return addRemoveStickLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* userinfo changed live data
|
||||
*/
|
||||
public MutableLiveData<FetchResult<List<UserInfo>>> getUserInfoLiveData() {
|
||||
return userInfoLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* friend changed live data
|
||||
*/
|
||||
public MutableLiveData<FetchResult<List<FriendInfo>>> getFriendInfoLiveData() {
|
||||
return friendInfoLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* team changed live data
|
||||
*/
|
||||
public MutableLiveData<FetchResult<List<Team>>> getTeamInfoLiveData() {
|
||||
return teamInfoLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* mute changed live data
|
||||
*/
|
||||
public MutableLiveData<FetchResult<MuteListChangedNotify>> getMuteInfoLiveData() {
|
||||
return muteInfoLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* conversation @ info
|
||||
*/
|
||||
public MutableLiveData<FetchResult<List<String>>> getAitLiveData() {
|
||||
return aitLiveData;
|
||||
}
|
||||
|
||||
public void getUnreadCount() {
|
||||
ConversationRepo.getMsgUnreadCountAsync(
|
||||
new FetchCallback<Integer>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Integer param) {
|
||||
FetchResult<Integer> fetchResult = new FetchResult<>(LoadStatus.Success);
|
||||
fetchResult.setData(param);
|
||||
unreadCountLiveData.setValue(fetchResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int code) {
|
||||
ALog.d(LIB_TAG, TAG, "getUnreadCount,onFailed" + code);
|
||||
ToastX.showShortToast(String.valueOf(code));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(@Nullable Throwable exception) {
|
||||
ALog.d(LIB_TAG, TAG, "getUnreadCount,onException");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void cleanUnreadCount() {
|
||||
ConversationRepo.clearAllUnreadCount();
|
||||
}
|
||||
|
||||
public void fetchConversation() {
|
||||
XKitRouter.withKey(RouterConstant.PATH_CHAT_AIT_NOTIFY_ACTION).navigate();
|
||||
queryConversation(null);
|
||||
}
|
||||
|
||||
public void loadMore(ConversationBean data) {
|
||||
if (data != null && data.infoData != null) {
|
||||
ALog.d(LIB_TAG, TAG, "loadMore:" + data.infoData.getContactId());
|
||||
queryConversation(data.infoData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void queryConversation(ConversationInfo data) {
|
||||
ALog.d(LIB_TAG, TAG, "queryConversation:" + (data == null));
|
||||
if (hasStart) {
|
||||
ALog.d(LIB_TAG, TAG, "queryConversation,has Started return");
|
||||
return;
|
||||
}
|
||||
hasStart = true;
|
||||
// NIMClient.getService(MsgService.class).queryRecentContacts()
|
||||
// .setCallback(new RequestCallbackWrapper<List<RecentContact>>() {
|
||||
// @Override
|
||||
// public void onResult(int code, List<RecentContact> recents, Throwable e) {
|
||||
// // recents参数即为最近联系人列表(最近会话列表)
|
||||
// if (code == 200) {
|
||||
// FetchResult<List<ConversationBean>> result = new FetchResult<>(LoadStatus.Success);
|
||||
// if (recents != null) {
|
||||
// result.setLoadStatus(LoadStatus.Finish);
|
||||
// List<ConversationBean> resultData = new ArrayList<>();
|
||||
//
|
||||
// for (int index = 0; recents != null && index < recents.size(); index++) {
|
||||
// ConversationInfo conversationInfo = new ConversationInfo(recents.get(index));
|
||||
// if (recents.get(index).getSessionType() == SessionTypeEnum.Team) {
|
||||
// fillTeamInfo(conversationInfo);
|
||||
// }
|
||||
// if (recents.get(index).getSessionType() == SessionTypeEnum.P2P) {
|
||||
// fillUserInfo(conversationInfo);
|
||||
// }
|
||||
// resultData.add(conversationFactory.CreateBean(conversationInfo));
|
||||
// }
|
||||
// hasMore = false; //param != null && param.size() == PAGE_LIMIT;
|
||||
// result.setData(resultData);
|
||||
// queryLiveData.setValue(result);
|
||||
// hasStart = false;
|
||||
// }
|
||||
// } else {
|
||||
// ToastX.showShortToast(String.valueOf(code));
|
||||
// hasStart = false;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
ConversationRepoAll.getAllSessionList(
|
||||
// data,
|
||||
// PAGE_LIMIT,
|
||||
// comparator,
|
||||
new FetchCallback<List<ConversationInfo>>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable List<ConversationInfo> param) {
|
||||
FetchResult<List<ConversationBean>> result = new FetchResult<>(LoadStatus.Success);
|
||||
if (data != null) {
|
||||
result.setLoadStatus(LoadStatus.Finish);
|
||||
}
|
||||
ALog.d(
|
||||
LIB_TAG,
|
||||
TAG,
|
||||
"queryConversation:onSuccess,size=" + (param != null ? param.size() : 0));
|
||||
List<ConversationBean> resultData = new ArrayList<>();
|
||||
for (int index = 0; param != null && index < param.size(); index++) {
|
||||
resultData.add(conversationFactory.CreateBean(param.get(index)));
|
||||
}
|
||||
hasMore = false; //param != null && param.size() == PAGE_LIMIT;
|
||||
result.setData(resultData);
|
||||
queryLiveData.setValue(result);
|
||||
hasStart = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int code) {
|
||||
ALog.d(LIB_TAG, TAG, "queryConversation,onFailed" + code);
|
||||
ToastX.showShortToast(String.valueOf(code));
|
||||
hasStart = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(@Nullable Throwable exception) {
|
||||
ALog.d(LIB_TAG, TAG, "queryConversation,onException");
|
||||
hasStart = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteMoreConversation(int type, List<ConversationBean> data) {
|
||||
for (ConversationBean bean : data) {
|
||||
deleteConversation(type, bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void fillTeamInfo(ConversationInfo info) {
|
||||
Team team = TeamProvider.INSTANCE.getTeamById(info.getContactId());
|
||||
info.setTeamInfo(team);
|
||||
}
|
||||
|
||||
public void fillUserInfo(ConversationInfo info) {
|
||||
FriendInfo friendInfo = FriendProvider.INSTANCE.getFriendInfo(info.getContactId());
|
||||
UserInfo userInfo = UserInfoProvider.getUserInfo(info.getContactId(), true);
|
||||
friendInfo.setUserInfo(userInfo);
|
||||
info.setFriendInfo(friendInfo);
|
||||
info.setUserInfo(userInfo);
|
||||
}
|
||||
|
||||
|
||||
// public void deleteFriendConversation(String accid,ConversationBean conversationBean) {
|
||||
// RecentContact recentContact = NIMClient.getService(MsgService.class).queryRecentContact(contactId, SessionTypeEnum.P2P);
|
||||
// ConversationRepo.deleteSession(
|
||||
// accid,
|
||||
// SessionTypeEnum.P2P,
|
||||
// DeleteTypeEnum.LOCAL_AND_REMOTE,
|
||||
// true,
|
||||
// new FetchCallback<Void>() {
|
||||
// @Override
|
||||
// public void onSuccess(@Nullable Void param) {
|
||||
// FetchResult<List<ConversationBean>> result = new FetchResult<>(LoadStatus.Finish);
|
||||
// result.setFetchType(FetchResult.FetchType.Remove);
|
||||
// List<ConversationBean> beanList = new ArrayList<>();
|
||||
// beanList.add(conversationBean);
|
||||
// result.setData(beanList);
|
||||
// changeLiveData.setValue(result); //删除更新
|
||||
//// DeleteConversionEvent updateConversionEvent = new DeleteConversionEvent();
|
||||
//// updateConversionEvent.setConversationBeanList(beanList);
|
||||
//// EventCenter.notifyEvent(updateConversionEvent);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFailed(int code) {
|
||||
// ALog.d(LIB_TAG, TAG, "deleteConversation,onFailed:" + code);
|
||||
// ToastX.showShortToast(String.valueOf(code));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onException(@Nullable Throwable exception) {
|
||||
// ALog.d(LIB_TAG, TAG, "deleteConversation,onException");
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// }
|
||||
|
||||
public void deleteConversation(int type, ConversationBean data) {
|
||||
ALog.d(LIB_TAG, TAG, "deleteConversation,data:" + data.infoData.getContactId());
|
||||
ConversationRepo.deleteSession(
|
||||
data.infoData.getContactId(),
|
||||
data.infoData.getSessionType(),
|
||||
type == 1 ? DeleteTypeEnum.LOCAL : DeleteTypeEnum.LOCAL_AND_REMOTE,
|
||||
true,
|
||||
new FetchCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void param) {
|
||||
ALog.d(LIB_TAG, TAG, "deleteConversation,onSuccess:" + data.infoData.getContactId());
|
||||
FetchResult<List<ConversationBean>> result = new FetchResult<>(LoadStatus.Finish);
|
||||
result.setFetchType(FetchResult.FetchType.Remove);
|
||||
List<ConversationBean> beanList = new ArrayList<>();
|
||||
// if (type == 1) {
|
||||
// data.setHide(true);
|
||||
// }
|
||||
beanList.add(data);
|
||||
result.setData(beanList);
|
||||
changeLiveData.setValue(result); //删除更新
|
||||
if (type == 2) {
|
||||
NIMClient.getService(MsgService.class).clearServerHistory(data.infoData.getContactId(), data.infoData.getSessionType(), false);
|
||||
}
|
||||
// DeleteConversionEvent updateConversionEvent = new DeleteConversionEvent();
|
||||
// updateConversionEvent.setConversationBeanList(beanList);
|
||||
// EventCenter.notifyEvent(updateConversionEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int code) {
|
||||
ALog.d(LIB_TAG, TAG, "deleteConversation,onFailed:" + code);
|
||||
ToastX.showShortToast(String.valueOf(code));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(@Nullable Throwable exception) {
|
||||
ALog.d(LIB_TAG, TAG, "deleteConversation,onException");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void addStickTop(ConversationBean data) {
|
||||
|
||||
ConversationRepoAll.addStickTop(
|
||||
data.infoData.getContactId(),
|
||||
data.infoData.getSessionType(),
|
||||
"",
|
||||
new FetchCallback<StickTopSessionInfo>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable StickTopSessionInfo param) {
|
||||
if (param != null) {
|
||||
FetchResult<ConversationBean> result = new FetchResult<>(LoadStatus.Success);
|
||||
data.infoData.setStickTop(true);
|
||||
result.setData(data);
|
||||
ALog.d(LIB_TAG, TAG, "addStickTop,onSuccess:" + param.getSessionId());
|
||||
stickLiveData.setValue(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int code) {
|
||||
ALog.d(LIB_TAG, TAG, "addStickTop,onFailed:" + code);
|
||||
if (code == ConversationUIConstant.ERROR_CODE_NETWORK) {
|
||||
ToastX.showShortToast(R.string.conversation_network_error_tip);
|
||||
} else {
|
||||
ToastX.showShortToast(String.valueOf(code));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(@Nullable Throwable exception) {
|
||||
ALog.d(LIB_TAG, TAG, "addStickTop,onException");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeStick(ConversationBean data) {
|
||||
ConversationRepoAll.removeStickTop(
|
||||
data.infoData.getContactId(),
|
||||
data.infoData.getSessionType(),
|
||||
"",
|
||||
new FetchCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void param) {
|
||||
FetchResult<ConversationBean> result = new FetchResult<>(LoadStatus.Success);
|
||||
data.infoData.setStickTop(false);
|
||||
result.setData(data);
|
||||
ALog.d(LIB_TAG, TAG, "removeStick,onSuccess:" + data.infoData.getContactId());
|
||||
stickLiveData.setValue(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int code) {
|
||||
ALog.d(LIB_TAG, TAG, "addStickTop,onFailed:" + code);
|
||||
if (code == ConversationUIConstant.ERROR_CODE_NETWORK) {
|
||||
ToastX.showShortToast(R.string.conversation_network_error_tip);
|
||||
} else {
|
||||
ToastX.showShortToast(String.valueOf(code));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(@Nullable Throwable exception) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private final Observer<StickTopSessionInfo> addStickObserver =
|
||||
param -> {
|
||||
ALog.d(LIB_TAG, TAG, "addStickObserver,onSuccess:" + param.getSessionId());
|
||||
FetchResult<String> result = new FetchResult<>(LoadStatus.Finish);
|
||||
result.setFetchType(FetchResult.FetchType.Add);
|
||||
result.setData(param.getSessionId());
|
||||
addRemoveStickLiveData.setValue(result);
|
||||
};
|
||||
|
||||
private final Observer<List<StickTopSessionInfo>> syncStickObserver =
|
||||
param -> {
|
||||
ALog.d(LIB_TAG, TAG, "syncStickObserver,onSuccess:" + param.size());
|
||||
queryConversation(null);
|
||||
};
|
||||
|
||||
private final Observer<StickTopSessionInfo> removeStickObserver =
|
||||
param -> {
|
||||
ALog.d(LIB_TAG, TAG, "removeStickObserver,onSuccess:" + param.getSessionId());
|
||||
FetchResult<String> result = new FetchResult<>(LoadStatus.Finish);
|
||||
result.setFetchType(FetchResult.FetchType.Remove);
|
||||
result.setData(param.getSessionId());
|
||||
addRemoveStickLiveData.setValue(result);
|
||||
};
|
||||
|
||||
private final EventObserver<List<ConversationInfo>> changeObserver =
|
||||
new EventObserver<List<ConversationInfo>>() {
|
||||
@Override
|
||||
public void onEvent(@Nullable List<ConversationInfo> param) {
|
||||
if (param != null) {
|
||||
FetchResult<List<ConversationBean>> result = new FetchResult<>(LoadStatus.Success);
|
||||
List<ConversationBean> resultData = new ArrayList<>();
|
||||
for (int index = 0; index < param.size(); index++) {
|
||||
ConversationInfo conversationInfo = param.get(index);
|
||||
if (ConversationUtils.isMineLeave(conversationInfo)) { //如果是群解散,被移除,被解散不删会话
|
||||
if (conversationInfo.getFromAccount().equals(IMKitClient.account())) {
|
||||
deleteConversation(2, conversationFactory.CreateBean(param.get(index)));
|
||||
} else { //更新未读数
|
||||
ConversationBean bean = conversationFactory.CreateBean(param.get(index));
|
||||
resultData.add(bean);
|
||||
}
|
||||
// deleteConversation(2, conversationFactory.CreateBean(param.get(index)));
|
||||
// ALog.d(
|
||||
// LIB_TAG,
|
||||
// TAG,
|
||||
// "changeObserver,DismissTeam,onSuccess:" + param.get(index).getContactId());
|
||||
// continue;
|
||||
} else {
|
||||
ConversationBean bean = conversationFactory.CreateBean(param.get(index));
|
||||
// bean.param = conversationInfo.getContactId();
|
||||
// bean.paramKey = RouterConstant.CHAT_ID_KRY;
|
||||
// if (conversationInfo.getSessionType() == SessionTypeEnum.Team) {
|
||||
// bean.router = RouterConstant.PATH_CHAT_TEAM_PAGE;
|
||||
// bean.viewType = 2;
|
||||
// } else {
|
||||
// bean.router = RouterConstant.PATH_CHAT_P2P_PAGE;
|
||||
// bean.viewType = 1;
|
||||
// }
|
||||
resultData.add(bean);
|
||||
}
|
||||
}
|
||||
result.setData(resultData);
|
||||
changeLiveData.setValue(result);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final EventObserver<ConversationInfo> deleteObserver =
|
||||
new EventObserver<ConversationInfo>() {
|
||||
@Override
|
||||
public void onEvent(@Nullable ConversationInfo param) {
|
||||
ALog.d(LIB_TAG, TAG, "deleteObserver,onSuccess:" + (param == null));
|
||||
FetchResult<List<ConversationBean>> result = new FetchResult<>(LoadStatus.Finish);
|
||||
result.setFetchType(FetchResult.FetchType.Remove);
|
||||
List<ConversationBean> beanList = new ArrayList<>();
|
||||
if (param != null) {
|
||||
beanList.add(conversationFactory.CreateBean(param));
|
||||
}
|
||||
result.setData(beanList);
|
||||
changeLiveData.setValue(result);
|
||||
}
|
||||
};
|
||||
|
||||
private final UserInfoObserver userInfoObserver =
|
||||
userList -> {
|
||||
ALog.d(LIB_TAG, TAG, "userInfoObserver,userList:" + userList.size());
|
||||
FetchResult<List<UserInfo>> result = new FetchResult<>(LoadStatus.Success);
|
||||
result.setData(userList);
|
||||
userInfoLiveData.setValue(result);
|
||||
};
|
||||
|
||||
private final FriendObserver friendObserver =
|
||||
(friendChangeType, accountList) -> {
|
||||
ALog.d(LIB_TAG, TAG, "friendObserver,userList:" + accountList.size());
|
||||
if (friendChangeType == FriendChangeType.Update) {
|
||||
ContactRepo.getFriendList(
|
||||
accountList,
|
||||
new FetchCallback<List<FriendInfo>>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable List<FriendInfo> param) {
|
||||
ALog.d(
|
||||
LIB_TAG, TAG, "friendObserver,getFriendInfo,onSuccess:" + accountList.size());
|
||||
FetchResult<List<FriendInfo>> result = new FetchResult<>(LoadStatus.Success);
|
||||
result.setData(param);
|
||||
friendInfoLiveData.setValue(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int code) {
|
||||
ALog.d(LIB_TAG, TAG, "friendObserver,getFriendInfo,onFailed:" + code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(@Nullable Throwable exception) {
|
||||
ALog.d(
|
||||
LIB_TAG,
|
||||
TAG,
|
||||
"friendObserver,getFriendInfo,onException"
|
||||
+ (exception != null ? exception.getMessage() : "null"));
|
||||
}
|
||||
});
|
||||
} else if (friendChangeType == FriendChangeType.Delete) {
|
||||
FetchResult<List<FriendInfo>> result = new FetchResult<>(LoadStatus.Success);
|
||||
List<FriendInfo> friendList = new ArrayList<>();
|
||||
for (String account : accountList) {
|
||||
friendList.add(new FriendInfo(account, null, null));
|
||||
}
|
||||
result.setData(friendList);
|
||||
friendInfoLiveData.setValue(result);
|
||||
}
|
||||
};
|
||||
|
||||
private final Observer<List<Team>> teamUpdateObserver =
|
||||
teamList -> {
|
||||
if (teamList != null) {
|
||||
ALog.d(LIB_TAG, TAG, "teamUpdateObserver,teamInfoList:" + teamList.size());
|
||||
FetchResult<List<Team>> result = new FetchResult<>(LoadStatus.Success);
|
||||
result.setData(teamList);
|
||||
teamInfoLiveData.setValue(result);
|
||||
}
|
||||
};
|
||||
|
||||
private final Observer<MuteListChangedNotify> muteObserver =
|
||||
muteNotify -> {
|
||||
if (muteNotify != null) {
|
||||
ALog.d(LIB_TAG, TAG, "muteObserver,muteNotify:" + muteNotify.getAccount());
|
||||
FetchResult<MuteListChangedNotify> result = new FetchResult<>(LoadStatus.Success);
|
||||
result.setData(muteNotify);
|
||||
muteInfoLiveData.setValue(result);
|
||||
}
|
||||
};
|
||||
|
||||
public boolean hasMore() {
|
||||
return hasMore;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
super.onCleared();
|
||||
ConversationObserverRepo.unregisterSessionDeleteObserver(deleteObserver);
|
||||
ConversationObserverRepo.unregisterSessionChangedObserver(changeObserver);
|
||||
ContactObserverRepo.unregisterUserInfoObserver(userInfoObserver);
|
||||
ContactObserverRepo.unregisterFriendObserver(friendObserver);
|
||||
TeamObserverRepo.unregisterTeamUpdateObserver(teamUpdateObserver);
|
||||
ConversationObserverRepo.unregisterNotifyChangeObserver(muteObserver);
|
||||
ConversationObserverRepo.unregisterAddStickTopObserver(addStickObserver);
|
||||
ConversationObserverRepo.unregisterSyncStickTopObserver(syncStickObserver);
|
||||
ConversationObserverRepo.unregisterRemoveStickTopObserver(removeStickObserver);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,418 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.view;
|
||||
|
||||
import static com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant.LIB_TAG;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.netease.nimlib.sdk.friend.model.MuteListChangedNotify;
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
|
||||
import com.netease.nimlib.sdk.team.constant.TeamMessageNotifyTypeEnum;
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.yunxin.kit.alog.ALog;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.BaseViewHolder;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.ViewHolderClickListener;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.IConversationFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.common.DataUtils;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.DefaultViewHolderFactory;
|
||||
import com.netease.yunxin.kit.corekit.im.IMKitClient;
|
||||
import com.netease.yunxin.kit.corekit.im.model.FriendInfo;
|
||||
import com.netease.yunxin.kit.corekit.im.model.UserInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* conversation adapter
|
||||
*/
|
||||
public class ConversationAdapter extends RecyclerView.Adapter<BaseViewHolder> {
|
||||
|
||||
private final String TAG = "ConversationAdapter";
|
||||
private IConversationFactory viewHolderFactory = new DefaultViewHolderFactory();
|
||||
private final List<ConversationBean> conversationList = new ArrayList<>();
|
||||
private Comparator<ConversationInfo> dataComparator;
|
||||
private ViewHolderClickListener clickListener;
|
||||
private boolean isShow = true;
|
||||
private final LinearLayoutManager layoutManager;
|
||||
|
||||
private boolean isShowAll = true;
|
||||
|
||||
public ConversationAdapter(LinearLayoutManager layoutManager) {
|
||||
this.layoutManager = layoutManager;
|
||||
}
|
||||
|
||||
public void setShowAll(boolean showAll) {
|
||||
this.isShowAll = showAll;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* set data and clear conversationList
|
||||
*/
|
||||
public void setData(List<ConversationBean> data) {
|
||||
conversationList.clear();
|
||||
if (data != null) {
|
||||
conversationList.addAll(data);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void setShowTag(boolean show) {
|
||||
isShow = show;
|
||||
if (show) {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add data to list forward
|
||||
*/
|
||||
public void addForwardData(List<ConversationBean> data) {
|
||||
if (data != null) {
|
||||
conversationList.addAll(0, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* append data to list
|
||||
*/
|
||||
public void appendData(List<ConversationBean> data) {
|
||||
if (data != null) {
|
||||
int position = conversationList.size();
|
||||
conversationList.addAll(data);
|
||||
notifyItemInserted(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void update(List<ConversationBean> data) {
|
||||
for (int i = 0; data != null && i < data.size(); i++) {
|
||||
update(data.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void update(ConversationBean data) {
|
||||
ALog.d(LIB_TAG, TAG, "update" + data.infoData.getContactId());
|
||||
int position = layoutManager.findFirstVisibleItemPosition();
|
||||
int removeIndex = -1;
|
||||
for (int j = 0; j < conversationList.size(); j++) {
|
||||
if (data.equals(conversationList.get(j))) {
|
||||
removeIndex = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ALog.d(LIB_TAG, TAG, "update, removeIndex:" + removeIndex);
|
||||
if (removeIndex > -1) {
|
||||
conversationList.remove(removeIndex);
|
||||
int insertIndex = searchComparatorIndex(data);
|
||||
ALog.d(
|
||||
LIB_TAG,
|
||||
TAG,
|
||||
"update, insertIndex:" + insertIndex + "unread:" + data.infoData.getUnreadCount());
|
||||
conversationList.add(insertIndex, data);
|
||||
if (isShow && isShowAll) {
|
||||
notifyItemMoved(removeIndex, insertIndex);
|
||||
notifyItemChanged(insertIndex);
|
||||
} else {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
} else {
|
||||
int insertIndex = searchComparatorIndex(data);
|
||||
conversationList.add(insertIndex, data);
|
||||
if (isShow && isShowAll) {
|
||||
notifyItemInserted(insertIndex);
|
||||
} else {
|
||||
notifyItemChanged(insertIndex);
|
||||
}
|
||||
}
|
||||
layoutManager.scrollToPosition(position);
|
||||
}
|
||||
|
||||
public void updateSelector(ConversationBean data) {
|
||||
int size = conversationList.indexOf(data);
|
||||
if (size >= 0) {
|
||||
conversationList.set(size, data);
|
||||
notifyItemChanged(size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void updateUserInfo(List<UserInfo> data) {
|
||||
Map<String, UserInfo> accountMap = DataUtils.getUserInfoMap(data);
|
||||
if (accountMap != null) {
|
||||
for (int i = 0; i < conversationList.size(); i++) {
|
||||
UserInfo info = conversationList.get(i).infoData.getUserInfo();
|
||||
if (info != null && accountMap.containsKey(info.getAccount())) {
|
||||
conversationList.get(i).infoData.setUserInfo(accountMap.get(info.getAccount()));
|
||||
if (isShow) {
|
||||
notifyItemChanged(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFriendInfo(List<FriendInfo> data) {
|
||||
Map<String, FriendInfo> accountMap = DataUtils.getFriendInfoMap(data);
|
||||
if (accountMap != null) {
|
||||
for (int i = 0; i < conversationList.size(); i++) {
|
||||
UserInfo info = conversationList.get(i).infoData.getUserInfo();
|
||||
if (info != null && accountMap.containsKey(info.getAccount())) {
|
||||
conversationList.get(i).infoData.setFriendInfo(accountMap.get(info.getAccount()));
|
||||
if (isShow) {
|
||||
notifyItemChanged(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTeamInfo(List<Team> data) {
|
||||
Map<String, Team> accountMap = DataUtils.getTeamInfoMap(data);
|
||||
if (accountMap != null) {
|
||||
for (int i = 0; i < conversationList.size(); i++) {
|
||||
ConversationInfo info = conversationList.get(i).infoData;
|
||||
if (info != null
|
||||
&& info.getTeamInfo() != null
|
||||
&& accountMap.containsKey(info.getTeamInfo().getId())) {
|
||||
Team team = accountMap.get(info.getTeamInfo().getId());
|
||||
info.setTeamInfo(team);
|
||||
if (team != null && team.getMessageNotifyType() != null) {
|
||||
info.setMute(team.getMessageNotifyType() == TeamMessageNotifyTypeEnum.Mute);
|
||||
}
|
||||
if (isShow) {
|
||||
notifyItemChanged(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTeamInfoType(List<Team> data, boolean isMy) {
|
||||
Map<String, Team> accountMap = DataUtils.getTeamInfoMap(data);
|
||||
if (accountMap != null) {
|
||||
for (int i = 0; i < conversationList.size(); i++) {
|
||||
ConversationInfo info = conversationList.get(i).infoData;
|
||||
if (info != null
|
||||
&& info.getTeamInfo() != null
|
||||
&& accountMap.containsKey(info.getTeamInfo().getId())) {
|
||||
Team team = accountMap.get(info.getTeamInfo().getId());
|
||||
info.setTeamInfo(team);
|
||||
if (team != null && team.getMessageNotifyType() != null) {
|
||||
info.setMute(team.getMessageNotifyType() == TeamMessageNotifyTypeEnum.Mute);
|
||||
}
|
||||
if (isMy && !team.getCreator().equals(IMKitClient.account())) {
|
||||
conversationList.remove(i);
|
||||
notifyItemRemoved(i);
|
||||
break;
|
||||
}
|
||||
if (!isMy && team.getCreator().equals(IMKitClient.account())) {
|
||||
conversationList.remove(i);
|
||||
notifyItemRemoved(i);
|
||||
break;
|
||||
}
|
||||
if (isShow) {
|
||||
notifyItemChanged(i);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateMuteInfo(MuteListChangedNotify data) {
|
||||
if (data != null) {
|
||||
for (int i = 0; i < conversationList.size(); i++) {
|
||||
String contactId = conversationList.get(i).infoData.getContactId();
|
||||
if (TextUtils.equals(contactId, data.getAccount())) {
|
||||
conversationList.get(i).infoData.setMute(data.isMute());
|
||||
if (isShow) {
|
||||
notifyItemChanged(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int searchComparatorIndex(ConversationBean data) {
|
||||
int index = conversationList.size();
|
||||
// add stick must be insert 0
|
||||
if (data.infoData.isStickTop()) {
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < conversationList.size(); i++) {
|
||||
if (dataComparator != null
|
||||
&& dataComparator.compare(data.infoData, conversationList.get(i).infoData) < 1) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public void removeData(List<ConversationBean> dataList) {
|
||||
if (dataList == null || dataList.size() < 1) {
|
||||
return;
|
||||
}
|
||||
for (ConversationBean data : dataList) {
|
||||
int index = -1;
|
||||
for (int j = 0; j < conversationList.size(); j++) {
|
||||
if (data.equals(conversationList.get(j))) {
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index > -1) {
|
||||
removeData(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAll() {
|
||||
conversationList.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void removeData(String id) {
|
||||
int index = -1;
|
||||
for (int j = 0; j < conversationList.size(); j++) {
|
||||
if (TextUtils.equals(conversationList.get(j).infoData.getContactId(), id)) {
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index > -1) {
|
||||
removeData(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeData(int position) {
|
||||
if (position >= 0 && position < conversationList.size()) {
|
||||
conversationList.remove(position);
|
||||
if (isShow) {
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateAit(List<String> idList) {
|
||||
int index = -1;
|
||||
for (String id : idList) {
|
||||
for (int j = 0; j < conversationList.size(); j++) {
|
||||
if (TextUtils.equals(conversationList.get(j).infoData.getContactId(), id)) {
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index > -1) {
|
||||
notifyItemChanged(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addStickTop(String id) {
|
||||
int index = -1;
|
||||
for (int j = 0; j < conversationList.size(); j++) {
|
||||
if (TextUtils.equals(conversationList.get(j).infoData.getContactId(), id)) {
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index > -1) {
|
||||
conversationList.get(index).infoData.setStickTop(true);
|
||||
ConversationBean data = conversationList.remove(index);
|
||||
conversationList.add(0, data);
|
||||
if (isShow) {
|
||||
notifyItemMoved(index, 0);
|
||||
notifyItemChanged(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeStickTop(String id) {
|
||||
int index = -1;
|
||||
for (int j = 0; j < conversationList.size(); j++) {
|
||||
if (TextUtils.equals(conversationList.get(j).infoData.getContactId(), id)) {
|
||||
index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index > -1) {
|
||||
ConversationBean data = conversationList.remove(index);
|
||||
data.infoData.setStickTop(false);
|
||||
int insertIndex = searchComparatorIndex(data);
|
||||
conversationList.add(insertIndex, data);
|
||||
if (isShow) {
|
||||
notifyItemMoved(index, insertIndex);
|
||||
notifyItemChanged(insertIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewHolderFactory(IConversationFactory factory) {
|
||||
this.viewHolderFactory = factory;
|
||||
}
|
||||
|
||||
public void setViewHolderClickListener(ViewHolderClickListener listener) {
|
||||
this.clickListener = listener;
|
||||
}
|
||||
|
||||
public void setComparator(Comparator<ConversationInfo> comparator) {
|
||||
this.dataComparator = comparator;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
BaseViewHolder viewHolder = null;
|
||||
if (viewHolderFactory != null) {
|
||||
viewHolder = viewHolderFactory.createViewHolder(parent, viewType);
|
||||
}
|
||||
return viewHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
|
||||
holder.onBindData(conversationList.get(position), position);
|
||||
holder.setItemOnClickListener(clickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return viewHolderFactory.getItemViewType(conversationList.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (isShowAll) {
|
||||
return conversationList.size();
|
||||
} else {
|
||||
return Math.min(conversationList.size(), 3);
|
||||
}
|
||||
// return conversationList.size();
|
||||
}
|
||||
|
||||
public ConversationBean getData(int index) {
|
||||
if (index >= 0 && index < conversationList.size()) {
|
||||
return conversationList.get(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ConversationBean> getConversationList() {
|
||||
return conversationList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.netease.yunxin.kit.common.ui.widgets.TitleBarView;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.databinding.ConversationViewLayoutBinding;
|
||||
|
||||
public class ConversationLayout extends LinearLayout {
|
||||
|
||||
private ConversationViewLayoutBinding viewBinding;
|
||||
|
||||
public ConversationLayout(Context context) {
|
||||
super(context);
|
||||
init(null);
|
||||
}
|
||||
|
||||
public ConversationLayout(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
public ConversationLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
public ConversationLayout(
|
||||
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
private void init(AttributeSet attrs) {
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
|
||||
viewBinding = ConversationViewLayoutBinding.inflate(layoutInflater, this);
|
||||
}
|
||||
|
||||
public TitleBarView getTitleBar() {
|
||||
return viewBinding.conversationTitleBar;
|
||||
}
|
||||
|
||||
public LinearLayout getTopLayout() {
|
||||
return viewBinding.conversationTopLayout;
|
||||
}
|
||||
|
||||
public LinearLayout getBodyLayout() {
|
||||
return viewBinding.conversationBodyLayout;
|
||||
}
|
||||
|
||||
public ConversationView getConversationView() {
|
||||
return viewBinding.conversationView;
|
||||
}
|
||||
|
||||
public FrameLayout getBottomLayout() {
|
||||
return viewBinding.conversationBottomLayout;
|
||||
}
|
||||
|
||||
public FrameLayout getBodyTopLayout() {
|
||||
return viewBinding.conversationBodyTopLayout;
|
||||
}
|
||||
|
||||
public TextView getErrorTextView() {
|
||||
return viewBinding.conversationNetworkErrorTv;
|
||||
}
|
||||
|
||||
public void setEmptyViewVisible(int visible) {
|
||||
viewBinding.conversationEmptyView.setVisibility(visible);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
// Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.netease.yunxin.kit.conversationkit.ui.view;
|
||||
|
||||
import static com.netease.yunxin.kit.conversationkit.ui.common.ConversationConstant.LIB_TAG;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.netease.nimlib.sdk.friend.model.MuteListChangedNotify;
|
||||
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
|
||||
import com.netease.nimlib.sdk.team.model.Team;
|
||||
import com.netease.yunxin.kit.alog.ALog;
|
||||
import com.netease.yunxin.kit.chatkit.model.ConversationInfo;
|
||||
import com.netease.yunxin.kit.common.ui.viewholder.ViewHolderClickListener;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.IConversationFactory;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.R;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.model.ConversationBean;
|
||||
import com.netease.yunxin.kit.conversationkit.ui.page.interfaces.ILoadListener;
|
||||
import com.netease.yunxin.kit.corekit.im.model.FriendInfo;
|
||||
import com.netease.yunxin.kit.corekit.im.model.UserInfo;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* conversation list view
|
||||
*/
|
||||
public class ConversationView extends FrameLayout {
|
||||
|
||||
private final String TAG = "ConversationView";
|
||||
private RecyclerView recyclerView;
|
||||
private ConversationAdapter adapter;
|
||||
private ILoadListener loadMoreListener;
|
||||
private final int LOAD_MORE_DIFF = 5;
|
||||
|
||||
public ConversationView(Context context) {
|
||||
super(context);
|
||||
init(null);
|
||||
}
|
||||
|
||||
public ConversationView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
public ConversationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(attrs);
|
||||
}
|
||||
|
||||
private void init(AttributeSet attrs) {
|
||||
recyclerView = new RecyclerView(getContext());
|
||||
recyclerView.setId(R.id.conversation_rv);
|
||||
this.addView(
|
||||
recyclerView,
|
||||
new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
|
||||
adapter = new ConversationAdapter(layoutManager);
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.addOnScrollListener(
|
||||
new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
|
||||
super.onScrollStateChanged(recyclerView, newState);
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
int position = layoutManager.findLastVisibleItemPosition();
|
||||
if (loadMoreListener != null
|
||||
&& loadMoreListener.hasMore()
|
||||
&& adapter.getItemCount() < position + LOAD_MORE_DIFF) {
|
||||
ConversationBean last = adapter.getData(adapter.getItemCount() - 1);
|
||||
loadMoreListener.loadMore(last);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
super.onScrolled(recyclerView, dx, dy);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setLoadMoreListener(ILoadListener listener) {
|
||||
this.loadMoreListener = listener;
|
||||
}
|
||||
|
||||
public void setItemClickListener(ViewHolderClickListener listener) {
|
||||
adapter.setViewHolderClickListener(listener);
|
||||
}
|
||||
|
||||
|
||||
public void addItemDecoration(RecyclerView.ItemDecoration decoration) {
|
||||
recyclerView.addItemDecoration(decoration);
|
||||
}
|
||||
|
||||
public void setViewHolderFactory(IConversationFactory factory) {
|
||||
adapter.setViewHolderFactory(factory);
|
||||
}
|
||||
|
||||
public void setComparator(Comparator<ConversationInfo> comparator) {
|
||||
this.adapter.setComparator(comparator);
|
||||
}
|
||||
|
||||
|
||||
public void setData(List<ConversationBean> data) {
|
||||
if (adapter != null) {
|
||||
adapter.setData(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void addData(List<ConversationBean> data) {
|
||||
if (adapter != null) {
|
||||
adapter.appendData(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void update(List<ConversationBean> data) {
|
||||
if (adapter != null) {
|
||||
ALog.d(LIB_TAG, TAG, "update ConversationBean list, start");
|
||||
adapter.update(data);
|
||||
ALog.d(LIB_TAG, TAG, "update ConversationBean list, end");
|
||||
}
|
||||
}
|
||||
|
||||
public void update(ConversationBean data) {
|
||||
if (adapter != null) {
|
||||
ALog.d(LIB_TAG, TAG, "update ConversationBean, start");
|
||||
adapter.update(data);
|
||||
ALog.d(LIB_TAG, TAG, "update ConversationBean, end");
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSelector(ConversationBean data) {
|
||||
if (adapter != null) {
|
||||
adapter.updateSelector(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateUserInfo(List<UserInfo> data) {
|
||||
if (adapter != null) {
|
||||
adapter.updateUserInfo(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFriendInfo(List<FriendInfo> data) {
|
||||
if (adapter != null) {
|
||||
adapter.updateFriendInfo(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTeamInfo(List<Team> data) {
|
||||
if (adapter != null) {
|
||||
adapter.updateTeamInfo(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTeamInfoType(List<Team> data,boolean isMyGroup) {
|
||||
if (adapter != null) {
|
||||
adapter.updateTeamInfoType(data,isMyGroup);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateMuteInfo(MuteListChangedNotify changedNotify) {
|
||||
if (adapter != null) {
|
||||
adapter.updateMuteInfo(changedNotify);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(List<ConversationBean> data) {
|
||||
if (adapter != null) {
|
||||
adapter.removeData(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAll() {
|
||||
if (adapter != null) {
|
||||
adapter.removeAll();
|
||||
}
|
||||
}
|
||||
|
||||
public int getDataSize() {
|
||||
if (adapter != null) {
|
||||
return adapter.getItemCount();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void removeConversation(String id) {
|
||||
if (adapter != null) {
|
||||
adapter.removeData(id);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateAit(List<String> idList) {
|
||||
if (adapter != null) {
|
||||
adapter.updateAit(idList);
|
||||
}
|
||||
}
|
||||
|
||||
public void addStickTop(String id) {
|
||||
if (adapter != null) {
|
||||
adapter.addStickTop(id);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeStickTop(String id) {
|
||||
if (adapter != null) {
|
||||
adapter.removeStickTop(id);
|
||||
}
|
||||
}
|
||||
|
||||
public void setShowTag(boolean show) {
|
||||
if (adapter != null) {
|
||||
adapter.setShowTag(show);
|
||||
}
|
||||
}
|
||||
|
||||
public ConversationAdapter getAdatper() {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
//设置全部已读回执
|
||||
public void setMakerReadAll() {
|
||||
if (adapter != null) {
|
||||
List<ConversationBean> listAll = adapter.getConversationList();
|
||||
if (listAll != null && listAll.size() > 0) {
|
||||
for (ConversationBean bean : listAll) {
|
||||
ConversationInfo info = bean.infoData;
|
||||
if (info.getSessionType() == SessionTypeEnum.P2P) {
|
||||
|
||||
} else if (info.getSessionType() == SessionTypeEnum.Team
|
||||
|| info.getSessionType() == SessionTypeEnum.SUPER_TEAM) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 578 B |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 845 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="6dp" />
|
||||
|
||||
<solid android:color="@color/color_6877fe" />
|
||||
</shape>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="6dp" />
|
||||
|
||||
<stroke
|
||||
android:width="@dimen/dimen_1_dp"
|
||||
android:color="@color/color_6877fe" />
|
||||
</shape>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<selector xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" tools:ignore="MissingDefaultResource">
|
||||
|
||||
<item android:drawable="@color/fun_conversation_item_bg_color" android:state_pressed="false" />
|
||||
<item android:drawable="@color/fun_conversation_item_stick_bg_color" android:state_pressed="true" />
|
||||
<item android:drawable="@color/fun_conversation_item_bg_color"/>
|
||||
</selector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<selector xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" tools:ignore="MissingDefaultResource">
|
||||
|
||||
<item android:drawable="@color/fun_conversation_item_stick_bg_color" />
|
||||
</selector>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:gravity="top|end" android:top="2dp" android:right="17dp">
|
||||
<rotate android:fromDegrees="45">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/fun_conversation_add_pop_bg_color"/>
|
||||
<size android:height="10.45dp" android:width="10.45dp"/>
|
||||
</shape>
|
||||
</rotate>
|
||||
</item>
|
||||
|
||||
|
||||
<item android:top="5dp">
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="4dp" />
|
||||
<solid android:color="@color/fun_conversation_add_pop_bg_color" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:pathData="M6.9706,2.7743C9.12,2.7777 10.9176,4.4086 11.1293,6.5476C11.3413,8.6866 9.8984,10.6385 7.7916,11.0634C5.6845,11.4884 3.598,10.2484 2.9643,8.1945C2.3305,6.1405 3.3552,3.9405 5.3352,3.1042C5.8526,2.8853 6.4088,2.7731 6.9706,2.7743ZM6.9706,1.8046C4.1144,1.8046 1.7988,4.1201 1.7988,6.9763C1.7988,9.8324 4.1144,12.148 6.9706,12.148C9.8267,12.148 12.1423,9.8324 12.1423,6.9763C12.1423,4.1201 9.8267,1.8046 6.9706,1.8046ZM13.7099,14.2005C13.6462,14.2007 13.5831,14.1881 13.5243,14.1637C13.4654,14.1393 13.412,14.1035 13.3671,14.0583L10.9105,11.6017C10.7269,11.4114 10.7295,11.109 10.9164,10.9219C11.1035,10.7349 11.4059,10.7322 11.596,10.9161L14.0526,13.3726C14.1203,13.4405 14.1665,13.5268 14.1852,13.6209C14.2039,13.7149 14.1943,13.8123 14.1576,13.9009C14.121,13.9896 14.059,14.0654 13.9793,14.1187C13.8996,14.172 13.8058,14.2005 13.7099,14.2005Z"
|
||||
android:fillColor="#A6ADB6"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,4 @@
|
||||
<vector android:height="20dp" android:viewportHeight="21"
|
||||
android:viewportWidth="21" android:width="20dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FC596A" android:pathData="M10.5,0C4.706,0 0,4.706 0,10.5C0,16.294 4.706,21 10.5,21C16.294,21 21,16.294 21,10.5C21,4.706 16.294,0 10.5,0ZM11.25,16.5H9.75V15H11.25V16.5ZM9.75,13.5V4.5H11.25V13.5H9.75Z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:ignore="MissingDefaultResource">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,137 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/topLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
tools:ignore="MissingConstraints">
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.TitleBarView
|
||||
android:id="@+id/titleBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_52_dp"
|
||||
android:visibility="gone"
|
||||
app:head_img_visible="visible"
|
||||
app:head_title="@string/conversation_title"
|
||||
app:head_title_color="@color/color_black"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.RoundFrameLayout
|
||||
android:id="@+id/searchLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_36_dp"
|
||||
android:layout_marginStart="@dimen/dimen_8_dp"
|
||||
android:visibility="gone"
|
||||
android:layout_marginEnd="@dimen/dimen_8_dp"
|
||||
android:background="@color/color_white"
|
||||
app:corner_radius="@dimen/dimen_4_dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/dimen_20_dp"
|
||||
android:layout_height="@dimen/dimen_20_dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/fun_ic_conversation_search" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/dimen_36_dp"
|
||||
android:layout_marginStart="@dimen/dimen_5_dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/fun_conversation_search_text"
|
||||
android:textColor="@color/fun_conversation_search_text_color"
|
||||
android:textSize="@dimen/text_size_16" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.netease.yunxin.kit.common.ui.widgets.RoundFrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bodyTopLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bodyLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
tools:ignore="MissingConstraints">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/errorTv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/color_fceeee"
|
||||
android:gravity="center"
|
||||
android:paddingStart="@dimen/dimen_35_dp"
|
||||
android:paddingTop="@dimen/dimen_10_dp"
|
||||
android:paddingEnd="@dimen/dimen_5_dp"
|
||||
android:paddingBottom="@dimen/dimen_10_dp"
|
||||
android:text="@string/conversation_network_error_tip"
|
||||
android:textColor="@color/color_50_000000"
|
||||
android:textSize="14dp"
|
||||
android:visibility="gone"
|
||||
app:drawableStartCompat="@drawable/ic_error" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.netease.yunxin.kit.conversationkit.ui.view.ConversationView
|
||||
android:id="@+id/conversationView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/emptyLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_188_dp"
|
||||
android:layout_marginTop="@dimen/dimen_150_dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:src="@drawable/fun_ic_conversation_empty" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/conversation_empty_tip" />
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bottomLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="MissingConstraints" />
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,231 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="76dp"
|
||||
android:background="@drawable/fun_conversation_view_holder_selector"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_selector"
|
||||
android:layout_width="@dimen/dimen_20_dp"
|
||||
android:layout_height="@dimen/dimen_20_dp"
|
||||
android:layout_marginStart="@dimen/fun_conversation_margin_15dp"
|
||||
android:background="@drawable/fun_ic_unselector_conversation"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/avatarView"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/avatarView" />
|
||||
|
||||
<View
|
||||
android:id="@+id/view_selectorclick"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/avatarView"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/avatarView"
|
||||
app:layout_constraintTop_toTopOf="@+id/avatarView" />
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.ContactAvatarView
|
||||
android:id="@+id/avatarView"
|
||||
android:layout_width="@dimen/dimen_45_dp"
|
||||
android:layout_height="@dimen/dimen_45_dp"
|
||||
android:layout_marginStart="@dimen/fun_conversation_margin_15dp"
|
||||
android:layout_marginTop="15dp"
|
||||
app:avatarCorner="@dimen/dimen_45_dp"
|
||||
app:layout_constraintLeft_toRightOf="@+id/iv_selector"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/contentLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/dimen_45_dp"
|
||||
android:layout_marginVertical="15dp"
|
||||
android:layout_marginStart="@dimen/fun_conversation_margin_15dp"
|
||||
android:layout_marginEnd="@dimen/fun_conversation_margin_15dp"
|
||||
app:layout_constraintLeft_toRightOf="@+id/avatarView"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nameTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="middle"
|
||||
android:maxWidth="@dimen/dimen_120_dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/fun_conversation_item_title_text_color"
|
||||
android:textSize="@dimen/text_size_16" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/aliasTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/fun_conversation_item_title_text_color"
|
||||
android:textSize="@dimen/text_size_16"
|
||||
android:visibility="gone"
|
||||
|
||||
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<!-- <TextView-->
|
||||
<!-- android:id="@+id/groupNumber"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_marginStart="@dimen/dimen_5_dp"-->
|
||||
<!-- android:layout_marginEnd="@dimen/dimen_16_dp"-->
|
||||
<!-- android:textColor="@color/fun_conversation_item_title_text_color"-->
|
||||
<!-- android:textSize="@dimen/text_size_16"-->
|
||||
<!-- android:textStyle="bold"-->
|
||||
<!-- android:visibility="visible"-->
|
||||
<!-- app:layout_constraintLeft_toRightOf="@+id/muteIv"-->
|
||||
<!-- app:layout_constraintRight_toLeftOf="@+id/timeTv"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent" />-->
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/messageLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="@dimen/dimen_7_dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/unreadTv">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/aitTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/dimen_4_dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/conversation_ait_tip"
|
||||
android:textColor="@color/color_ff4e54"
|
||||
android:textSize="@dimen/text_size_14"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/draftTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/dimen_4_dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/conversation_draft_tip"
|
||||
android:textColor="@color/color_ff4e54"
|
||||
android:textSize="@dimen/text_size_14"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/draftTvContent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="@dimen/text_size_14"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/messageTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="@dimen/text_size_14" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timeTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:ellipsize="end"
|
||||
android:maxWidth="@dimen/dimen_100_dp"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/fun_conversation_item_time_text_color"
|
||||
android:textSize="@dimen/text_size_12"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/ll_name"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/ll_name" />
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/muteIv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginLeft="@dimen/dimen_5_dp"
|
||||
android:src="@drawable/fun_ic_conversation_mute"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/ll_name"
|
||||
app:layout_constraintLeft_toRightOf="@+id/ll_name"
|
||||
app:layout_constraintTop_toTopOf="@+id/ll_name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_myteamtype"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dimen_5_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_10_dp"
|
||||
android:ellipsize="middle"
|
||||
android:maxWidth="@dimen/dimen_60_dp"
|
||||
android:paddingStart="@dimen/dimen_5_dp"
|
||||
android:paddingEnd="@dimen/dimen_5_dp"
|
||||
android:singleLine="true"
|
||||
android:textSize="@dimen/text_size_12"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/ll_name"
|
||||
app:layout_constraintLeft_toRightOf="@+id/muteIv"
|
||||
app:layout_constraintTop_toTopOf="@+id/ll_name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/unreadTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/dimen_2_dp"
|
||||
android:background="@drawable/bg_conversation_red_dot"
|
||||
android:gravity="center"
|
||||
android:paddingStart="@dimen/dimen_5_dp"
|
||||
android:paddingEnd="@dimen/dimen_5_dp"
|
||||
android:textColor="@color/color_white"
|
||||
android:textSize="@dimen/text_size_12"
|
||||
android:visibility="gone"
|
||||
|
||||
app:layout_constraintBottom_toBottomOf="@+id/messageLayout"
|
||||
app:layout_constraintRight_toRightOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="#EDE3E3"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:ignore="MissingDefaultResource">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/topLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.TitleBarView
|
||||
android:id="@+id/titleBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_42_dp"
|
||||
app:head_img_visible="visible"
|
||||
app:head_title="@string/conversation_title"
|
||||
app:head_title_color="@color/color_black"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.RoundFrameLayout
|
||||
android:id="@+id/searchLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/color_white"
|
||||
app:corner_radius="@dimen/dimen_4_dp"
|
||||
android:layout_marginStart="@dimen/dimen_16_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_16_dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/dimen_36_dp"
|
||||
android:text="@string/fun_conversation_search_text"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:drawablePadding="@dimen/dimen_8_dp"
|
||||
android:drawableStart="@drawable/fun_ic_conversation_search" />
|
||||
</com.netease.yunxin.kit.common.ui.widgets.RoundFrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bodyTopLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bodyLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/errorTv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="36dp"
|
||||
android:background="@color/color_fee3e6"
|
||||
android:gravity="center"
|
||||
android:text="@string/conversation_network_error_tip"
|
||||
android:textColor="@color/color_fc596a"
|
||||
android:textSize="14dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.netease.yunxin.kit.conversationkit.ui.view.ConversationView
|
||||
android:id="@+id/conversationView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout android:id="@+id/emptyLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_188_dp"
|
||||
android:layout_marginTop="@dimen/dimen_150_dp"
|
||||
android:visibility="gone"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/dimen_118_dp"
|
||||
android:layout_height="@dimen/dimen_96_dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:src="@drawable/ic_conversation_empty"/>
|
||||
|
||||
<TextView android:id="@+id/empty_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/conversation_empty_tip"/>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bottomLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</merge>
|
||||
20
conversationkit-ui/src/main/res-fun/values/colors.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="fun_conversation_page_bg_color">#ededed</color>
|
||||
<color name="fun_conversation_secondary_page_bg_color">#ededed</color>
|
||||
<color name="fun_conversation_search_text_color">#4d000000</color>
|
||||
<color name="fun_conversation_item_bg_color">#FFFBFB</color>
|
||||
<color name="fun_conversation_item_title_text_color">#333333</color>
|
||||
<color name="fun_conversation_item_sub_title_text_color">#7F7B81</color>
|
||||
<color name="fun_conversation_item_time_text_color">#7f7b81</color>
|
||||
<color name="fun_conversation_item_divide_line_color">#d8d8d8</color>
|
||||
|
||||
<!-- 置顶会话背景色 -->
|
||||
<color name="fun_conversation_item_stick_bg_color">#ededef</color>
|
||||
|
||||
<!-- 创建群聊和添加好友PopupWindow 字体颜色 -->
|
||||
<color name="fun_conversation_add_pop_text_color">#ffffff</color>
|
||||
<color name="fun_conversation_add_pop_bg_color">#4c4c4c</color>
|
||||
<color name="color_6877fe">#6877fe</color>
|
||||
|
||||
</resources>
|
||||
9
conversationkit-ui/src/main/res-fun/values/dimens.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="fun_add_pop_item_height">50dp</dimen>
|
||||
<dimen name="fun_add_pop_item_width">126dp</dimen>
|
||||
<dimen name="fun_add_pop_item_margin_right_top">16dp</dimen>
|
||||
<dimen name="fun_add_pop_item_padding">8dp</dimen>
|
||||
<dimen name="fun_conversation_margin_15dp">15dp</dimen>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<selector xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" tools:ignore="MissingDefaultResource">
|
||||
|
||||
<item android:drawable="@color/color_white" android:state_pressed="false" />
|
||||
<item android:drawable="@color/color_ededef" android:state_pressed="true" />
|
||||
</selector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<selector xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" tools:ignore="MissingDefaultResource">
|
||||
|
||||
<item android:drawable="@color/color_ededef" />
|
||||
</selector>
|
||||
@@ -0,0 +1,36 @@
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="14dp"
|
||||
android:viewportWidth="14"
|
||||
android:viewportHeight="14">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M9.0805,10.5H13"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M10.9999,8.5808L10.9999,12.5003"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M6.4598,3.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M8.5324,8.0002H4.7499C2.6789,8.0002 0.9999,9.6792 0.9999,11.7502V11.7502C0.9999,12.4406 1.5596,13.0002 2.2499,13.0002H8.5324"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,36 @@
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="14dp"
|
||||
android:viewportWidth="14"
|
||||
android:viewportHeight="14">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M11.8972,3.9999C11.8972,5.2141 10.9129,6.1985 9.6986,6.1985C8.4844,6.1985 7.5,5.2141 7.5,3.9999C7.5,2.7856 8.4844,1.8013 9.6986,1.8013C10.9129,1.8013 11.8972,2.7856 11.8972,3.9999Z"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M4.8888,5.3892C4.8888,6.1562 4.267,6.778 3.4999,6.778C2.7329,6.778 2.111,6.1562 2.111,5.3892C2.111,4.6221 2.7329,4.0002 3.4999,4.0002C4.267,4.0002 4.8888,4.6221 4.8888,5.3892Z"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M3.0181,8.7217H2.5833C1.4327,8.7217 0.4999,9.6544 0.4999,10.805V10.805C0.4999,11.1886 0.8109,11.4995 1.1944,11.4995H3.0181"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M5.5,11.5C5.5,9.567 7.067,8 9,8H10C11.933,8 13.5,9.567 13.5,11.5C13.5,12.0523 13.0523,12.5 12.5,12.5H6.5C5.9477,12.5 5.5,12.0523 5.5,11.5Z"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,48 @@
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="14dp"
|
||||
android:viewportWidth="14"
|
||||
android:viewportHeight="14">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M10,10H13"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M11.5,8.5L11.5,11.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M9.8014,3.922m-2.1986,0a2.1986,2.1986 0,1 1,4.3972 0a2.1986,2.1986 0,1 1,-4.3972 0"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M3.8888,5.8889m-1.3889,0a1.3889,1.3889 0,1 1,2.7778 0a1.3889,1.3889 0,1 1,-2.7778 0"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M8.8653,7.8794H8.2977C6.4763,7.8794 4.9998,9.3559 4.9998,11.1773V11.1773C4.9998,11.7844 5.4919,12.2766 6.0991,12.2766H8.9858"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M3.5182,9.2227H3.0834C1.9327,9.2227 1,10.1554 1,11.306V11.306C1,11.6895 1.3109,12.0005 1.6945,12.0005H3.5182"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,39 @@
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="14dp"
|
||||
android:height="14dp"
|
||||
android:viewportWidth="14"
|
||||
android:viewportHeight="14">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M0.5,2.5L12,13"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M11.4737,10.5005V6.5C11.4737,3.8839 9.3529,1.7632 6.7368,1.7632C5.5701,1.7632 4.5019,2.185 3.6764,2.8845M2,6.5V10.5005H6.7368"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M0.8125,10.5C3.431,10.5 4.9561,10.5 7,10.5M13,10.5C12.2123,10.5 12.197,10.5 11.5,10.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M5.5,13H8.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#656A72"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M6,1C6,0.4477 6.4477,0 7,0C7.5523,0 8,0.4477 8,1V1.5H6V1Z"
|
||||
android:fillColor="#656A72"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:ignore="MissingDefaultResource">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/topLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
tools:ignore="MissingConstraints">
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.TitleBarView
|
||||
android:id="@+id/titleBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_52_dp"
|
||||
app:head_img_visible="visible"
|
||||
app:head_title="@string/conversation_title"
|
||||
app:head_title_color="@color/color_black"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<View
|
||||
android:id="@+id/conversationLine"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_1_dp"
|
||||
android:alpha="0.6"
|
||||
android:background="@color/color_e9eff5"
|
||||
tools:ignore="MissingConstraints" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bodyTopLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bodyLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
tools:ignore="MissingConstraints">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/errorTv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="36dp"
|
||||
android:background="@color/color_fee3e6"
|
||||
android:gravity="center"
|
||||
android:text="@string/conversation_network_error_tip"
|
||||
android:textColor="@color/color_fc596a"
|
||||
android:textSize="14dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.netease.yunxin.kit.conversationkit.ui.view.ConversationView
|
||||
android:id="@+id/conversationView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout android:id="@+id/emptyLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_188_dp"
|
||||
android:layout_marginTop="@dimen/dimen_150_dp"
|
||||
android:visibility="gone"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/dimen_118_dp"
|
||||
android:layout_height="@dimen/dimen_96_dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:src="@drawable/ic_conversation_empty"/>
|
||||
|
||||
<TextView android:id="@+id/empty_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/conversation_empty_tip"/>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bottomLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/rootView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_62_dp">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/avatarLayout"
|
||||
android:layout_width="@dimen/dimen_52_dp"
|
||||
android:layout_height="@dimen/dimen_42_dp"
|
||||
android:layout_marginVertical="@dimen/dimen_10_dp"
|
||||
android:layout_marginStart="@dimen/dimen_20_dp">
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.ContactAvatarView
|
||||
android:id="@+id/avatarView"
|
||||
android:layout_width="@dimen/dimen_42_dp"
|
||||
android:layout_height="@dimen/dimen_42_dp" />
|
||||
|
||||
<TextView android:id="@+id/unreadTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_marginEnd="@dimen/dimen_5_dp"
|
||||
android:background="@drawable/bg_conversation_red_dot"
|
||||
android:gravity="center"
|
||||
android:paddingStart="@dimen/dimen_5_dp"
|
||||
android:paddingEnd="@dimen/dimen_5_dp"
|
||||
android:textColor="@color/color_white"
|
||||
android:textSize="@dimen/text_size_12"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/contentLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="@dimen/dimen_74_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_20_dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nameTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen_10_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_100_dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_333333"
|
||||
android:textSize="@dimen/text_size_16" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen_35_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_18_dp"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/aitTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:layout_marginEnd="@dimen/dimen_4_dp"
|
||||
android:textColor="@color/color_ff4e54"
|
||||
android:visibility="gone"
|
||||
android:text="@string/conversation_ait_tip"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/messageTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_999999"/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/timeTv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="@dimen/dimen_12_dp"
|
||||
android:ellipsize="end"
|
||||
android:maxWidth="@dimen/dimen_100_dp"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_cccccc"
|
||||
android:textSize="@dimen/text_size_12" />
|
||||
|
||||
<ImageView android:id="@+id/muteIv"
|
||||
android:layout_width="@dimen/dimen_12_dp"
|
||||
android:layout_height="@dimen/dimen_12_dp"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="@dimen/dimen_38_dp"
|
||||
android:src="@drawable/ic_conversation_mute"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/root_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_62_dp">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_avatar_fl"
|
||||
android:layout_width="@dimen/dimen_52_dp"
|
||||
android:layout_height="@dimen/dimen_42_dp"
|
||||
android:layout_marginVertical="@dimen/dimen_10_dp"
|
||||
android:layout_marginStart="@dimen/dimen_20_dp">
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.ContactAvatarView
|
||||
android:id="@+id/avatar_view"
|
||||
android:layout_width="@dimen/dimen_42_dp"
|
||||
android:layout_height="@dimen/dimen_42_dp" />
|
||||
|
||||
<TextView android:id="@+id/conversation_unread_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_marginEnd="@dimen/dimen_5_dp"
|
||||
android:background="@drawable/bg_conversation_red_dot"
|
||||
android:gravity="center"
|
||||
android:paddingStart="@dimen/dimen_5_dp"
|
||||
android:paddingEnd="@dimen/dimen_5_dp"
|
||||
android:textColor="@color/color_white"
|
||||
android:textSize="@dimen/text_size_12"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_time_fl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="@dimen/dimen_74_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_20_dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conversation_name_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen_10_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_100_dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_333333"
|
||||
android:textSize="@dimen/text_size_16" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conversation_message_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:layout_marginTop="@dimen/dimen_35_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_18_dp"
|
||||
android:textColor="@color/color_999999" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conversation_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="@dimen/dimen_12_dp"
|
||||
android:ellipsize="end"
|
||||
android:maxWidth="@dimen/dimen_100_dp"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_cccccc"
|
||||
android:textSize="@dimen/text_size_12" />
|
||||
|
||||
<ImageView android:id="@+id/conversation_mute_iv"
|
||||
android:layout_width="@dimen/dimen_12_dp"
|
||||
android:layout_height="@dimen/dimen_12_dp"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="@dimen/dimen_38_dp"
|
||||
android:src="@drawable/ic_conversation_mute"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/root_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_62_dp">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_avatar_fl"
|
||||
android:layout_width="@dimen/dimen_52_dp"
|
||||
android:layout_height="@dimen/dimen_42_dp"
|
||||
android:layout_marginVertical="@dimen/dimen_10_dp"
|
||||
android:layout_marginStart="@dimen/dimen_20_dp">
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.ContactAvatarView
|
||||
android:id="@+id/avatar_view"
|
||||
android:layout_width="@dimen/dimen_42_dp"
|
||||
android:layout_height="@dimen/dimen_42_dp" />
|
||||
|
||||
<TextView android:id="@+id/conversation_unread_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_marginEnd="@dimen/dimen_5_dp"
|
||||
android:background="@drawable/bg_conversation_red_dot"
|
||||
android:gravity="center"
|
||||
android:paddingStart="@dimen/dimen_5_dp"
|
||||
android:paddingEnd="@dimen/dimen_5_dp"
|
||||
android:textColor="@color/color_white"
|
||||
android:textSize="@dimen/text_size_12"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_time_fl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="@dimen/dimen_74_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_20_dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conversation_name_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen_10_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_100_dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_333333"
|
||||
android:textSize="@dimen/text_size_16" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen_35_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_18_dp"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/conversation_ait_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:layout_marginEnd="@dimen/dimen_4_dp"
|
||||
android:textColor="@color/color_f24957"
|
||||
android:visibility="gone"
|
||||
android:text="@string/conversation_ait_tip"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conversation_message_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_999999"/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/conversation_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="@dimen/dimen_12_dp"
|
||||
android:ellipsize="end"
|
||||
android:maxWidth="@dimen/dimen_100_dp"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_cccccc"
|
||||
android:textSize="@dimen/text_size_12" />
|
||||
|
||||
<ImageView android:id="@+id/conversation_mute_iv"
|
||||
android:layout_width="@dimen/dimen_12_dp"
|
||||
android:layout_height="@dimen/dimen_12_dp"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="@dimen/dimen_38_dp"
|
||||
android:src="@drawable/ic_conversation_mute"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="@dimen/dimen_10_dp" />
|
||||
<solid android:color="@color/color_cccccc" />
|
||||
</shape>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="@dimen/dimen_10_dp" />
|
||||
<solid android:color="@color/color_ff4e54" />
|
||||
</shape>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<selector xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" tools:ignore="MissingDefaultResource">
|
||||
|
||||
<item android:drawable="@color/color_white" android:state_pressed="false" />
|
||||
<item android:drawable="@color/color_ededef" android:state_pressed="true" />
|
||||
</selector>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!-- Copyright (c) 2022 NetEase, Inc. All rights reserved. -->
|
||||
<!-- Use of this source code is governed by a MIT license that can be -->
|
||||
<!-- found in the LICENSE file. -->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M9,9m-8.5,0a8.5,8.5 0,1 1,17 0a8.5,8.5 0,1 1,-17 0"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#969AA0" />
|
||||
</vector>
|
||||
@@ -0,0 +1,16 @@
|
||||
<!-- Copyright (c) 2022 NetEase, Inc. All rights reserved. -->
|
||||
<!-- Use of this source code is governed by a MIT license that can be -->
|
||||
<!-- found in the LICENSE file. -->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:pathData="M9,9m-9,0a9,9 0,1 1,18 0a9,9 0,1 1,-18 0"
|
||||
android:fillColor="#337EFF" />
|
||||
<path
|
||||
android:pathData="M5.1508,8.7407C4.7315,8.3813 4.1002,8.4299 3.7407,8.8492C3.3813,9.2685 3.4299,9.8998 3.8492,10.2593L5.1508,8.7407ZM8,12.5L7.3492,13.2593C7.7587,13.6102 8.3727,13.5733 8.7372,13.1757L8,12.5ZM14.2372,7.1757C14.6103,6.7686 14.5828,6.136 14.1757,5.7628C13.7686,5.3896 13.136,5.4172 12.7628,5.8243L14.2372,7.1757ZM3.8492,10.2593L7.3492,13.2593L8.6508,11.7407L5.1508,8.7407L3.8492,10.2593ZM8.7372,13.1757L14.2372,7.1757L12.7628,5.8243L7.2628,11.8243L8.7372,13.1757Z"
|
||||
android:fillColor="#ffffff" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (c) 2022 NetEase, Inc. All rights reserved. -->
|
||||
<!-- Use of this source code is governed by a MIT license that can be -->
|
||||
<!-- found in the LICENSE file. -->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@drawable/conversation_radio_button_selected" android:state_checked="true" />
|
||||
|
||||
<item android:drawable="@drawable/conversation_radio_button_not_selected" android:state_checked="false" />
|
||||
|
||||
</selector>
|
||||
@@ -0,0 +1,17 @@
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M9,9m-8.5,0a8.5,8.5 0,1 1,17 0a8.5,8.5 0,1 1,-17 0"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#969AA0" />
|
||||
</vector>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:pathData="M9,9m-9,0a9,9 0,1 1,18 0a9,9 0,1 1,-18 0"
|
||||
android:fillColor="#337EFF" />
|
||||
<path
|
||||
android:pathData="M5.1508,8.7407C4.7315,8.3813 4.1002,8.4299 3.7407,8.8492C3.3813,9.2685 3.4299,9.8998 3.8492,10.2593L5.1508,8.7407ZM8,12.5L7.3492,13.2593C7.7587,13.6102 8.3727,13.5733 8.7372,13.1757L8,12.5ZM14.2372,7.1757C14.6103,6.7686 14.5828,6.136 14.1757,5.7628C13.7686,5.3896 13.136,5.4172 12.7628,5.8243L14.2372,7.1757ZM3.8492,10.2593L7.3492,13.2593L8.6508,11.7407L5.1508,8.7407L3.8492,10.2593ZM8.7372,13.1757L14.2372,7.1757L12.7628,5.8243L7.2628,11.8243L8.7372,13.1757Z"
|
||||
android:fillColor="#ffffff" />
|
||||
</vector>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@drawable/ic_conversation_radio_button_selected" android:state_checked="true" />
|
||||
|
||||
<item android:drawable="@drawable/ic_conversation_radio_button_not_selected" android:state_checked="false" />
|
||||
|
||||
</selector>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.BackTitleBar
|
||||
android:id="@+id/conversation_selector_title_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_60_dp"
|
||||
app:leftTitleText="@string/cancel_title"
|
||||
app:rightTitleText="@string/sure_title"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<TextView android:id="@+id/conversation_subtitle_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/text_size_12"
|
||||
android:textColor="@color/color_999999"
|
||||
android:text="@string/recent_title"
|
||||
android:layout_marginLeft="@dimen/dimen_20_dp"
|
||||
/>
|
||||
|
||||
|
||||
<com.netease.yunxin.kit.conversationkit.ui.view.ConversationView
|
||||
android:id="@+id/conversation_selector_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/dimen_12_dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:ignore="MissingDefaultResource">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/conversation_top_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.TitleBarView
|
||||
android:id="@+id/conversation_title_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_52_dp"
|
||||
app:head_img_visible="visible"
|
||||
app:head_title="@string/conversation_title"
|
||||
app:head_title_color="@color/color_black"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<View
|
||||
android:id="@+id/conversation_line"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_1_dp"
|
||||
android:alpha="0.6"
|
||||
android:background="@color/color_e9eff5"
|
||||
tools:ignore="MissingConstraints" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_body_top_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/conversation_body_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conversation_network_error_tv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="36dp"
|
||||
android:background="@color/color_fee3e6"
|
||||
android:gravity="center"
|
||||
android:text="@string/conversation_network_error_tip"
|
||||
android:textColor="@color/color_fc596a"
|
||||
android:textSize="14dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.netease.yunxin.kit.conversationkit.ui.view.ConversationView
|
||||
android:id="@+id/conversation_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout android:id="@+id/conversation_empty_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen_188_dp"
|
||||
android:layout_marginTop="@dimen/dimen_150_dp"
|
||||
android:visibility="gone"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/dimen_118_dp"
|
||||
android:layout_height="@dimen/dimen_96_dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:src="@drawable/ic_conversation_empty"/>
|
||||
|
||||
<TextView android:id="@+id/empty_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/conversation_empty_tip"/>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_bottom_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</merge>
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/root_view"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@drawable/conversation_common_view_holder_selector"
|
||||
android:orientation="horizontal"
|
||||
android:layout_height="@dimen/dimen_62_dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatRadioButton
|
||||
android:id="@+id/conversation_selector_cb"
|
||||
android:layout_width="@dimen/dimen_18_dp"
|
||||
android:layout_height="@dimen/dimen_18_dp"
|
||||
android:layout_marginStart="@dimen/dimen_20_dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
style="@style/ConversationSelectorRadioBtn"
|
||||
android:clickable="false"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_avatar_fl"
|
||||
android:layout_width="@dimen/dimen_52_dp"
|
||||
android:layout_height="@dimen/dimen_42_dp"
|
||||
android:layout_marginVertical="@dimen/dimen_10_dp"
|
||||
android:layout_marginStart="@dimen/dimen_20_dp">
|
||||
|
||||
<com.netease.yunxin.kit.common.ui.widgets.ContactAvatarView
|
||||
android:id="@+id/avatar_view"
|
||||
android:layout_width="@dimen/dimen_42_dp"
|
||||
android:layout_height="@dimen/dimen_42_dp" />
|
||||
|
||||
<TextView android:id="@+id/conversation_unread_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_marginEnd="@dimen/dimen_5_dp"
|
||||
android:background="@drawable/bg_conversation_red_dot"
|
||||
android:gravity="center"
|
||||
android:paddingStart="@dimen/dimen_5_dp"
|
||||
android:paddingEnd="@dimen/dimen_5_dp"
|
||||
android:textColor="@color/color_white"
|
||||
android:textSize="@dimen/text_size_12"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/conversation_name_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen_10_dp"
|
||||
android:layout_marginEnd="@dimen/dimen_100_dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/color_333333"
|
||||
android:textSize="@dimen/text_size_16" />
|
||||
|
||||
</LinearLayout>
|
||||
48
conversationkit-ui/src/main/res/values-en/string.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="conversation_title">CommsEase IM</string>
|
||||
<string name="add_friend">Add Contacts</string>
|
||||
<string name="create_group_team">Create Temp Group</string>
|
||||
<string name="create_advanced_team"> Create Group</string>
|
||||
<string name="create_advanced_team_success">Create group successfully</string>
|
||||
|
||||
<string name="stick_title">Sticky on Top</string>
|
||||
<string name="cancel_stick_title">Unpin</string>
|
||||
<string name="delete_title">Delete this chat</string>
|
||||
<string name="hide_title">Hide this chat</string>
|
||||
<string name="recent_title">Last chat</string>
|
||||
<string name="cancel_title">Cancel </string>
|
||||
<string name="sure_title">Yes</string>
|
||||
<string name="sure_count_title">Yes(%d)</string>
|
||||
|
||||
<string name="conversation_network_error_tip">No Internet</string>
|
||||
<string name="conversation_empty_tip">No Chat</string>
|
||||
<string name="conversation_service_empty_tip">No customer service session record yet</string>
|
||||
<string name="conversation_ait_tip">[You were mentioned]</string>
|
||||
<string name="conversation_draft_tip">[Draft]</string>
|
||||
<!-- message type-->
|
||||
<string name="msg_type_location">[Location Message]</string>
|
||||
<string name="msg_type_rtc_video">[Video Call]</string>
|
||||
<string name="msg_type_rtc_audio">[Audio Call]</string>
|
||||
<string name="msg_type_image">[Photo Message]</string>
|
||||
<string name="msg_type_audio">[Voice Message]</string>
|
||||
<string name="msg_type_video">[Video Message]</string>
|
||||
<string name="msg_type_file">[File Message]</string>
|
||||
<string name="msg_type_notification">[Notification Message]</string>
|
||||
<string name="msg_type_notification_announcement">[Group Announcement] %s</string>
|
||||
<string name="msg_type_tip">[Tip Message]</string>
|
||||
<string name="msg_type_custom">[Custom Message]</string>
|
||||
<string name="msg_type_no_tips">[Unknown Message]</string>
|
||||
|
||||
<string name="fun_conversation_search_text">Search</string>
|
||||
<string name="time_zuotian_txt">Yesterday</string>
|
||||
<string name="mine_text">Mine</string>
|
||||
|
||||
<string name="chat_message_revoke_content">recalled the message</string>
|
||||
<string name="services_text">Service</string>
|
||||
</resources>
|
||||
50
conversationkit-ui/src/main/res/values-ja/string.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="conversation_title">クラウド IM</string>
|
||||
<string name="add_friend">友達を追加</string>
|
||||
<string name="create_group_team">ディスカッション グループを作成する</string>
|
||||
<string name="create_advanced_team">高度なグループを作成する</string>
|
||||
<string name="create_advanced_team_success">グループ チャットが正常に作成されました</string>
|
||||
|
||||
<string name="stick_title">このチャットを選択してください</string>
|
||||
<string name="cancel_stick_title">スティックをキャンセル</string>
|
||||
<string name="delete_title">このチャットを削除</string>
|
||||
<string name="hide_title">このチャットを非表示にする</string>
|
||||
<string name="recent_title">最近のチャット</string>
|
||||
<string name="cancel_title">キャンセル</string>
|
||||
<string name="sure_title">OK</string>
|
||||
<string name="sure_count_title">確認(%d)</string>
|
||||
|
||||
<string name="conversation_network_error_tip">ネットワークは現在利用できません。ネットワーク設定を確認してください。 </string>
|
||||
<string name="conversation_empty_tip">まだ会話がありません</string>
|
||||
<string name="conversation_service_empty_tip">カスタマーサービスセッションの記録はまだありません</string>
|
||||
<string name="conversation_ait_tip">[Someone@me]</string>
|
||||
<string name="conversation_draft_tip">[下書き]</string>
|
||||
|
||||
<!-- メッセージ タイプ -->
|
||||
<string name="msg_type_location">[地理的位置]</string>
|
||||
<string name="msg_type_rtc_video">[ビデオ通話]</string>
|
||||
<string name="msg_type_rtc_audio">[音声通話]</string>
|
||||
<string name="msg_type_image">[画像メッセージ]</string>
|
||||
<string name="msg_type_audio">[音声メッセージ]</string>
|
||||
<string name="msg_type_video">[ビデオメッセージ]</string>
|
||||
<string name="msg_type_file">[ファイル メッセージ]</string>
|
||||
<string name="msg_type_notification">[通知メッセージ]</string>
|
||||
<string name="msg_type_notification_announcement">[グループのお知らせ] %s</string>
|
||||
<string name="msg_type_tip">[リマインダーメッセージ]</string>
|
||||
<string name="msg_type_custom">[カスタム メッセージ]</string>
|
||||
<string name="msg_type_no_tips">[不明なメッセージ本文]</string>
|
||||
|
||||
<string name="fun_conversation_search_text">検索</string>
|
||||
<string name="time_zuotian_txt">昨日</string>
|
||||
<string name="mine_text">私の</string>
|
||||
|
||||
<string name="chat_message_revoke_content">がメッセージを撤回しました</string>
|
||||
<string name="services_text">顧客サービス</string>
|
||||
</resources>
|
||||
49
conversationkit-ui/src/main/res/values-zh/string.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="conversation_title">云信IM</string>
|
||||
<string name="add_friend">添加好友</string>
|
||||
<string name="create_group_team">创建讨论组</string>
|
||||
<string name="create_advanced_team">创建高级群</string>
|
||||
<string name="create_advanced_team_success">成功创建了群聊</string>
|
||||
|
||||
<string name="stick_title">置顶该聊天</string>
|
||||
<string name="cancel_stick_title">取消置顶</string>
|
||||
<string name="delete_title">删除该聊天</string>
|
||||
<string name="hide_title">隐藏该聊天</string>
|
||||
<string name="recent_title">最近聊天</string>
|
||||
<string name="cancel_title">取消</string>
|
||||
<string name="sure_title">确定</string>
|
||||
<string name="sure_count_title">确定(%d)</string>
|
||||
|
||||
<string name="conversation_network_error_tip">当前网络不可用,请检查你当网络设置。</string>
|
||||
<string name="conversation_empty_tip">暂无会话</string>
|
||||
<string name="conversation_service_empty_tip">暂无客服会话记录</string>
|
||||
<string name="conversation_ait_tip">[有人@我]</string>
|
||||
<string name="conversation_draft_tip">[草稿]</string>
|
||||
<!-- message type-->
|
||||
<string name="msg_type_location">[地理位置]</string>
|
||||
<string name="msg_type_rtc_video">[视频通话]</string>
|
||||
<string name="msg_type_rtc_audio">[音频通话]</string>
|
||||
<string name="msg_type_image">[图片消息]</string>
|
||||
<string name="msg_type_audio">[语音消息]</string>
|
||||
<string name="msg_type_video">[视频消息]</string>
|
||||
<string name="msg_type_file">[文件消息]</string>
|
||||
<string name="msg_type_notification">[通知消息]</string>
|
||||
<string name="msg_type_notification_announcement">[群公告] %s</string>
|
||||
<string name="msg_type_tip">[提醒消息]</string>
|
||||
<string name="msg_type_custom">[自定义消息]</string>
|
||||
<string name="msg_type_no_tips">[未知消息体]</string>
|
||||
|
||||
<string name="fun_conversation_search_text">搜索</string>
|
||||
<string name="time_zuotian_txt">昨天</string>
|
||||
<string name="mine_text">我的</string>
|
||||
|
||||
<string name="chat_message_revoke_content">撤回了一条消息</string>
|
||||
<string name="services_text">客服</string>
|
||||
</resources>
|
||||
20
conversationkit-ui/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="color_white">#FFFFFF</color>
|
||||
<color name="color_333333">#333333</color>
|
||||
<color name="color_337eff">#337eff</color>
|
||||
<color name="color_ededef">#ededef</color>
|
||||
<color name="color_666666">#666666</color>
|
||||
<color name="color_ff4e54">#ff4e54</color>
|
||||
<color name="color_999999">#999999</color>
|
||||
<color name="color_cccccc">#cccccc</color>
|
||||
<color name="color_9e9e9e">#9e9e9e</color>
|
||||
<color name="color_e9eff5">#e9eff5</color>
|
||||
<color name="color_fee3e6">#fee3e6</color>
|
||||
<color name="color_fc596a">#fc596a</color>
|
||||
<color name="color_50_000000">#7f000000</color>
|
||||
<color name="color_fceeee">#fceeee</color>
|
||||
<color name="color_5a5a5a">#5a5a5a</color>
|
||||
<color name="color_7e7b84">#7E7B84</color>
|
||||
<color name="color_f4f4f4">#f4f4f4</color>
|
||||
</resources>
|
||||
21
conversationkit-ui/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="pop_margin_right">-105dp</dimen>
|
||||
<dimen name="pop_item_height">32dp</dimen>
|
||||
<dimen name="pop_text_margin_left">15dp</dimen>
|
||||
<dimen name="pop_text_margin_right_top">8dp</dimen>
|
||||
<dimen name="alert_dialog_width">188dp</dimen>
|
||||
<dimen name="dimen_62_dp">62dp</dimen>
|
||||
<dimen name="dimen_60_dp">60dp</dimen>
|
||||
<dimen name="dimen_38_dp">38dp</dimen>
|
||||
<dimen name="dimen_52_dp">52dp</dimen>
|
||||
<dimen name="dimen_42_dp">42dp</dimen>
|
||||
<dimen name="dimen_5_dp">5dp</dimen>
|
||||
<dimen name="dimen_74_dp">74dp</dimen>
|
||||
<dimen name="dimen_100_dp">100dp</dimen>
|
||||
<dimen name="dimen_18_dp">18dp</dimen>
|
||||
<dimen name="dimen_8_dp">8dp</dimen>
|
||||
<dimen name="dimen_14_dp">14dp</dimen>
|
||||
|
||||
<dimen name="text_size_12">12sp</dimen>
|
||||
</resources>
|
||||
4
conversationkit-ui/src/main/res/values/ids.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<item name="conversation_rv" type="id"/>
|
||||
</resources>
|
||||
50
conversationkit-ui/src/main/res/values/string.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="conversation_title">雲端信IM</string>
|
||||
<string name="add_friend">新增好友</string>
|
||||
<string name="create_group_team">建立討論群組</string>
|
||||
<string name="create_advanced_team">建立高級群</string>
|
||||
<string name="create_advanced_team_success">成功建立了群組聊天</string>
|
||||
|
||||
<string name="stick_title">置頂該聊天</string>
|
||||
<string name="cancel_stick_title">取消置頂</string>
|
||||
<string name="delete_title">刪除該聊天</string>
|
||||
<string name="hide_title">隱藏該聊天</string>
|
||||
<string name="recent_title">最近聊天</string>
|
||||
<string name="cancel_title">取消</string>
|
||||
<string name="sure_title">確定</string>
|
||||
<string name="sure_count_title">確定(%d)</string>
|
||||
|
||||
<string name="conversation_network_error_tip">目前網路不可用,請檢查你當網路設定。 </string>
|
||||
<string name="conversation_empty_tip">暫無會話</string>
|
||||
<string name="conversation_service_empty_tip">暫無客服會話記錄</string>
|
||||
<string name="conversation_ait_tip">[有人@我]</string>
|
||||
<string name="conversation_draft_tip">[草稿]</string>
|
||||
|
||||
<!-- message type-->
|
||||
<string name="msg_type_location">[地理位置]</string>
|
||||
<string name="msg_type_rtc_video">[視訊通話]</string>
|
||||
<string name="msg_type_rtc_audio">[音訊通話]</string>
|
||||
<string name="msg_type_image">[圖片訊息]</string>
|
||||
<string name="msg_type_audio">[語音訊息]</string>
|
||||
<string name="msg_type_video">[視訊訊息]</string>
|
||||
<string name="msg_type_file">[檔案訊息]</string>
|
||||
<string name="msg_type_notification">[通知訊息]</string>
|
||||
<string name="msg_type_notification_announcement">[群公告] %s</string>
|
||||
<string name="msg_type_tip">[提醒訊息]</string>
|
||||
<string name="msg_type_custom">[自訂訊息]</string>
|
||||
<string name="msg_type_no_tips">[未知訊息體]</string>
|
||||
|
||||
<string name="fun_conversation_search_text">搜尋</string>
|
||||
<string name="time_zuotian_txt">昨天</string>
|
||||
<string name="mine_text">我的</string>
|
||||
|
||||
<string name="chat_message_revoke_content">撤回了一則訊息</string>
|
||||
<string name="services_text">客服</string>
|
||||
</resources>
|
||||
13
conversationkit-ui/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<style name="ConversationSelectorRadioBtn" parent="Widget.AppCompat.CompoundButton.RadioButton">
|
||||
<item name="android:button">@drawable/conversation_radio_button_selector</item>
|
||||
</style>
|
||||
</resources>
|
||||
253
conversationkit-ui/src/main/res/xml/emoji.xml
Normal file
@@ -0,0 +1,253 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 NetEase, Inc. All rights reserved.
|
||||
~ Use of this source code is governed by a MIT license that can be
|
||||
~ found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<PopoEmoticons>
|
||||
<Catalog Title="default">
|
||||
<Emoticon File="emoji_00.png" ID="emoticon_emoji_0" Tag="[大笑]" />
|
||||
<Emoticon File="emoji_01.png" ID="emoticon_emoji_01" Tag="[开心]" />
|
||||
<Emoticon File="emoji_02.png" ID="emoticon_emoji_02" Tag="[色]" />
|
||||
<Emoticon File="emoji_03.png" ID="emoticon_emoji_03" Tag="[酷]" />
|
||||
<Emoticon File="emoji_04.png" ID="emoticon_emoji_04" Tag="[奸笑]" />
|
||||
<Emoticon File="emoji_05.png" ID="emoticon_emoji_05" Tag="[亲]" />
|
||||
<Emoticon File="emoji_06.png" ID="emoticon_emoji_06" Tag="[伸舌头]" />
|
||||
<Emoticon File="emoji_07.png" ID="emoticon_emoji_07" Tag="[眯眼]" />
|
||||
<Emoticon File="emoji_08.png" ID="emoticon_emoji_08" Tag="[可爱]" />
|
||||
<Emoticon File="emoji_09.png" ID="emoticon_emoji_09" Tag="[鬼脸]" />
|
||||
<Emoticon File="emoji_10.png" ID="emoticon_emoji_10" Tag="[偷笑]" />
|
||||
<Emoticon File="emoji_11.png" ID="emoticon_emoji_11" Tag="[喜悦]" />
|
||||
<Emoticon File="emoji_12.png" ID="emoticon_emoji_12" Tag="[狂喜]" />
|
||||
<Emoticon File="emoji_13.png" ID="emoticon_emoji_13" Tag="[惊讶]" />
|
||||
<Emoticon File="emoji_14.png" ID="emoticon_emoji_14" Tag="[流泪]" />
|
||||
<Emoticon File="emoji_15.png" ID="emoticon_emoji_15" Tag="[流汗]" />
|
||||
<Emoticon File="emoji_16.png" ID="emoticon_emoji_16" Tag="[天使]" />
|
||||
<Emoticon File="emoji_17.png" ID="emoticon_emoji_17" Tag="[笑哭]" />
|
||||
<Emoticon File="emoji_18.png" ID="emoticon_emoji_18" Tag="[尴尬]" />
|
||||
<Emoticon File="emoji_19.png" ID="emoticon_emoji_19" Tag="[惊恐]" />
|
||||
<Emoticon File="emoji_20.png" ID="emoticon_emoji_20" Tag="[大哭]" />
|
||||
<Emoticon File="emoji_21.png" ID="emoticon_emoji_21" Tag="[烦躁]" />
|
||||
<Emoticon File="emoji_22.png" ID="emoticon_emoji_22" Tag="[恐怖]" />
|
||||
<Emoticon File="emoji_23.png" ID="emoticon_emoji_23" Tag="[两眼冒星]" />
|
||||
<Emoticon File="emoji_24.png" ID="emoticon_emoji_24" Tag="[害羞]" />
|
||||
<Emoticon File="emoji_25.png" ID="emoticon_emoji_25" Tag="[睡着]" />
|
||||
<Emoticon File="emoji_26.png" ID="emoticon_emoji_26" Tag="[冒星]" />
|
||||
<Emoticon File="emoji_27.png" ID="emoticon_emoji_27" Tag="[口罩]" />
|
||||
<Emoticon File="emoji_28.png" ID="emoticon_emoji_28" Tag="[OK]" />
|
||||
<Emoticon File="emoji_29.png" ID="emoticon_emoji_29" Tag="[好吧]" />
|
||||
<Emoticon File="emoji_30.png" ID="emoticon_emoji_30" Tag="[鄙视]" />
|
||||
<Emoticon File="emoji_31.png" ID="emoticon_emoji_31" Tag="[难受]" />
|
||||
<Emoticon File="emoji_32.png" ID="emoticon_emoji_32" Tag="[不屑]" />
|
||||
<Emoticon File="emoji_33.png" ID="emoticon_emoji_33" Tag="[不舒服]" />
|
||||
<Emoticon File="emoji_34.png" ID="emoticon_emoji_34" Tag="[愤怒]" />
|
||||
<Emoticon File="emoji_35.png" ID="emoticon_emoji_35" Tag="[鬼怪]" />
|
||||
<Emoticon File="emoji_36.png" ID="emoticon_emoji_36" Tag="[发怒]" />
|
||||
<Emoticon File="emoji_37.png" ID="emoticon_emoji_37" Tag="[生气]" />
|
||||
<Emoticon File="emoji_38.png" ID="emoticon_emoji_38" Tag="[不高兴]" />
|
||||
<Emoticon File="emoji_39.png" ID="emoticon_emoji_39" Tag="[皱眉]" />
|
||||
<Emoticon File="emoji_40.png" ID="emoticon_emoji_40" Tag="[心碎]" />
|
||||
<Emoticon File="emoji_41.png" ID="emoticon_emoji_41" Tag="[心动]" />
|
||||
<Emoticon File="emoji_42.png" ID="emoticon_emoji_42" Tag="[好的]" />
|
||||
<Emoticon File="emoji_43.png" ID="emoticon_emoji_43" Tag="[低级]" />
|
||||
<Emoticon File="emoji_44.png" ID="emoticon_emoji_44" Tag="[赞]" />
|
||||
<Emoticon File="emoji_45.png" ID="emoticon_emoji_45" Tag="[鼓掌]" />
|
||||
<Emoticon File="emoji_46.png" ID="emoticon_emoji_46" Tag="[给力]" />
|
||||
<Emoticon File="emoji_47.png" ID="emoticon_emoji_47" Tag="[打你]" />
|
||||
<Emoticon File="emoji_48.png" ID="emoticon_emoji_48" Tag="[阿弥陀佛]" />
|
||||
<Emoticon File="emoji_49.png" ID="emoticon_emoji_49" Tag="[拜拜]" />
|
||||
<Emoticon File="emoji_50.png" ID="emoticon_emoji_50" Tag="[第一]" />
|
||||
<Emoticon File="emoji_51.png" ID="emoticon_emoji_51" Tag="[拳头]" />
|
||||
<Emoticon File="emoji_52.png" ID="emoticon_emoji_52" Tag="[手掌]" />
|
||||
<Emoticon File="emoji_53.png" ID="emoticon_emoji_53" Tag="[剪刀]" />
|
||||
<Emoticon File="emoji_54.png" ID="emoticon_emoji_54" Tag="[招手]" />
|
||||
<Emoticon File="emoji_55.png" ID="emoticon_emoji_55" Tag="[不要]" />
|
||||
<Emoticon File="emoji_56.png" ID="emoticon_emoji_56" Tag="[举着]" />
|
||||
<Emoticon File="emoji_57.png" ID="emoticon_emoji_57" Tag="[思考]" />
|
||||
<Emoticon File="emoji_58.png" ID="emoticon_emoji_58" Tag="[猪头]" />
|
||||
<Emoticon File="emoji_59.png" ID="emoticon_emoji_59" Tag="[不听]" />
|
||||
<Emoticon File="emoji_60.png" ID="emoticon_emoji_60" Tag="[不看]" />
|
||||
<Emoticon File="emoji_61.png" ID="emoticon_emoji_61" Tag="[不说]" />
|
||||
<Emoticon File="emoji_62.png" ID="emoticon_emoji_62" Tag="[猴子]" />
|
||||
<Emoticon File="emoji_63.png" ID="emoticon_emoji_63" Tag="[炸弹]" />
|
||||
<Emoticon File="emoji_64.png" ID="emoticon_emoji_64" Tag="[睡觉]" />
|
||||
<Emoticon File="emoji_65.png" ID="emoticon_emoji_65" Tag="[筋斗云]" />
|
||||
<Emoticon File="emoji_66.png" ID="emoticon_emoji_66" Tag="[火箭]" />
|
||||
<Emoticon File="emoji_67.png" ID="emoticon_emoji_67" Tag="[救护车]" />
|
||||
<Emoticon File="emoji_68.png" ID="emoticon_emoji_68" Tag="[便便]" />
|
||||
</Catalog>
|
||||
|
||||
<Catalog Title="tingting">
|
||||
<Emoticon File="tingting_00.png" ID="emoticon_tingting_00" Tag="[町町安靜]" />
|
||||
<Emoticon File="tingting_01.png" ID="emoticon_emoji_01" Tag="[町町無辜]" />
|
||||
<Emoticon File="tingting_02.png" ID="emoticon_tingting_02" Tag="[町町白眼]" />
|
||||
<Emoticon File="tingting_03.png" ID="emoticon_tingting_03" Tag="[町町生氣]" />
|
||||
<Emoticon File="tingting_04.png" ID="emoticon_tingting_04" Tag="[町町再見]" />
|
||||
<Emoticon File="tingting_05.png" ID="emoticon_tingting_05" Tag="[町町閉嘴]" />
|
||||
<Emoticon File="tingting_06.png" ID="emoticon_tingting_06" Tag="[町町犯困]" />
|
||||
<Emoticon File="tingting_07.png" ID="emoticon_tingting_07" Tag="[町町尷尬]" />
|
||||
<Emoticon File="tingting_08.png" ID="emoticon_tingting_08" Tag="[町町感動]" />
|
||||
<Emoticon File="tingting_09.png" ID="emoticon_tingting_09" Tag="[町町鼓掌]" />
|
||||
<Emoticon File="tingting_10.png" ID="emoticon_tingting_10" Tag="[町町害羞]" />
|
||||
<Emoticon File="tingting_11.png" ID="emoticon_tingting_11" Tag="[町町好色]" />
|
||||
<Emoticon File="tingting_12.png" ID="emoticon_tingting_12" Tag="[町町黑臉]" />
|
||||
<Emoticon File="tingting_13.png" ID="emoticon_tingting_13" Tag="[町町急怒]" />
|
||||
<Emoticon File="tingting_14.png" ID="emoticon_tingting_14" Tag="[町町驚慌]" />
|
||||
<Emoticon File="tingting_15.png" ID="emoticon_tingting_15" Tag="[町町驚訝]" />
|
||||
<Emoticon File="tingting_16.png" ID="emoticon_tingting_16" Tag="[町町沮喪]" />
|
||||
<Emoticon File="tingting_17.png" ID="emoticon_tingting_17" Tag="[町町開心]" />
|
||||
<Emoticon File="tingting_18.png" ID="emoticon_tingting_18" Tag="[町町瞌睡]" />
|
||||
<Emoticon File="tingting_19.png" ID="emoticon_tingting_19" Tag="[町町摳鼻]" />
|
||||
<Emoticon File="tingting_20.png" ID="emoticon_tingting_20" Tag="[町町哭泣]" />
|
||||
<Emoticon File="tingting_21.png" ID="emoticon_tingting_21" Tag="[町町苦臉]" />
|
||||
<Emoticon File="tingting_22.png" ID="emoticon_tingting_22" Tag="[町町酷]" />
|
||||
<Emoticon File="tingting_23.png" ID="emoticon_tingting_23" Tag="[町町 酷]" />
|
||||
<Emoticon File="tingting_24.png" ID="emoticon_tingting_24" Tag="[町町狂躁]" />
|
||||
<Emoticon File="tingting_25.png" ID="emoticon_tingting_25" Tag="[町町流汗]" />
|
||||
<Emoticon File="tingting_26.png" ID="emoticon_tingting_26" Tag="[町町罵人]" />
|
||||
<Emoticon File="tingting_27.png" ID="emoticon_tingting_27" Tag="[町町發怒]" />
|
||||
<Emoticon File="tingting_28.png" ID="emoticon_tingting_28" Tag="[町町氣哭]" />
|
||||
<Emoticon File="tingting_29.png" ID="emoticon_tingting_29" Tag="[町町敲頭]" />
|
||||
<Emoticon File="tingting_30.png" ID="emoticon_tingting_30" Tag="[町町親親]" />
|
||||
<Emoticon File="tingting_31.png" ID="emoticon_tingting_31" Tag="[町町吐舌頭]" />
|
||||
<Emoticon File="tingting_32.png" ID="emoticon_tingting_32" Tag="[町町微笑]" />
|
||||
<Emoticon File="tingting_33.png" ID="emoticon_tingting_33" Tag="[町町捂嘴笑]" />
|
||||
<Emoticon File="tingting_34.png" ID="emoticon_tingting_34" Tag="[町町兇]" />
|
||||
<Emoticon File="tingting_35.png" ID="emoticon_tingting_35" Tag="[町町羞笑]" />
|
||||
<Emoticon File="tingting_36.png" ID="emoticon_tingting_36" Tag="[町町眩暈]" />
|
||||
<Emoticon File="tingting_37.png" ID="emoticon_tingting_37" Tag="[町町疑問]" />
|
||||
<Emoticon File="tingting_38.png" ID="emoticon_tingting_38" Tag="[町町中毒]" />
|
||||
<Emoticon File="tingting_39.png" ID="emoticon_tingting_39" Tag="[町町齜牙]" />
|
||||
|
||||
</Catalog>
|
||||
|
||||
<Catalog Title="taotao">
|
||||
<Emoticon File="taotao_00.png" ID="emoticon_taotao_00" Tag="[淘淘安靜]" />
|
||||
<Emoticon File="taotao_01.png" ID="emoticon_taotao_01" Tag="[淘淘白眼]" />
|
||||
<Emoticon File="taotao_02.png" ID="emoticon_taotao_02" Tag="[淘淘生氣]" />
|
||||
<Emoticon File="taotao_03.png" ID="emoticon_taotao_03" Tag="[淘淘閉嘴]" />
|
||||
<Emoticon File="taotao_04.png" ID="emoticon_taotao_04" Tag="[淘淘犯困]" />
|
||||
<Emoticon File="taotao_05.png" ID="emoticon_taotao_05" Tag="[淘淘尷尬]" />
|
||||
<Emoticon File="taotao_06.png" ID="emoticon_taotao_06" Tag="[淘淘感動]" />
|
||||
<Emoticon File="taotao_07.png" ID="emoticon_taotao_07" Tag="[淘淘鼓掌]" />
|
||||
<Emoticon File="taotao_08.png" ID="emoticon_taotao_08" Tag="[淘淘害羞]" />
|
||||
<Emoticon File="taotao_09.png" ID="emoticon_taotao_09" Tag="[淘淘好色]" />
|
||||
<Emoticon File="taotao_10.png" ID="emoticon_taotao_10" Tag="[淘淘黑臉]" />
|
||||
<Emoticon File="taotao_11.png" ID="emoticon_taotao_11" Tag="[淘淘急怒]" />
|
||||
<Emoticon File="taotao_12.png" ID="emoticon_taotao_12" Tag="[淘淘驚慌]" />
|
||||
<Emoticon File="taotao_13.png" ID="emoticon_taotao_13" Tag="[淘淘驚訝]" />
|
||||
<Emoticon File="taotao_14.png" ID="emoticon_taotao_14" Tag="[淘淘沮喪]" />
|
||||
<Emoticon File="taotao_15.png" ID="emoticon_taotao_15" Tag="[淘淘開心]" />
|
||||
<Emoticon File="taotao_16.png" ID="emoticon_taotao_16" Tag="[淘淘瞌睡]" />
|
||||
<Emoticon File="taotao_17.png" ID="emoticon_taotao_17" Tag="[淘淘摳鼻]" />
|
||||
<Emoticon File="taotao_18.png" ID="emoticon_taotao_18" Tag="[淘淘哭泣]" />
|
||||
<Emoticon File="taotao_19.png" ID="emoticon_taotao_19" Tag="[淘淘苦臉]" />
|
||||
<Emoticon File="taotao_20.png" ID="emoticon_taotao_20" Tag="[淘淘酷]" />
|
||||
<Emoticon File="taotao_21.png" ID="emoticon_taotao_21" Tag="[淘淘 酷]" />
|
||||
<Emoticon File="taotao_22.png" ID="emoticon_taotao_22" Tag="[淘淘狂躁]" />
|
||||
<Emoticon File="taotao_23.png" ID="emoticon_taotao_23" Tag="[淘淘流汗]" />
|
||||
<Emoticon File="taotao_24.png" ID="emoticon_taotao_24" Tag="[淘淘罵人]" />
|
||||
<Emoticon File="taotao_25.png" ID="emoticon_taotao_25" Tag="[淘淘發怒]" />
|
||||
<Emoticon File="taotao_26.png" ID="emoticon_taotao_26" Tag="[淘淘氣哭]" />
|
||||
<Emoticon File="taotao_27.png" ID="emoticon_taotao_27" Tag="[淘淘敲頭]" />
|
||||
<Emoticon File="taotao_28.png" ID="emoticon_taotao_28" Tag="[淘淘親親]" />
|
||||
<Emoticon File="taotao_29.png" ID="emoticon_taotao_29" Tag="[淘淘吐舌頭]" />
|
||||
<Emoticon File="taotao_30.png" ID="emoticon_taotao_30" Tag="[淘淘微笑]" />
|
||||
<Emoticon File="taotao_31.png" ID="emoticon_taotao_31" Tag="[淘淘無辜]" />
|
||||
<Emoticon File="taotao_32.png" ID="emoticon_taotao_32" Tag="[淘淘捂嘴笑]" />
|
||||
<Emoticon File="taotao_33.png" ID="emoticon_taotao_33" Tag="[淘淘兇]" />
|
||||
<Emoticon File="taotao_34.png" ID="emoticon_taotao_34" Tag="[淘淘羞笑]" />
|
||||
<Emoticon File="taotao_35.png" ID="emoticon_taotao_35" Tag="[淘淘眩暈]" />
|
||||
<Emoticon File="taotao_36.png" ID="emoticon_taotao_36" Tag="[淘淘疑問]" />
|
||||
<Emoticon File="taotao_37.png" ID="emoticon_taotao_37" Tag="[淘淘再見]" />
|
||||
<Emoticon File="taotao_38.png" ID="emoticon_taotao_38" Tag="[淘淘中毒]" />
|
||||
<Emoticon File="taotao_39.png" ID="emoticon_taotao_39" Tag="[淘淘齜牙]" />
|
||||
|
||||
</Catalog>
|
||||
<Catalog Title="lele">
|
||||
|
||||
<Emoticon File="lele_00.png" ID="emoticon_lele_00" Tag="[樂樂安靜]" />
|
||||
<Emoticon File="lele_01.png" ID="emoticon_lele_01" Tag="[樂樂白眼]" />
|
||||
<Emoticon File="lele_02.png" ID="emoticon_lele_02" Tag="[樂樂生氣]" />
|
||||
<Emoticon File="lele_03.png" ID="emoticon_lele_37" Tag="[樂樂再見]" />
|
||||
<Emoticon File="lele_04.png" ID="emoticon_lele_03" Tag="[樂樂閉嘴]" />
|
||||
<Emoticon File="lele_05.png" ID="emoticon_lele_04" Tag="[樂樂犯困]" />
|
||||
<Emoticon File="lele_06.png" ID="emoticon_lele_05" Tag="[樂樂尷尬]" />
|
||||
<Emoticon File="lele_07.png" ID="emoticon_lele_06" Tag="[樂樂感動]" />
|
||||
<Emoticon File="lele_08.png" ID="emoticon_lele_07" Tag="[樂樂鼓掌]" />
|
||||
<Emoticon File="lele_09.png" ID="emoticon_lele_08" Tag="[樂樂害羞]" />
|
||||
<Emoticon File="lele_10.png" ID="emoticon_lele_09" Tag="[樂樂好色]" />
|
||||
<Emoticon File="lele_11.png" ID="emoticon_lele_10" Tag="[樂樂黑臉]" />
|
||||
<Emoticon File="lele_12.png" ID="emoticon_lele_11" Tag="[樂樂急怒]" />
|
||||
<Emoticon File="lele_13.png" ID="emoticon_lele_12" Tag="[樂樂驚慌]" />
|
||||
<Emoticon File="lele_14.png" ID="emoticon_lele_13" Tag="[樂樂驚訝]" />
|
||||
<Emoticon File="lele_15.png" ID="emoticon_lele_14" Tag="[樂樂沮喪]" />
|
||||
<Emoticon File="lele_16.png" ID="emoticon_lele_15" Tag="[樂樂開心]" />
|
||||
<Emoticon File="lele_17.png" ID="emoticon_lele_16" Tag="[樂樂瞌睡]" />
|
||||
<Emoticon File="lele_18.png" ID="emoticon_lele_17" Tag="[樂樂摳鼻]" />
|
||||
<Emoticon File="lele_19.png" ID="emoticon_lele_18" Tag="[樂樂哭泣]" />
|
||||
<Emoticon File="lele_20.png" ID="emoticon_lele_19" Tag="[樂樂苦臉]" />
|
||||
<Emoticon File="lele_21.png" ID="emoticon_lele_20" Tag="[樂樂酷]" />
|
||||
<Emoticon File="lele_22.png" ID="emoticon_lele_21" Tag="[樂樂 酷]" />
|
||||
<Emoticon File="lele_23.png" ID="emoticon_lele_22" Tag="[樂樂狂躁]" />
|
||||
<Emoticon File="lele_24.png" ID="emoticon_lele_23" Tag="[樂樂流汗]" />
|
||||
<Emoticon File="lele_25.png" ID="emoticon_lele_24" Tag="[樂樂罵人]" />
|
||||
<Emoticon File="lele_26.png" ID="emoticon_lele_25" Tag="[樂樂發怒]" />
|
||||
<Emoticon File="lele_27.png" ID="emoticon_lele_26" Tag="[樂樂氣哭]" />
|
||||
<Emoticon File="lele_28.png" ID="emoticon_lele_27" Tag="[樂樂敲頭]" />
|
||||
<Emoticon File="lele_29.png" ID="emoticon_lele_28" Tag="[樂樂親親]" />
|
||||
<Emoticon File="lele_30.png" ID="emoticon_lele_29" Tag="[樂樂吐舌頭]" />
|
||||
<Emoticon File="lele_31.png" ID="emoticon_lele_30" Tag="[樂樂微笑]" />
|
||||
<Emoticon File="lele_32.png" ID="emoticon_lele_31" Tag="[樂樂無辜]" />
|
||||
<Emoticon File="lele_33.png" ID="emoticon_lele_32" Tag="[樂樂捂嘴笑]" />
|
||||
<Emoticon File="lele_34.png" ID="emoticon_lele_33" Tag="[樂樂兇]" />
|
||||
<Emoticon File="lele_35.png" ID="emoticon_lele_34" Tag="[樂樂羞笑]" />
|
||||
<Emoticon File="lele_36.png" ID="emoticon_lele_35" Tag="[樂樂眩暈]" />
|
||||
<Emoticon File="lele_37.png" ID="emoticon_lele_36" Tag="[樂樂疑問]" />
|
||||
<Emoticon File="lele_38.png" ID="emoticon_lele_38" Tag="[樂樂中毒]" />
|
||||
<Emoticon File="lele_39.png" ID="emoticon_lele_39" Tag="[樂樂齜牙]" />
|
||||
|
||||
</Catalog>
|
||||
|
||||
<Catalog Title="tlt">
|
||||
<Emoticon File="tlt_gif_00.png" ID="emoticon_tlt_gif_00" Tag="[好喜歡你哦]" />
|
||||
<Emoticon File="tlt_gif_01.png" ID="emoticon_tlt_gif_01" Tag="[加油鴨]" />
|
||||
<Emoticon File="tlt_gif_02.png" ID="emoticon_tlt_gif_02" Tag="[老大駕到]" />
|
||||
<Emoticon File="tlt_gif_03.png" ID="emoticon_tlt_gif_03" Tag="[老妹你真美]" />
|
||||
<Emoticon File="tlt_gif_04.png" ID="emoticon_tlt_gif_04" Tag="[靈魂抓手]" />
|
||||
<Emoticon File="tlt_gif_05.png" ID="emoticon_tlt_gif_05" Tag="[菩薩保佑]" />
|
||||
<Emoticon File="tlt_gif_06.png" ID="emoticon_tlt_gif_06" Tag="[氣屎我了]" />
|
||||
<Emoticon File="tlt_gif_07.png" ID="emoticon_tlt_gif_07" Tag="[什麼情況]" />
|
||||
<Emoticon File="tlt_gif_08.png" ID="emoticon_tlt_gif_08" Tag="[送你好運]" />
|
||||
<Emoticon File="tlt_gif_09.png" ID="emoticon_tlt_gif_09" Tag="[太感動了]" />
|
||||
<Emoticon File="tlt_gif_10.png" ID="emoticon_tlt_gif_10" Tag="[為愛而戰]" />
|
||||
<Emoticon File="tlt_gif_11.png" ID="emoticon_tlt_gif_11" Tag="[要得手了]" />
|
||||
<Emoticon File="tlt_gif_12.png" ID="emoticon_tlt_gif_12" Tag="[勇冠三軍]" />
|
||||
<Emoticon File="tlt_gif_13.png" ID="emoticon_tlt_gif_13" Tag="[有驚喜哦]" />
|
||||
<Emoticon File="tlt_gif_14.png" ID="emoticon_tlt_gif_14" Tag="[抓不著就搗蛋]" />
|
||||
<Emoticon File="tlt_gif_15.png" ID="emoticon_tlt_gif_15" Tag="[聊天結束]" />
|
||||
<Emoticon File="tlt_gif_16.png" ID="emoticon_tlt_gif_16" Tag="[蒼天啊]" />
|
||||
<Emoticon File="tlt_gif_17.png" ID="emoticon_tlt_gif_17" Tag="[暈死]" />
|
||||
<Emoticon File="tlt_gif_18.png" ID="emoticon_tlt_gif_18" Tag="[幹就完了]" />
|
||||
<Emoticon File="tlt_gif_19.png" ID="emoticon_tlt_gif_19" Tag="[發財了]" />
|
||||
<Emoticon File="tlt_gif_20.png" ID="emoticon_tlt_gif_20" Tag="[對不起]" />
|
||||
<Emoticon File="tlt_gif_21.png" ID="emoticon_tlt_gif_21" Tag="[關我屁事]" />
|
||||
<Emoticon File="tlt_gif_22.png" ID="emoticon_tlt_gif_22" Tag="[嚇死我了]" />
|
||||
<Emoticon File="tlt_gif_23.png" ID="emoticon_tlt_gif_23" Tag="[送S去咯]" />
|
||||
<Emoticon File="tlt_gif_24.png" ID="emoticon_tlt_gif_24" Tag="[洗洗睡吧]" />
|
||||
<Emoticon File="tlt_gif_25.png" ID="emoticon_tlt_gif_25" Tag="[我要滅了你]" />
|
||||
<Emoticon File="tlt_gif_26.png" ID="emoticon_tlt_gif_26" Tag="[電不倒你]" />
|
||||
<Emoticon File="tlt_gif_27.png" ID="emoticon_tlt_gif_27" Tag="[大過年的]" />
|
||||
<Emoticon File="tlt_gif_28.png" ID="emoticon_tlt_gif_28" Tag="[有人放屁]" />
|
||||
<Emoticon File="tlt_gif_29.png" ID="emoticon_tlt_gif_29" Tag="[好樣的]" />
|
||||
<Emoticon File="tlt_gif_30.png" ID="emoticon_tlt_gif_30" Tag="[哇噢]" />
|
||||
<Emoticon File="tlt_gif_31.png" ID="emoticon_tlt_gif_31" Tag="[同志們好]" />
|
||||
<Emoticon File="tlt_gif_32.png" ID="emoticon_tlt_gif_32" Tag="[沒問題]" />
|
||||
<Emoticon File="tlt_gif_33.png" ID="emoticon_tlt_gif_33" Tag="[怎麼辦]" />
|
||||
<Emoticon File="tlt_gif_34.png" ID="emoticon_tlt_gif_34" Tag="[偷瞄一下]" />
|
||||
<Emoticon File="tlt_gif_35.png" ID="emoticon_tlt_gif_35" Tag="[今天舔誰呢]" />
|
||||
</Catalog>
|
||||
</PopoEmoticons>
|
||||
|
||||
|
||||