├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── gradle.properties ├── keystore.jks ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── pro │ │ └── glideim │ │ ├── App.kt │ │ ├── IMDataStorage.kt │ │ ├── MessageListener.kt │ │ ├── MessageNotifyActionReceiver.kt │ │ ├── UserConfig.kt │ │ ├── base │ │ ├── BaseActivity.kt │ │ └── BaseFragment.kt │ │ ├── db │ │ ├── GlideIMDatabase.kt │ │ ├── Message.kt │ │ ├── MessageDao.kt │ │ ├── Session.kt │ │ ├── SessionDao.kt │ │ ├── UserInfo.kt │ │ └── UserInfoDao.kt │ │ ├── ui │ │ ├── Events.kt │ │ ├── LoginActivity.kt │ │ ├── MainActivity.kt │ │ ├── ProgressDialog.kt │ │ ├── RegisterActivity.kt │ │ ├── SortedList.java │ │ ├── SortedListAdapterCallback.java │ │ ├── SplashActivity.kt │ │ ├── chat │ │ │ ├── ChatActivity.kt │ │ │ ├── MessageListSorter.kt │ │ │ ├── MySortedList.kt │ │ │ └── viewholder │ │ │ │ ├── ChatImageMessageViewData.kt │ │ │ │ ├── ChatImageMessageViewHolder.kt │ │ │ │ ├── ChatMessageViewData.kt │ │ │ │ ├── ChatMessageViewHolder.kt │ │ │ │ ├── ChatVoiceMessageViewData.kt │ │ │ │ ├── ChatVoteMessageViewData.kt │ │ │ │ ├── GroupNotifyViewHolder.kt │ │ │ │ └── NotifyViewData.kt │ │ ├── contacts │ │ │ ├── AddContactsActivity.kt │ │ │ ├── ContactsFragment.kt │ │ │ └── SelectContactsActivity.kt │ │ ├── dev │ │ │ └── DevOptionsActivity.kt │ │ ├── group │ │ │ ├── GroupDetailActivity.kt │ │ │ └── GroupMemberViewData.kt │ │ ├── profile │ │ │ └── ProfileFragment.kt │ │ └── session │ │ │ ├── SessionListSorter.kt │ │ │ ├── SessionViewData.kt │ │ │ ├── SessionViewHolder.kt │ │ │ └── SessionsFragment.kt │ │ ├── utils │ │ ├── GlideExtension.kt │ │ ├── GroupAvatarUtils.kt │ │ ├── ImageUploader.kt │ │ ├── ItemDecorationFactory.kt │ │ ├── LetterTouchView.kt │ │ ├── LifecycleExtensions.kt │ │ ├── MyBusUtils.java │ │ ├── RxRequestExtensions.kt │ │ ├── SwipeRefreshExtension.kt │ │ ├── ThreadUtils.java │ │ ├── TimeSpanExtensions.kt │ │ └── UpdateUtils.kt │ │ ├── viewholder │ │ └── EmptyViewHolder.kt │ │ └── widget │ │ └── FlowLayout.kt │ └── res │ ├── drawable │ ├── ic_account.xml │ ├── ic_add.xml │ ├── ic_add_outline.xml │ ├── ic_camera.xml │ ├── ic_check.xml │ ├── ic_check_circle.xml │ ├── ic_contacts.xml │ ├── ic_contacts_add.xml │ ├── ic_delete_cache.xml │ ├── ic_dev_mode.xml │ ├── ic_emoji.xml │ ├── ic_face.xml │ ├── ic_file.xml │ ├── ic_keyboard.xml │ ├── ic_launcher_background.xml │ ├── ic_location.xml │ ├── ic_logout.xml │ ├── ic_message.xml │ ├── ic_more_menu.xml │ ├── ic_notify.xml │ ├── ic_photos.xml │ ├── ic_send.xml │ ├── ic_settings.xml │ ├── ic_update.xml │ ├── ic_voice.xml │ ├── ic_vote.xml │ ├── ripple_option.xml │ ├── shape_badge_circle.xml │ └── shape_option_menu.xml │ ├── layout │ ├── activity_add_contacts.xml │ ├── activity_chat.xml │ ├── activity_dev_options.xml │ ├── activity_group_detail.xml │ ├── activity_login.xml │ ├── activity_main.xml │ ├── activity_register.xml │ ├── activity_select_contacts.xml │ ├── activity_splash.xml │ ├── fragment_contacts.xml │ ├── fragment_profile.xml │ ├── fragment_session.xml │ ├── item_chat_group_notify.xml │ ├── item_chat_image_message.xml │ ├── item_chat_message.xml │ ├── item_chat_title.xml │ ├── item_contacts.xml │ ├── item_empty.xml │ ├── item_group_member.xml │ ├── item_select_contacts.xml │ ├── item_session.xml │ ├── layout_multi_message.xml │ └── pop_message.xml │ ├── menu │ ├── menu_chat_group.xml │ ├── menu_chat_user.xml │ ├── menu_contacts_add.xml │ └── menu_home_nav.xml │ ├── mipmap │ └── ic_launcher.png │ ├── values │ ├── colors.xml │ ├── id.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ └── network_security_config.xml ├── build.gradle ├── buildSrc ├── build.gradle └── src │ └── main │ └── groovy │ └── Config.groovy ├── ci.gradle ├── glide-im-sdk ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── pro │ │ └── glideim │ │ └── sdk │ │ ├── AccountStateListener.java │ │ ├── Constants.java │ │ ├── ContactChangeListener.java │ │ ├── DataStorage.java │ │ ├── DefaultDataStoreImpl.java │ │ ├── GlideException.java │ │ ├── GlideIM.java │ │ ├── IMAccount.java │ │ ├── IMContact.java │ │ ├── IMContactList.java │ │ ├── IMGroupContact.java │ │ ├── IMGroupNotifyMessage.java │ │ ├── IMMessage.java │ │ ├── IMMessageListener.java │ │ ├── IMSession.java │ │ ├── IMSessionList.java │ │ ├── Logger.java │ │ ├── MessageChangeListener.java │ │ ├── Pair.java │ │ ├── ParameterizedTypeImpl.java │ │ ├── SessionUpdateListener.java │ │ ├── SilentObserver.java │ │ ├── api │ │ ├── Response.java │ │ ├── app │ │ │ ├── AppApi.java │ │ │ └── ReleaseInfoBean.java │ │ ├── auth │ │ │ ├── AuthApi.java │ │ │ ├── AuthBean.java │ │ │ ├── AuthDto.java │ │ │ ├── LoginDto.java │ │ │ └── RegisterDto.java │ │ ├── group │ │ │ ├── AddGroupMemberDto.java │ │ │ ├── CreateGroupBean.java │ │ │ ├── CreateGroupDto.java │ │ │ ├── GetGroupInfoDto.java │ │ │ ├── GetGroupMemberDto.java │ │ │ ├── GroupApi.java │ │ │ ├── GroupInfoBean.java │ │ │ ├── GroupMemberBean.java │ │ │ ├── JoinGroupDto.java │ │ │ └── RemoveMemberDto.java │ │ ├── msg │ │ │ ├── AckOfflineMsgDto.java │ │ │ ├── GetChatHistoryDto.java │ │ │ ├── GetGroupMessageStateDto.java │ │ │ ├── GetGroupMsgHistoryDto.java │ │ │ ├── GetSessionDto.java │ │ │ ├── GetUserMsgDto.java │ │ │ ├── GroupMessageBean.java │ │ │ ├── GroupMessageStateBean.java │ │ │ ├── MessageBean.java │ │ │ ├── MessageIDBean.java │ │ │ ├── MsgApi.java │ │ │ ├── SessionBean.java │ │ │ └── UserMsgBean.java │ │ └── user │ │ │ ├── ApprovalContactsDto.java │ │ │ ├── ContactsBean.java │ │ │ ├── ContactsUidDto.java │ │ │ ├── GetUserInfoDto.java │ │ │ ├── ProfileBean.java │ │ │ ├── RegisterDto.java │ │ │ ├── TokenBean.java │ │ │ ├── UserApi.java │ │ │ └── UserInfoBean.java │ │ ├── http │ │ ├── AuthInterceptor.java │ │ └── RetrofitManager.java │ │ ├── im │ │ ├── ConnStateListener.java │ │ ├── Heartbeat.java │ │ ├── IMClient.java │ │ ├── IMClientImpl.java │ │ ├── KeepAlive.java │ │ ├── Message.java │ │ └── MessageListener.java │ │ ├── messages │ │ ├── AckMessage.java │ │ ├── AckRequest.java │ │ ├── Actions.java │ │ ├── ChatMessage.java │ │ ├── CommMessage.java │ │ ├── GroupMessage.java │ │ ├── GroupNotify.java │ │ ├── GroupNotifyMemberChanges.java │ │ ├── GroupNotifyMemberRemoved.java │ │ └── RecallMessage.java │ │ ├── push │ │ └── NewContactsMessage.java │ │ ├── utils │ │ ├── RxUtils.java │ │ └── SLogger.java │ │ └── ws │ │ ├── HeartbeatHandler.java │ │ ├── MessageListener.java │ │ ├── NettyWsClient.java │ │ ├── RetrofitWsClient.java │ │ ├── WsClient.java │ │ └── WsInboundChHandler.java │ └── test │ └── java │ └── pro │ └── glideim │ └── sdk │ ├── GlideIMTest.java │ ├── IMClientTest.java │ ├── MockUserTest.java │ ├── TestObserver.java │ ├── TestResObserver.java │ ├── api │ ├── app │ │ └── AppApiTest.java │ ├── auth │ │ └── AuthApiTest.java │ ├── msg │ │ └── MsgApiTest.java │ └── user │ │ └── UserApiTest.java │ ├── entity │ └── IMSessionListTest.java │ ├── im │ └── RetrofitWsClientTest.java │ └── ws │ └── NettyTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── 3.png ├── a.jpg └── b.jpg └── settings.gradle /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Publish & Deploy 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | 8 | jobs: 9 | build-and-deploy: 10 | name: GoIM 11 | runs-on: ubuntu-latest 12 | steps: 13 | 14 | - name: Checkout 15 | uses: actions/checkout@master 16 | 17 | - name: Get Tag 18 | id: get_tag 19 | run: | 20 | echo ::set-output name=TAG::${GITHUB_REF/refs\/tags\//} 21 | 22 | - name: Set Up JDK 11 23 | uses: actions/setup-java@v2 24 | with: 25 | java-version: '11' 26 | distribution: 'temurin' 27 | cache: gradle 28 | 29 | - name: Build With Gradle 30 | run: | 31 | chmod +x gradlew 32 | ./gradlew buildCiRelease -PVERSION_NAME=${{ steps.get_tag.outputs.TAG }} -PVERSION_CODE=${{ steps.get_tag.outputs.TAG }} -PAPK_NAME=glide_im_release_${{ steps.get_tag.outputs.TAG }}.apk 33 | 34 | - name: Create Release 35 | id: create_release 36 | uses: actions/create-release@master 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GitAction }} 39 | with: 40 | tag_name: ${{ github.ref }} 41 | release_name: GlideIM_release_${{ steps.get_tag.outputs.TAG }} 42 | draft: false 43 | prerelease: false 44 | 45 | - name: Upload Release Asset 46 | id: upload-release-asset 47 | uses: actions/upload-release-asset@master 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GitAction }} 50 | with: 51 | tag_name: ${{ github.ref }} 52 | upload_url: ${{ steps.create_release.outputs.upload_url }} 53 | asset_path: glide_im_release_${{ steps.get_tag.outputs.TAG }}.apk 54 | asset_name: glide_im_release_${{ steps.get_tag.outputs.TAG }}.apk 55 | asset_content_type: application/gzip 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /.idea 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | local.properties 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Glide IM 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GlideIM Android 客户端 2 | 3 | Android UI 部分使用 kotlin 实现, IM 封装成了一个 SDK, 使用 Java 实现. 4 | 5 | ## 基本功能 6 | 7 | - 注册登录 8 | - 好友添加 9 | - 群添加 创建群 10 | - 会话列表 11 | - 联系人列表 12 | - 自动重连 13 | - 消息收发 14 | 15 | ## 下载 16 | 17 | [Download](https://github.com/Glide-IM/Glide-IM-Android/releases) 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id 'com.blankj.bus' 5 | id "org.jetbrains.kotlin.kapt" 6 | } 7 | 8 | bus { 9 | busUtilsClass "pro.glideim.utils.MyBusUtils" 10 | } 11 | 12 | android { 13 | compileSdk 31 14 | 15 | defaultConfig { 16 | applicationId "pro.glideim" 17 | minSdk 26 18 | targetSdk 30 19 | versionCode Config.version 20 | versionName Config.versionName 21 | 22 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 23 | } 24 | 25 | signingConfigs { 26 | release { 27 | keyAlias 'key0' 28 | keyPassword 'password' 29 | storeFile file('keystore.jks') 30 | storePassword 'password' 31 | } 32 | } 33 | 34 | buildTypes { 35 | debug { 36 | signingConfig signingConfigs.release 37 | 38 | buildConfigField "String", "BASE_URL", DEV_API_BASE_URL 39 | } 40 | 41 | release { 42 | minifyEnabled false 43 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 44 | signingConfig signingConfigs.release 45 | 46 | buildConfigField "String", "BASE_URL", RELEASE_API_BASE_URL 47 | } 48 | } 49 | compileOptions { 50 | sourceCompatibility JavaVersion.VERSION_1_8 51 | targetCompatibility JavaVersion.VERSION_1_8 52 | } 53 | kotlinOptions { 54 | jvmTarget = '1.8' 55 | } 56 | packagingOptions { 57 | exclude 'META-INF/INDEX.LIST' 58 | exclude 'META-INF/io.netty.versions.properties' 59 | } 60 | } 61 | 62 | dependencies { 63 | 64 | implementation project(":glide-im-sdk") 65 | 66 | implementation 'androidx.core:core-ktx:1.7.0' 67 | implementation 'androidx.appcompat:appcompat:1.4.1' 68 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 69 | implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" 70 | implementation "androidx.viewpager2:viewpager2:1.0.0" 71 | 72 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8' 73 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2' 74 | 75 | implementation 'com.google.android.material:material:1.6.0-alpha02' 76 | 77 | kapt "androidx.room:room-compiler:2.4.1" 78 | annotationProcessor "androidx.room:room-compiler:2.4.1" 79 | implementation "androidx.room:room-runtime:2.4.1" 80 | implementation "androidx.room:room-ktx:2.4.1" 81 | implementation "androidx.room:room-rxjava2:2.4.1" 82 | 83 | implementation 'com.github.bumptech.glide:glide:4.12.0' 84 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' 85 | 86 | implementation "com.vanniktech:emoji-google:0.8.0" 87 | implementation "com.vanniktech:emoji-material:0.8.0" 88 | implementation 'com.blankj:utilcodex:1.31.0' 89 | implementation 'com.dengzii:androidktx:1.2.1' 90 | implementation 'com.dengzii:adapter:1.4.2' 91 | } -------------------------------------------------------------------------------- /app/gradle.properties: -------------------------------------------------------------------------------- 1 | DEV_API_BASE_URL=\"http://api.glide-im.pro/api/\" 2 | 3 | RELEASE_API_BASE_URL=\"http://api.t.glide-im.pro/api/\" -------------------------------------------------------------------------------- /app/keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glide-im/Glide-IM-Android/19a8f741ceab19dfe12c0cd1c115adce26d8cf4f/app/keystore.jks -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/App.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim 2 | 3 | import android.app.Application 4 | import com.dengzii.adapter.SuperAdapter 5 | import com.vanniktech.emoji.EmojiManager 6 | import com.vanniktech.emoji.google.GoogleEmojiProvider 7 | import pro.glideim.sdk.GlideIM 8 | 9 | class App : Application() { 10 | 11 | companion object { 12 | private const val TAG = "App" 13 | } 14 | 15 | override fun onCreate() { 16 | super.onCreate() 17 | 18 | EmojiManager.install(GoogleEmojiProvider()) 19 | IMDataStorage.init(this) 20 | MessageListener.init(this) 21 | 22 | // SLogger.setLogger(object : Logger { 23 | // override fun d(tag: String, log: String) { 24 | // Log.d(tag, log) 25 | // } 26 | // 27 | // override fun e(tag: String, t: Throwable) { 28 | // Log.e(tag, "e: ", t) 29 | // } 30 | // }) 31 | 32 | val userConfig = UserConfig(this) 33 | GlideIM.init(userConfig.baseUrl) 34 | if (userConfig.enableCache) { 35 | GlideIM.getInstance().dataStorage = IMDataStorage.getInstance() 36 | } 37 | GlideIM.getInstance().setDevice(1) 38 | 39 | SuperAdapter.addDefaultViewHolderForType( 40 | SuperAdapter.Empty::class.java, 41 | pro.glideim.viewholder.EmptyViewHolder::class.java 42 | ) 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/MessageNotifyActionReceiver.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.Intent 6 | 7 | class MessageNotifyActionReceiver : BroadcastReceiver() { 8 | override fun onReceive(context: Context?, intent: Intent?) { 9 | intent ?: return 10 | context ?: return 11 | val to = intent.getLongExtra("session", 0) 12 | val type = intent.getIntExtra("type", 0) 13 | // GlideIM.getAccount().imSessionList.getSession(type, to).clearUnread() 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/UserConfig.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim 2 | 3 | import android.content.Context 4 | import com.dengzii.ktx.android.content.Preferences 5 | import com.dengzii.ktx.android.content.preference 6 | 7 | class UserConfig(context: Context) : Preferences(context, "user_config") { 8 | var password by preference("") 9 | var account by preference("") 10 | var lastUpdateCheck by preference("0") 11 | var newestVersion by preference(0) 12 | var baseUrl by preference(BuildConfig.BASE_URL) 13 | var enableCache by preference(false) 14 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/base/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.base 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import android.widget.Toast 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.blankj.utilcode.util.ActivityUtils 8 | import pro.glideim.sdk.GlideIM 9 | import pro.glideim.sdk.IMAccount 10 | import pro.glideim.sdk.im.ConnStateListener 11 | import pro.glideim.sdk.ws.WsClient 12 | import pro.glideim.ui.LoginActivity 13 | import pro.glideim.utils.RequestStateCallback 14 | 15 | abstract class BaseActivity : AppCompatActivity(), RequestStateCallback, ConnStateListener { 16 | 17 | private val TAG = BaseActivity::class.java.simpleName 18 | 19 | abstract val layoutResId: Int 20 | 21 | private var inited = false 22 | 23 | protected var needAuth = true 24 | 25 | open val account: IMAccount? get() = GlideIM.getAccount() 26 | 27 | override fun onCreate(savedInstanceState: Bundle?) { 28 | super.onCreate(savedInstanceState) 29 | setContentView(layoutResId) 30 | } 31 | 32 | override fun onStart() { 33 | super.onStart() 34 | if (!inited) { 35 | initView() 36 | inited = true 37 | } 38 | account?.imClient?.apply { 39 | onStateChange(webSocketClient.state, "") 40 | } 41 | account?.imClient?.addConnStateListener(this) 42 | } 43 | 44 | override fun onResume() { 45 | super.onResume() 46 | if (needAuth && (account == null || account?.uid == 0L)) { 47 | LoginActivity.start(this) 48 | finish() 49 | } 50 | } 51 | 52 | abstract fun initView() 53 | 54 | fun toast(msg: String) { 55 | Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() 56 | } 57 | 58 | override fun onRequestStart() { 59 | 60 | } 61 | 62 | override fun onRequestFinish() { 63 | 64 | } 65 | 66 | override fun onRequestError(t: Throwable) { 67 | toast(t.message ?: "error") 68 | } 69 | 70 | override fun onStop() { 71 | super.onStop() 72 | account?.imClient?.removeConnStateListener(this) 73 | } 74 | 75 | open fun updateConnState(state: String) { 76 | 77 | } 78 | 79 | override fun onStateChange(state: Int, msg: String?) { 80 | Log.d(TAG, "onStateChange: $state") 81 | val s = when (state) { 82 | WsClient.STATE_CLOSED -> { 83 | "disconnected" 84 | } 85 | WsClient.STATE_CONNECTING -> "connecting" 86 | WsClient.STATE_OPENED -> "" 87 | else -> "" 88 | } 89 | runOnUiThread { updateConnState(s) } 90 | } 91 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.base 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.Toast 8 | import androidx.annotation.IdRes 9 | import androidx.fragment.app.Fragment 10 | import pro.glideim.sdk.GlideIM 11 | import pro.glideim.sdk.IMAccount 12 | import pro.glideim.sdk.im.ConnStateListener 13 | import pro.glideim.sdk.ws.WsClient 14 | import pro.glideim.utils.RequestStateCallback 15 | 16 | abstract class BaseFragment : Fragment(), RequestStateCallback, ConnStateListener { 17 | 18 | private lateinit var mView: View 19 | 20 | abstract val layoutRes: Int 21 | 22 | abstract fun initView() 23 | 24 | private var inited = false 25 | 26 | protected val account: IMAccount? = GlideIM.getAccount() 27 | 28 | override fun onCreateView( 29 | inflater: LayoutInflater, 30 | container: ViewGroup?, 31 | savedInstanceState: Bundle? 32 | ): View? { 33 | mView = inflater.inflate(layoutRes, null) 34 | return mView 35 | } 36 | 37 | override fun onStart() { 38 | super.onStart() 39 | if (!inited) { 40 | initView() 41 | inited = true 42 | } 43 | } 44 | 45 | 46 | fun findViewById(@IdRes id: Int): T { 47 | return mView.findViewById(id) 48 | } 49 | 50 | fun toast(msg: String) { 51 | Toast.makeText(requireActivity(), msg, Toast.LENGTH_SHORT).show() 52 | } 53 | 54 | override fun onRequestStart() { 55 | 56 | } 57 | 58 | override fun onRequestFinish() { 59 | 60 | } 61 | 62 | override fun onRequestError(t: Throwable) { 63 | t.printStackTrace() 64 | toast(t.message ?: "error") 65 | } 66 | 67 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 68 | super.onViewCreated(view, savedInstanceState) 69 | 70 | account?.imClient?.apply { 71 | onStateChange(webSocketClient.state, "") 72 | addConnStateListener(this@BaseFragment) 73 | } 74 | } 75 | 76 | override fun onDestroyView() { 77 | super.onDestroyView() 78 | account?.imClient?.apply { 79 | removeConnStateListener(this@BaseFragment) 80 | } 81 | } 82 | 83 | open fun updateConnState(state: String) { 84 | 85 | } 86 | 87 | override fun onStateChange(state: Int, msg: String?) { 88 | val s = when (state) { 89 | WsClient.STATE_CLOSED -> { 90 | "disconnected" 91 | } 92 | WsClient.STATE_CONNECTING -> "connecting" 93 | WsClient.STATE_OPENED -> "" 94 | else -> "" 95 | } 96 | activity?.runOnUiThread { 97 | updateConnState(s) 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/db/GlideIMDatabase.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.db 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | 8 | @Database(entities = [Session::class, Message::class, UserInfo::class], version = 2, exportSchema = false) 9 | abstract class GlideIMDatabase : RoomDatabase() { 10 | 11 | abstract fun sessionDao(): SessionDao 12 | abstract fun messageDao(): MessageDao 13 | abstract fun userInfoDao(): UserInfoDao 14 | 15 | companion object { 16 | fun getDb(context: Context): GlideIMDatabase { 17 | return Room.databaseBuilder(context, GlideIMDatabase::class.java, "glide-im-db") 18 | .build() 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/db/Message.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.db 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | import pro.glideim.sdk.IMAccount 6 | import pro.glideim.sdk.IMMessage 7 | 8 | @Entity 9 | data class Message( 10 | val uid: Long = 0, 11 | @PrimaryKey 12 | val mid: Long = 0, 13 | val cliSeq: Long = 0, 14 | val from: Long = 0, 15 | val to: Long = 0, 16 | val type: Int = 0, 17 | val sendAt: Long = 0, 18 | val createAt: Long = 0, 19 | val content: String = "", 20 | val targetId: Long = 0, 21 | val targetType: Int = 0, 22 | val state: Int = 0, 23 | val status: Int = 0, 24 | val recallBy:Long = 0, 25 | val seq: Long = 0 26 | ) { 27 | companion object { 28 | fun fromIMMessage(uid: Long, m: IMMessage): Message { 29 | return Message( 30 | uid = uid, 31 | mid = m.mid, 32 | cliSeq = m.cliSeq, 33 | from = m.from, 34 | to = m.to, 35 | type = m.type, 36 | sendAt = m.sendAt, 37 | createAt = m.createAt, 38 | content = m.content, 39 | targetId = m.targetId, 40 | targetType = m.targetType, 41 | state = m.state, 42 | status = m.status, 43 | recallBy = m.recallBy, 44 | seq = m.seq, 45 | ) 46 | } 47 | } 48 | 49 | fun toIMMessage(account: IMAccount): IMMessage { 50 | return IMMessage(account).apply { 51 | mid = this@Message.mid 52 | cliSeq = this@Message.cliSeq 53 | from = this@Message.from 54 | to = this@Message.to 55 | type = this@Message.type 56 | sendAt = this@Message.sendAt 57 | createAt = this@Message.createAt 58 | content = this@Message.content 59 | targetId = this@Message.targetId 60 | targetType = this@Message.targetType 61 | state = this@Message.state 62 | status = this@Message.status 63 | seq = this@Message.seq 64 | recallBy = this@Message.recallBy 65 | } 66 | 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/db/MessageDao.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.db 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Insert 5 | import androidx.room.Query 6 | import androidx.room.Update 7 | 8 | @Dao 9 | interface MessageDao { 10 | 11 | @Insert 12 | fun add(vararg message: Message) 13 | 14 | @Update 15 | suspend fun update(vararg s: Message) 16 | 17 | @Query("SELECT * FROM message WHERE mid=:id LIMIT 1") 18 | suspend fun exist(id: Long): List 19 | 20 | @Query("SELECT * FROM Message WHERE uid=:uid AND targetId=:target AND targetType=:targetType") 21 | fun get(uid: Long, targetType: Int, target: Long): List 22 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/db/Session.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.db 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | import pro.glideim.sdk.IMAccount 6 | import pro.glideim.sdk.IMSession 7 | 8 | @Entity 9 | data class Session( 10 | @PrimaryKey 11 | val id: String = "", 12 | val uid: Long = 0, 13 | val to: Long = 0, 14 | val lastMsgSender: Long = 0, 15 | val title: String, 16 | val avatar: String? = null, 17 | val unread: Int = 0, 18 | val updateAt: Long = 0, 19 | val previousUpdateAt: Long = 0, 20 | val type: Int = 0, 21 | val lastMsg: String? = null, 22 | val lastMsgId: Long = 0, 23 | val createAt: Long = 0 24 | ) { 25 | companion object { 26 | fun fromIMSession(uid: Long, s: IMSession): Session { 27 | return Session( 28 | id = "$uid@${s.to}", 29 | uid = uid, 30 | to = s.to, 31 | lastMsgSender = s.lastMsgSender, 32 | title = s.title, 33 | avatar = s.avatar, 34 | unread = s.unread, 35 | updateAt = s.updateAt, 36 | previousUpdateAt = s.previousUpdateAt, 37 | type = s.type, 38 | lastMsg = s.lastMsg, 39 | lastMsgId = s.lastMsgId, 40 | createAt = s.createAt 41 | ) 42 | } 43 | } 44 | 45 | fun toImSession(account: IMAccount): IMSession { 46 | return IMSession(account, to, type).apply { 47 | to = this@Session.to 48 | lastMsgSender = this@Session.lastMsgSender 49 | title = this@Session.title 50 | avatar = this@Session.avatar 51 | unread = this@Session.unread 52 | updateAt = this@Session.updateAt 53 | previousUpdateAt = this@Session.previousUpdateAt 54 | type = this@Session.type 55 | lastMsg = this@Session.lastMsg 56 | lastMsgId = this@Session.lastMsgId 57 | createAt = this@Session.createAt 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/db/SessionDao.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.db 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Insert 5 | import androidx.room.Query 6 | import androidx.room.Update 7 | 8 | @Dao 9 | interface SessionDao { 10 | 11 | @Insert 12 | suspend fun add(vararg s: Session) 13 | 14 | @Update 15 | suspend fun update(vararg s: Session) 16 | 17 | @Query("SELECT * FROM session WHERE id=:id LIMIT 1") 18 | suspend fun exist(id: String): List 19 | 20 | @Query("SELECT * FROM session WHERE uid=:uid") 21 | fun get(uid: Long): List 22 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/db/UserInfo.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.db 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | import pro.glideim.sdk.api.user.UserInfoBean 6 | 7 | @Entity 8 | data class UserInfo( 9 | @PrimaryKey 10 | val uid: Long, 11 | val avatar: String, 12 | val nickname: String, 13 | val account: String, 14 | val updateAt: Long 15 | ) { 16 | companion object { 17 | fun fromUserInfoBean(u: UserInfoBean): UserInfo { 18 | return UserInfo( 19 | u.uid, 20 | u.avatar, 21 | u.nickname, 22 | u.account, 23 | updateAt = System.currentTimeMillis() 24 | ) 25 | } 26 | } 27 | 28 | fun toUserInfoBean(): UserInfoBean { 29 | return UserInfoBean().apply { 30 | uid = this@UserInfo.uid 31 | avatar = this@UserInfo.avatar 32 | account = this@UserInfo.account 33 | nickname = this@UserInfo.nickname 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/db/UserInfoDao.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.db 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Insert 5 | import androidx.room.Query 6 | import androidx.room.Update 7 | 8 | @Dao 9 | interface UserInfoDao { 10 | 11 | @Insert 12 | suspend fun add(vararg s: UserInfo) 13 | 14 | @Update 15 | suspend fun update(vararg s: UserInfo) 16 | 17 | @Query("SELECT * FROM userinfo WHERE uid=:uid LIMIT 1") 18 | suspend fun exist(uid: Long): List 19 | 20 | @Query("SELECT * FROM userinfo WHERE uid=:uid") 21 | fun get(uid: Long): UserInfo? 22 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/Events.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui 2 | 3 | import pro.glideim.utils.MyBusUtils 4 | 5 | object Events { 6 | const val EVENT_UPDATE_ALL_CONTACTS = "EVENT_UPDATE_CONTACTS" 7 | 8 | fun updateContacts() { 9 | MyBusUtils.post(EVENT_UPDATE_ALL_CONTACTS) 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/ProgressDialog.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.DialogFragment 8 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 9 | import com.google.android.material.dialog.MaterialDialogs 10 | import pro.glideim.R 11 | 12 | class ProgressDialog:DialogFragment() { 13 | 14 | override fun onCreateView( 15 | inflater: LayoutInflater, 16 | container: ViewGroup?, 17 | savedInstanceState: Bundle? 18 | ): View? { 19 | 20 | return super.onCreateView(inflater, container, savedInstanceState) 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/RegisterActivity.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import com.dengzii.ktx.android.content.update 6 | import com.google.android.material.button.MaterialButton 7 | import com.google.android.material.textfield.TextInputEditText 8 | import pro.glideim.R 9 | import pro.glideim.UserConfig 10 | import pro.glideim.base.BaseActivity 11 | import pro.glideim.sdk.GlideIM 12 | import pro.glideim.utils.io2main 13 | import pro.glideim.utils.request2 14 | 15 | class RegisterActivity : BaseActivity() { 16 | 17 | private val mEtPasswordAgain by lazy { findViewById(R.id.et_password_again) } 18 | private val mBtSubmit by lazy { findViewById(R.id.bt_submit) } 19 | private val mEtPassword by lazy { findViewById(R.id.et_password) } 20 | private val mEtAccount by lazy { findViewById(R.id.et_account) } 21 | 22 | 23 | 24 | override val layoutResId = R.layout.activity_register 25 | 26 | companion object { 27 | @JvmStatic 28 | fun start(context: Context) { 29 | val starter = Intent(context, RegisterActivity::class.java) 30 | context.startActivity(starter) 31 | } 32 | } 33 | 34 | override fun initView() { 35 | needAuth = false 36 | mBtSubmit.setOnClickListener { 37 | submit() 38 | } 39 | } 40 | 41 | private fun submit() { 42 | if (!validate()) { 43 | return 44 | } 45 | val account = mEtAccount.text.toString() 46 | val password = mEtPassword.text.toString() 47 | 48 | GlideIM.register(account, password) 49 | .io2main() 50 | .request2(this) { 51 | toast("Register success!") 52 | UserConfig(this).update { 53 | this.account = account 54 | this.password = password 55 | } 56 | finish() 57 | } 58 | } 59 | 60 | private fun validate(): Boolean { 61 | 62 | val account = mEtAccount.text.toString() 63 | val password = mEtPassword.text.toString() 64 | val passwordAgain = mEtPasswordAgain.text.toString() 65 | 66 | if (account.isBlank() || account.length < 5) { 67 | toast("Please check your account, must contain more than 5 characters") 68 | return false 69 | } 70 | if (password.isBlank() || password.length < 6) { 71 | toast("Please check your password, must contain more than 6 characters") 72 | return false 73 | } 74 | if (password != passwordAgain) { 75 | toast("The password is inconsistent") 76 | return false 77 | } 78 | 79 | return true 80 | } 81 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/SortedListAdapterCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package pro.glideim.ui; 18 | 19 | import androidx.recyclerview.widget.RecyclerView; 20 | 21 | /** 22 | * A {@link androidx.recyclerview.widget.SortedList.Callback} implementation that can bind a {@link androidx.recyclerview.widget.SortedList} to a 23 | * {@link RecyclerView.Adapter}. 24 | */ 25 | public abstract class SortedListAdapterCallback extends SortedList.Callback { 26 | 27 | final RecyclerView.Adapter mAdapter; 28 | 29 | /** 30 | * Creates a {@link SortedList.Callback} that will forward data change events to the provided 31 | * Adapter. 32 | * 33 | * @param adapter The Adapter instance which should receive events from the SortedList. 34 | */ 35 | public SortedListAdapterCallback(RecyclerView.Adapter adapter) { 36 | mAdapter = adapter; 37 | } 38 | 39 | @Override 40 | public void onInserted(int position, int count) { 41 | mAdapter.notifyItemRangeInserted(position, count); 42 | } 43 | 44 | @Override 45 | public void onRemoved(int position, int count) { 46 | mAdapter.notifyItemRangeRemoved(position, count); 47 | } 48 | 49 | @Override 50 | public void onMoved(int fromPosition, int toPosition) { 51 | mAdapter.notifyItemMoved(fromPosition, toPosition); 52 | } 53 | 54 | @Override 55 | public void onChanged(int position, int count) { 56 | mAdapter.notifyItemRangeChanged(position, count); 57 | } 58 | 59 | @Override 60 | public void onChanged(int position, int count, Object payload) { 61 | mAdapter.notifyItemRangeChanged(position, count, payload); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/SplashActivity.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui 2 | 3 | import com.dengzii.ktx.android.content.update 4 | import com.google.android.material.textview.MaterialTextView 5 | import pro.glideim.BuildConfig 6 | import pro.glideim.MessageListener 7 | import pro.glideim.R 8 | import pro.glideim.UserConfig 9 | import pro.glideim.base.BaseActivity 10 | import pro.glideim.sdk.GlideIM 11 | import pro.glideim.sdk.api.app.AppApi 12 | import pro.glideim.sdk.utils.RxUtils 13 | import pro.glideim.utils.UpdateUtils 14 | import pro.glideim.utils.io2main 15 | import pro.glideim.utils.request 16 | import pro.glideim.utils.request2 17 | import java.util.concurrent.TimeUnit 18 | 19 | class SplashActivity : BaseActivity() { 20 | 21 | private val mTvState by lazy { findViewById(R.id.tv_state) } 22 | 23 | override val layoutResId = R.layout.activity_splash 24 | 25 | override fun initView() { 26 | needAuth = false 27 | 28 | val checkAt = UserConfig(this).lastUpdateCheck.toLong() 29 | val spanMinutes = System.currentTimeMillis() - checkAt / 1000 / 60 30 | 31 | if (spanMinutes > 60) { 32 | AppApi.API.releaseInfo 33 | .timeout(5, TimeUnit.SECONDS) 34 | .map(RxUtils.bodyConverter()) 35 | .doOnError { 36 | tryLogin() 37 | } 38 | .request2(this) { 39 | UserConfig(this).update { 40 | lastUpdateCheck = (System.currentTimeMillis() / 1000).toString() 41 | } 42 | if (it.versionCode > BuildConfig.VERSION_CODE) { 43 | UpdateUtils.showUpdate(this, it) { c -> 44 | if (c) { 45 | tryLogin() 46 | } 47 | } 48 | } else { 49 | tryLogin() 50 | } 51 | } 52 | } else { 53 | tryLogin() 54 | } 55 | } 56 | 57 | private fun tryLogin() { 58 | GlideIM.authDefaultAccount() 59 | .io2main() 60 | .request { 61 | onStart { 62 | // mTvState.text = "Connecting to server" 63 | } 64 | onSuccess { 65 | GlideIM.getAccount().setImMessageListener(MessageListener.getInstance()) 66 | MainActivity.start(this@SplashActivity) 67 | finish() 68 | } 69 | onError { 70 | it.printStackTrace() 71 | LoginActivity.start(this@SplashActivity) 72 | finish() 73 | } 74 | } 75 | } 76 | 77 | override fun onRequestError(t: Throwable) { 78 | t.printStackTrace() 79 | } 80 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/chat/MessageListSorter.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.chat 2 | 3 | import com.dengzii.adapter.SuperAdapter 4 | import pro.glideim.ui.SortedListAdapterCallback 5 | import pro.glideim.ui.chat.viewholder.ChatMessageViewData 6 | 7 | class MessageListSorter(adapter: SuperAdapter) : 8 | SortedListAdapterCallback(adapter) { 9 | 10 | override fun compare(o1: ChatMessageViewData, o2: ChatMessageViewData): Int { 11 | var c1 = o1.message.mid 12 | var c2 = o2.message.mid 13 | if (c1 == 0L || c2 == 0L) { 14 | c1 = o1.message.sendAt 15 | c2 = o2.message.sendAt 16 | } 17 | if (c1 == c2) { 18 | return 0 19 | } 20 | return (c2 - c1).toInt() 21 | } 22 | 23 | override fun areContentsTheSame( 24 | oldItem: ChatMessageViewData, 25 | newItem: ChatMessageViewData 26 | ): Boolean { 27 | val om = oldItem.message 28 | val nm = newItem.message 29 | return (om.sendAt == nm.sendAt 30 | && om.content == nm.content 31 | && om.status == nm.status 32 | && om.state == nm.state) 33 | } 34 | 35 | override fun areItemsTheSame(item1: ChatMessageViewData, item2: ChatMessageViewData): Boolean { 36 | if (item1.message.mid == 0L && item2.message.mid == 0L) { 37 | return item1.message.sendAt == item2.message.sendAt 38 | } 39 | return item1.message.mid == item2.message.mid 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/chat/MySortedList.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.chat 2 | 3 | import pro.glideim.ui.SortedList 4 | 5 | 6 | class MySortedList : List { 7 | 8 | lateinit var l: SortedList 9 | 10 | fun remove(i: T): Boolean { 11 | return l.remove(i) 12 | } 13 | 14 | fun add(m: T) { 15 | l.add(m) 16 | } 17 | 18 | fun clear() { 19 | l.clear() 20 | } 21 | 22 | fun addAll(ms: List) { 23 | l.addAll(ms) 24 | } 25 | 26 | override val size get() = l.size() 27 | 28 | override fun contains(element: T): Boolean { 29 | return l.indexOf(element) != SortedList.INVALID_POSITION 30 | } 31 | 32 | override fun containsAll(elements: Collection): Boolean { 33 | for (element in elements) { 34 | if (!contains(element)) { 35 | return false 36 | } 37 | } 38 | return true 39 | } 40 | 41 | override fun get(index: Int): T { 42 | return l.get(index) 43 | } 44 | 45 | override fun indexOf(element: T): Int { 46 | return l.indexOf(element) 47 | } 48 | 49 | override fun isEmpty(): Boolean { 50 | return l.size() == 0 51 | } 52 | 53 | override fun iterator(): Iterator { 54 | return object : Iterator { 55 | override fun hasNext(): Boolean { 56 | return false 57 | } 58 | 59 | override fun next(): T { 60 | return get(0) 61 | } 62 | } 63 | } 64 | 65 | override fun lastIndexOf(element: T): Int { 66 | return l.indexOf(element) 67 | } 68 | 69 | override fun listIterator(): ListIterator { 70 | return object : ListIterator { 71 | override fun hasNext() = false 72 | override fun hasPrevious() = false 73 | override fun next() = get(0) 74 | override fun nextIndex() = 0 75 | override fun previous() = get(0) 76 | override fun previousIndex() = 0 77 | } 78 | } 79 | 80 | override fun listIterator(index: Int): ListIterator { 81 | return listIterator() 82 | } 83 | 84 | override fun subList(fromIndex: Int, toIndex: Int): List { 85 | return emptyList() 86 | } 87 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/chat/viewholder/ChatImageMessageViewData.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.chat.viewholder 2 | 3 | import pro.glideim.sdk.IMMessage 4 | 5 | class ChatImageMessageViewData( 6 | showTitle: Boolean, 7 | message: IMMessage 8 | ) : ChatMessageViewData(showTitle, message) -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/chat/viewholder/ChatMessageViewData.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.chat.viewholder 2 | 3 | import pro.glideim.sdk.IMMessage 4 | 5 | open class ChatMessageViewData( 6 | var showTitle: Boolean, 7 | var message: IMMessage, 8 | var unknown: Boolean = false 9 | ) -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/chat/viewholder/ChatVoiceMessageViewData.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.chat.viewholder 2 | 3 | import pro.glideim.sdk.IMMessage 4 | 5 | class ChatVoiceMessageViewData( 6 | showTitle: Boolean, 7 | message: IMMessage 8 | ) : ChatMessageViewData(showTitle, message) -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/chat/viewholder/ChatVoteMessageViewData.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.chat.viewholder 2 | 3 | import pro.glideim.sdk.IMMessage 4 | 5 | class ChatVoteMessageViewData( 6 | showTitle: Boolean, 7 | message: IMMessage 8 | ) : ChatMessageViewData(showTitle, message) -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/chat/viewholder/GroupNotifyViewHolder.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.chat.viewholder 2 | 3 | import android.view.ViewGroup 4 | import com.dengzii.adapter.AbsViewHolder 5 | import com.google.android.material.textview.MaterialTextView 6 | import pro.glideim.R 7 | 8 | class GroupNotifyViewHolder(p: ViewGroup) : AbsViewHolder(p) { 9 | 10 | private val mTvContent by lazy { findViewById(R.id.tv_content) } 11 | 12 | override fun onCreate(parent: ViewGroup) { 13 | setContentView(R.layout.item_chat_group_notify) 14 | } 15 | 16 | override fun onBindData(data: NotifyViewData, position: Int) { 17 | mTvContent.text = data.content 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/chat/viewholder/NotifyViewData.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.chat.viewholder 2 | 3 | import pro.glideim.sdk.IMMessage 4 | 5 | data class NotifyViewData( 6 | val msg: IMMessage, 7 | val content: String 8 | ) : ChatMessageViewData(false, msg, false) -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/contacts/AddContactsActivity.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.contacts 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import com.dengzii.ktx.android.content.intentExtra 6 | import com.google.android.material.button.MaterialButton 7 | import com.google.android.material.textfield.TextInputEditText 8 | import pro.glideim.R 9 | import pro.glideim.base.BaseActivity 10 | import pro.glideim.sdk.GlideIM 11 | import pro.glideim.sdk.api.user.ContactsUidDto 12 | import pro.glideim.sdk.api.user.UserApi 13 | import pro.glideim.ui.Events 14 | import pro.glideim.utils.io2main 15 | import pro.glideim.utils.request 16 | import pro.glideim.utils.request2 17 | 18 | class AddContactsActivity : BaseActivity() { 19 | private val mBtQrCode by lazy { findViewById(R.id.bt_qr_code) } 20 | private val mBtSearch by lazy { findViewById(R.id.bt_search) } 21 | private val mEtId by lazy { findViewById(R.id.et_id) } 22 | 23 | private val mSearchGroup by intentExtra("group", false) 24 | 25 | override val layoutResId = R.layout.activity_add_contacts 26 | 27 | companion object { 28 | @JvmStatic 29 | fun start(context: Context, isGroup: Boolean) { 30 | val starter = Intent(context, AddContactsActivity::class.java).apply { 31 | putExtra("group", isGroup) 32 | } 33 | context.startActivity(starter) 34 | } 35 | } 36 | 37 | override fun initView() { 38 | if (mSearchGroup) { 39 | mEtId.hint = "Input Group ID" 40 | } else { 41 | mEtId.hint = "Input User ID" 42 | } 43 | mBtSearch.setOnClickListener { 44 | search() 45 | } 46 | mBtQrCode.setOnClickListener { 47 | toast("TODO") 48 | } 49 | } 50 | 51 | private fun search() { 52 | val id = mEtId.text.toString() 53 | if (id.toLongOrNull() == null || id.length < 2) { 54 | toast("check id") 55 | return 56 | } 57 | if (mSearchGroup) { 58 | GlideIM.getAccount().joinGroup(id.toLong()) 59 | .io2main() 60 | .request2(this) { 61 | toast("Group added") 62 | Events.updateContacts() 63 | finish() 64 | } 65 | } else { 66 | UserApi.API.addContacts(ContactsUidDto(id.toLong(), "")) 67 | .request(this) { 68 | toast("Contacts added") 69 | Events.updateContacts() 70 | finish() 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/dev/DevOptionsActivity.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.dev 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.view.ContextMenu 7 | import android.view.Menu 8 | import android.view.View 9 | import androidx.core.content.edit 10 | import com.blankj.utilcode.util.AppUtils 11 | import com.dengzii.ktx.android.content.update 12 | import com.dengzii.ktx.android.content.use 13 | import com.google.android.material.switchmaterial.SwitchMaterial 14 | import com.google.android.material.textfield.TextInputEditText 15 | import pro.glideim.BuildConfig 16 | import pro.glideim.R 17 | import pro.glideim.UserConfig 18 | import pro.glideim.base.BaseActivity 19 | 20 | class DevOptionsActivity : BaseActivity() { 21 | 22 | private val mSwEnableCache by lazy { findViewById(R.id.sw_enable_cache) } 23 | private val mEtBaseUrl by lazy { findViewById(R.id.et_base_url) } 24 | 25 | override val layoutResId = R.layout.activity_dev_options 26 | 27 | companion object { 28 | @JvmStatic 29 | fun start(context: Context) { 30 | val starter = Intent(context, DevOptionsActivity::class.java) 31 | context.startActivity(starter) 32 | } 33 | } 34 | 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | needAuth = false 37 | super.onCreate(savedInstanceState) 38 | } 39 | 40 | override fun initView() { 41 | title = "Developer Options" 42 | 43 | UserConfig(this).use { 44 | mSwEnableCache.isChecked = enableCache 45 | mEtBaseUrl.setText(baseUrl) 46 | } 47 | } 48 | 49 | private fun apply() { 50 | UserConfig(this).update { 51 | enableCache = mSwEnableCache.isChecked 52 | baseUrl = mEtBaseUrl.text.toString() 53 | } 54 | AppUtils.relaunchApp(true) 55 | } 56 | 57 | private fun reset() { 58 | mSwEnableCache.isChecked = false 59 | mEtBaseUrl.setText(BuildConfig.BASE_URL) 60 | } 61 | 62 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 63 | menu ?: return super.onCreateOptionsMenu(menu) 64 | 65 | val reset = menu.add(0, 1, 0, "Reset") 66 | reset.setShowAsAction(1) 67 | reset.isVisible = true 68 | reset.setOnMenuItemClickListener { 69 | reset() 70 | false 71 | } 72 | 73 | val apply = menu.add(0, 2, 0, "Apply") 74 | apply.setShowAsAction(2) 75 | apply.isVisible = true 76 | apply.setOnMenuItemClickListener { 77 | apply() 78 | false 79 | } 80 | 81 | return true 82 | } 83 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/group/GroupMemberViewData.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.group 2 | 3 | import pro.glideim.sdk.api.group.GroupMemberBean 4 | import pro.glideim.sdk.api.user.UserInfoBean 5 | 6 | data class GroupMemberViewData( 7 | val memberInfo: GroupMemberBean, 8 | val userInfo: UserInfoBean 9 | ) -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/session/SessionListSorter.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.session 2 | 3 | import com.dengzii.adapter.SuperAdapter 4 | import pro.glideim.ui.SortedListAdapterCallback 5 | 6 | class SessionListSorter(adapter: SuperAdapter) : 7 | SortedListAdapterCallback(adapter) { 8 | 9 | override fun compare(o1: SessionViewData, o2: SessionViewData): Int { 10 | if (o1.updateAt == o2.updateAt) { 11 | return 0 12 | } 13 | return (o2.updateAt - o1.updateAt).toInt() 14 | } 15 | 16 | override fun areContentsTheSame(oldItem: SessionViewData, newItem: SessionViewData): Boolean { 17 | return oldItem.updateAt == newItem.updateAt && 18 | oldItem.title == newItem.title && 19 | oldItem.unread == newItem.unread && 20 | oldItem.avatar == newItem.avatar && 21 | oldItem.lastMsg == newItem.lastMsg 22 | } 23 | 24 | override fun areItemsTheSame(item1: SessionViewData, item2: SessionViewData): Boolean { 25 | return item1.to == item2.to && item1.type == item2.type 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/session/SessionViewData.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.session 2 | 3 | import pro.glideim.sdk.IMSession 4 | 5 | class SessionViewData private constructor( 6 | val s: IMSession, 7 | val type: Int, 8 | val to: Long, 9 | val title: String, 10 | var updateAt: Long, 11 | val lastMsg: String, 12 | val avatar: String, 13 | val unread: Int, 14 | val preUpdateAt:Long 15 | ) { 16 | companion object { 17 | fun create(s: IMSession): SessionViewData { 18 | return SessionViewData( 19 | s = s, 20 | type = s.type, 21 | to = s.to, 22 | s.title, 23 | s.updateAt, 24 | s.lastMsg ?: "", 25 | s.avatar, 26 | s.unread, 27 | s.previousUpdateAt 28 | ) 29 | } 30 | } 31 | 32 | override fun toString(): String { 33 | return "$type@$to" 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/ui/session/SessionViewHolder.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.ui.session 2 | 3 | import android.view.ViewGroup 4 | import android.widget.TextView 5 | import androidx.appcompat.widget.AppCompatImageView 6 | import com.dengzii.adapter.AbsViewHolder 7 | import com.dengzii.ktx.android.antiShakeClick 8 | import com.dengzii.ktx.android.hide 9 | import com.dengzii.ktx.android.show 10 | import com.google.android.material.textview.MaterialTextView 11 | import pro.glideim.R 12 | import pro.glideim.base.BaseActivity 13 | import pro.glideim.sdk.Constants 14 | import pro.glideim.ui.chat.ChatActivity 15 | import pro.glideim.utils.GroupAvatarUtils 16 | import pro.glideim.utils.loadImageRoundCorners 17 | import pro.glideim.utils.secToTimeSpan 18 | 19 | class SessionViewHolder(v: ViewGroup) : AbsViewHolder(v) { 20 | 21 | private val mTvNewMessage by lazy { findViewById(R.id.tv_new_message) } 22 | private val mTvTime by lazy { findViewById(R.id.tv_time) } 23 | private val mTvContent by lazy { findViewById(R.id.tv_content) } 24 | private val mTvTitle by lazy { findViewById(R.id.tv_title) } 25 | private val mIvAvatar by lazy { findViewById(R.id.iv_avatar) } 26 | private val mVgContainer by lazy { findViewById(R.id.vg_container) } 27 | 28 | override fun onCreate(parent: ViewGroup) { 29 | setContentView(R.layout.item_session) 30 | } 31 | 32 | override fun onBindData(data: SessionViewData, position: Int) { 33 | 34 | if (data.type == Constants.SESSION_TYPE_GROUP) { 35 | GroupAvatarUtils.loadAvatar((context as BaseActivity).account, data.to, 4f, mIvAvatar) 36 | } else { 37 | mIvAvatar.loadImageRoundCorners(data.avatar, 4f) 38 | } 39 | 40 | mTvTitle.text = data.title + "${data.to}" 41 | // mTvContent.text = data.lastMsg 42 | mTvContent.text = data.s.lastMsg 43 | if (data.unread > 0) { 44 | mTvNewMessage.show() 45 | mTvNewMessage.text = data.unread.toString() 46 | } else { 47 | mTvNewMessage.hide() 48 | } 49 | mTvTime.text = data.updateAt.secToTimeSpan() 50 | 51 | mVgContainer.antiShakeClick { 52 | ChatActivity.start(context, data.to, data.type) 53 | } 54 | } 55 | 56 | override fun onBindData(data: SessionViewData, position: Int, payloads: MutableList?) { 57 | super.onBindData(data, position, payloads) 58 | 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/utils/GlideExtension.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.utils 2 | 3 | import android.widget.ImageView 4 | import androidx.annotation.DrawableRes 5 | import com.bumptech.glide.Glide 6 | import com.bumptech.glide.load.resource.bitmap.CircleCrop 7 | import com.bumptech.glide.load.resource.bitmap.RoundedCorners 8 | import com.bumptech.glide.request.RequestOptions 9 | import com.dengzii.ktx.android.dp2px 10 | import pro.glideim.R 11 | 12 | fun ImageView.loadImage(@DrawableRes res: Int) { 13 | 14 | Glide.with(this) 15 | .load(res) 16 | .apply(RequestOptions.fitCenterTransform()) 17 | .into(this).clearOnDetach() 18 | } 19 | 20 | 21 | fun ImageView.loadImage(url: String?) { 22 | 23 | if (url.isNullOrEmpty()) { 24 | loadImage(R.mipmap.ic_launcher) 25 | return 26 | } 27 | Glide.with(this) 28 | .load(url) 29 | .apply(RequestOptions.fitCenterTransform()) 30 | .placeholder(R.mipmap.ic_launcher) 31 | .into(this) 32 | .clearOnDetach() 33 | } 34 | 35 | 36 | fun ImageView.loadImageClipCircle(url: String?) { 37 | 38 | if (url.isNullOrEmpty()) { 39 | return 40 | } 41 | Glide.with(this) 42 | .load(url) 43 | .apply(RequestOptions.bitmapTransform(CircleCrop())) 44 | .placeholder(R.mipmap.ic_launcher) 45 | .into(this) 46 | .clearOnDetach() 47 | } 48 | 49 | fun ImageView.loadImageRoundCorners(url: String?, radius: Float = 10f) { 50 | 51 | if (url.isNullOrEmpty()) { 52 | return 53 | } 54 | Glide.with(this) 55 | .load(url) 56 | .apply(RequestOptions.bitmapTransform(RoundedCorners(radius.dp2px()))) 57 | .placeholder(R.mipmap.ic_launcher) 58 | .into(this) 59 | .clearOnDetach() 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/utils/ImageUploader.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.utils 2 | 3 | object ImageUploader { 4 | 5 | fun upload() { 6 | 7 | } 8 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/utils/ItemDecorationFactory.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.utils 2 | 3 | import android.graphics.Canvas 4 | import android.graphics.Paint 5 | import android.graphics.Rect 6 | import android.view.View 7 | import androidx.recyclerview.widget.RecyclerView 8 | import com.dengzii.ktx.android.dp2px 9 | 10 | 11 | object ItemDecorationFactory { 12 | 13 | fun createOffset( 14 | dp: Int 15 | ): RecyclerView.ItemDecoration { 16 | 17 | return object : RecyclerView.ItemDecoration() { 18 | val size = dp.toFloat().dp2px() 19 | override fun getItemOffsets( 20 | outRect: Rect, 21 | view: View, 22 | parent: RecyclerView, 23 | state: RecyclerView.State 24 | ) { 25 | super.getItemOffsets(outRect, view, parent, state) 26 | outRect.set(0, size / 2, 0, size / 2) 27 | } 28 | } 29 | } 30 | 31 | fun createDivider( 32 | dpSize: Float, color: Int, 33 | marginStart: Float = 0f, 34 | marginEnd: Float = 0f 35 | ): RecyclerView.ItemDecoration { 36 | 37 | return object : RecyclerView.ItemDecoration() { 38 | val size = dpSize.dp2px() 39 | val paint by lazy { 40 | Paint().apply { 41 | setColor(color) 42 | strokeWidth = size.toFloat() 43 | } 44 | } 45 | val startX = marginStart.dp2px().toFloat() 46 | 47 | override fun getItemOffsets( 48 | outRect: Rect, view: View, 49 | parent: RecyclerView, state: RecyclerView.State 50 | ) { 51 | super.getItemOffsets(outRect, view, parent, state) 52 | outRect.set(0, size / 2, 0, size / 2) 53 | } 54 | 55 | override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { 56 | super.onDrawOver(c, parent, state) 57 | for (i in 0 until parent.childCount - 1) { 58 | val view = parent.getChildAt(i) 59 | val top = view.bottom.toFloat() 60 | // val left = view.paddingLeft + size 61 | val right = (view.width - view.paddingRight - size).toFloat() 62 | // val bottom = top + size 63 | c.drawLine(startX, top, right - marginEnd.dp2px(), top, paint) 64 | } 65 | } 66 | } 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/utils/LifecycleExtensions.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.utils 2 | 3 | import androidx.lifecycle.Lifecycle 4 | import androidx.lifecycle.LifecycleEventObserver 5 | import androidx.lifecycle.LifecycleOwner 6 | 7 | 8 | fun LifecycleOwner.onState(state: Lifecycle.State, callback: () -> Unit) { 9 | lifecycle.addObserver(object : LifecycleEventObserver { 10 | override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { 11 | if (event.targetState == state) { 12 | callback.invoke() 13 | lifecycle.removeObserver(this) 14 | } 15 | } 16 | }) 17 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/utils/SwipeRefreshExtension.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.utils 2 | 3 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout 4 | import pro.glideim.R 5 | 6 | 7 | var SwipeRefreshLayout.onRefreshCallback: (() -> Unit)? 8 | set(value) { 9 | setTag(R.id.tag_swipe_refresh_on_refresh_listener, value) 10 | } 11 | get() { 12 | return getTag(R.id.tag_swipe_refresh_on_refresh_listener) as? () -> Unit 13 | } 14 | 15 | fun SwipeRefreshLayout.onRefresh(callback: () -> Unit) { 16 | setOnRefreshListener { 17 | callback.invoke() 18 | } 19 | onRefreshCallback = callback 20 | } 21 | 22 | fun SwipeRefreshLayout.startRefresh() { 23 | isRefreshing = true 24 | onRefreshCallback?.invoke() 25 | } 26 | 27 | fun SwipeRefreshLayout.finishRefresh() { 28 | isRefreshing = false 29 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/utils/TimeSpanExtensions.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.utils 2 | 3 | import java.util.* 4 | 5 | 6 | private const val hourSec = 60 * 60 7 | private const val daySec = hourSec * 24 8 | private const val mothSec = daySec * 30 9 | 10 | fun Long.secToTimeSpan(): String { 11 | 12 | val instance = Calendar.getInstance(Locale.getDefault()) 13 | instance.time = Date(this * 1000) 14 | val today = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) 15 | 16 | val m = instance.get(Calendar.MONTH) + 1 17 | val d = instance.get(Calendar.DAY_OF_MONTH) 18 | val h = instance.get(Calendar.HOUR_OF_DAY) 19 | val min = instance.get(Calendar.MINUTE) 20 | 21 | return when (today - d) { 22 | 0 -> "$h:${if (min < 10) "0" else ""}$min" 23 | 1 -> "昨天" 24 | 2 -> "前天" 25 | else -> "$m-$d" 26 | } 27 | 28 | // return when { 29 | // span <= 10 -> "刚刚" 30 | // span <= 60 -> "$span 秒前" 31 | // span <= 30 * 60 -> "${span / 60} 分钟前" 32 | // span <= hourSec -> "半小时时前" 33 | // span <= daySec -> "${span / hourSec} 小时前" 34 | // span <= daySec * 2 -> "昨天" 35 | // span <= daySec * 3 -> "前天" 36 | // span <= mothSec -> "${span / daySec} 天前" 37 | // else -> "${span / mothSec} 个月前" 38 | // } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/utils/UpdateUtils.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.utils 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.net.Uri 6 | import androidx.appcompat.app.AlertDialog 7 | import com.dengzii.ktx.format 8 | import pro.glideim.BuildConfig 9 | import pro.glideim.sdk.api.app.ReleaseInfoBean 10 | import java.util.* 11 | 12 | object UpdateUtils { 13 | 14 | fun showUpdate(context: Context, info: ReleaseInfoBean, callback: (cancel: Boolean) -> Unit) { 15 | val builder = AlertDialog.Builder(context) 16 | val date = Date(info.updateAt * 1000) 17 | val format = date.format("yyyy MM.dd") 18 | builder.setCancelable(false) 19 | builder.setTitle("New Version ${info.versionName}") 20 | builder.setMessage( 21 | "Current: ${BuildConfig.VERSION_NAME}\n" + 22 | "Date: $format\n" + 23 | "What's New: \n" + 24 | "${info.description}\n" 25 | ) 26 | builder.setPositiveButton("Download") { d, _ -> 27 | val intent = Intent(Intent.ACTION_VIEW) 28 | intent.data = Uri.parse(info.downloadUrl) 29 | context.startActivity(intent) 30 | d.dismiss() 31 | callback(false) 32 | } 33 | builder.setNegativeButton("Cancel") { d, _ -> 34 | d.dismiss() 35 | callback(true) 36 | } 37 | builder.create().show() 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/pro/glideim/viewholder/EmptyViewHolder.kt: -------------------------------------------------------------------------------- 1 | package pro.glideim.viewholder 2 | 3 | import android.view.ViewGroup 4 | import com.dengzii.adapter.AbsViewHolder 5 | import com.dengzii.adapter.SuperAdapter 6 | 7 | class EmptyViewHolder(v: ViewGroup) : AbsViewHolder(v) { 8 | 9 | override fun onCreate(parent: ViewGroup) { 10 | 11 | } 12 | 13 | override fun onBindData(data: SuperAdapter.Empty, position: Int) { 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_account.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_outline.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_camera.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_circle.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_contacts.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_contacts_add.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_cache.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dev_mode.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_emoji.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_face.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_file.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_keyboard.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_location.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_logout.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_message.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more_menu.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notify.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_photos.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_send.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_update.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_voice.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_vote.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple_option.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_badge_circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_option_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_contacts.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 36 | 37 | 40 | 41 | 46 | 47 | 48 | 49 | 55 | 56 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_dev_options.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_group_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 14 | 22 | 23 | 28 | 29 | 30 | 31 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_register.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 19 | 20 | 28 | 29 | 30 | 34 | 35 | 42 | 43 | 44 | 45 | 49 | 50 | 57 | 58 | 59 | 66 | 67 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_select_contacts.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 26 | 27 | 28 | 38 | 39 | 40 | 41 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_session.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 22 | 23 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_chat_group_notify.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_chat_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_contacts.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_empty.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_group_member.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 23 | 24 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_select_contacts.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 18 | 19 | 29 | 30 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_session.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | 30 | 31 | 43 | 44 | 45 | 52 | 53 | 65 | 66 | -------------------------------------------------------------------------------- /app/src/main/res/layout/pop_message.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_chat_group.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_chat_user.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_contacts_add.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 12 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_home_nav.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glide-im/Glide-IM-Android/19a8f741ceab19dfe12c0cd1c115adce26d8cf4f/app/src/main/res/mipmap/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #0097a7 5 | #56c8d8 6 | #006978 7 | #fb8c00 8 | #ffbd45 9 | #c25e00 10 | #333 11 | #5C5C5C 12 | 13 | #FFFFFF 14 | #DCDCDC 15 | 16 | #E3E3E3 17 | 18 | #fff 19 | #ffcccccc 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | GlideIM 3 | Login 4 | Account 5 | Password 6 | Sign In 7 | submit 8 | Sign Up 9 | Forgot Password? 10 | or 11 | Register 12 | Password again 13 | SignIn 14 | Home 15 | Messages 16 | Profile 17 | Sign Out 18 | Contacts 19 | UID or Group ID 20 | Search 21 | Scan QR Code 22 | QR Code 23 | New Contacts 24 | Chat 25 | Notifications 26 | Add Friend 27 | Add Group 28 | Create Group 29 | Search User 30 | Join Group 31 | Members 32 | Invite 33 | Exit And Delete 34 | Group Members 35 | Clean Cache 36 | Update Profile 37 | Settings 38 | Complete 39 | Recall 40 | Api Base URL 41 | Enable Cache 42 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | 23 | 24 | 28 | 29 | 34 | 35 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply from: "ci.gradle" 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | jcenter() 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:4.1.3' 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20" 12 | classpath 'com.blankj:bus-gradle-plugin:2.6' 13 | 14 | // NOTE: Do not place your application dependencies here; they belong 15 | // in the individual module build.gradle files 16 | } 17 | } 18 | 19 | task clean(type: Delete) { 20 | delete rootProject.buildDir 21 | } -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | // config repositories 3 | repositories { 4 | 5 | } 6 | 7 | // config gradle project type 8 | // we config groovy and java-gradle-plugin 9 | // this means 10 | apply { 11 | plugin 'groovy' 12 | plugin 'java-gradle-plugin' 13 | } 14 | 15 | // import gradle api and groovy lang 16 | dependencies { 17 | implementation gradleApi() 18 | implementation localGroovy() 19 | } -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/Config.groovy: -------------------------------------------------------------------------------- 1 | class Config { 2 | 3 | static version = 144 4 | static versionName = "1.4.4" 5 | } -------------------------------------------------------------------------------- /ci.gradle: -------------------------------------------------------------------------------- 1 | // ./gradlew buildCiRelease -PVERSION_NAME=1.0.0 -PVERSION_CODE=1 -PAPK_NAME=a.apk 2 | 3 | task initBuildVersion { 4 | def p = gradle.startParameter.projectProperties 5 | if(!p.containsKey("VERSION_NAME")){ 6 | return 7 | } 8 | Config.versionName = VERSION_NAME.toString().replaceAll("v", "") 9 | Config.version = Integer.parseInt(VERSION_CODE.toString().replaceAll("[^0-9]", "")) 10 | } 11 | 12 | task buildCiRelease(dependsOn: ["initBuildVersion", "app:assembleRelease"], type: Copy) { 13 | from "${rootProject.projectDir.path}/app/build/outputs/apk/release/" 14 | into "./" 15 | include('*.apk') 16 | exclude('*.json') 17 | 18 | doLast { 19 | File f = new File("app-release.apk") 20 | f.renameTo(APK_NAME) 21 | } 22 | } 23 | 24 | buildCiRelease.mustRunAfter initBuildVersion -------------------------------------------------------------------------------- /glide-im-sdk/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /glide-im-sdk/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'kotlin-android' 4 | } 5 | 6 | android { 7 | compileSdk 31 8 | 9 | defaultConfig { 10 | minSdk 26 11 | targetSdk 31 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | vectorDrawables.useSupportLibrary true 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | consumerProguardFiles "consumer-rules.pro" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_1_8 28 | targetCompatibility JavaVersion.VERSION_1_8 29 | } 30 | kotlinOptions { 31 | jvmTarget = '1.8' 32 | } 33 | testOptions { 34 | unitTests.all { 35 | useJUnitPlatform() 36 | } 37 | } 38 | } 39 | 40 | dependencies { 41 | 42 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0' 43 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' 44 | 45 | implementation 'androidx.core:core-ktx:1.7.0' 46 | implementation 'io.netty:netty-all:4.1.70.Final' 47 | 48 | 49 | implementation 'io.reactivex.rxjava2:rxjava:2.1.9' 50 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 51 | implementation 'com.squareup.okhttp3:okhttp:4.9.0' 52 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0' 53 | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' 54 | implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1' 55 | 56 | implementation 'io.reactivex.rxjava2:rxjava:2.1.9' 57 | implementation 'com.squareup.retrofit2:retrofit:2.9.0' 58 | implementation 'com.squareup.okhttp3:okhttp:4.9.0' 59 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0' 60 | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' 61 | } -------------------------------------------------------------------------------- /glide-im-sdk/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glide-im/Glide-IM-Android/19a8f741ceab19dfe12c0cd1c115adce26d8cf4f/glide-im-sdk/consumer-rules.pro -------------------------------------------------------------------------------- /glide-im-sdk/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /glide-im-sdk/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/AccountStateListener.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | public interface AccountStateListener { 4 | void onLoggedIn(); 5 | 6 | void onReconnect(); 7 | 8 | void onKickOut(String deviceInfo); 9 | } 10 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/Constants.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | public class Constants { 4 | 5 | public static final int GROUP_MEMBER_OWNER = 1; 6 | public static final int GROUP_MEMBER_ADMIN = 2; 7 | public static final int GROUP_MEMBER = 3; 8 | 9 | public static final int SESSION_TYPE_USER = 1; 10 | public static final int SESSION_TYPE_GROUP = 2; 11 | public static final int SESSION_TYPE_DEVICE = 3; 12 | 13 | public static final int MESSAGE_TYPE_GROUP_NOTIFY = -1; 14 | public static final int MESSAGE_TYPE_TEXT = 1; 15 | public static final int MESSAGE_TYPE_IMAGE = 2; 16 | public static final int MESSAGE_TYPE_VOICE = 3; 17 | public static final int MESSAGE_TYPE_RECALL = 100; 18 | } 19 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/ContactChangeListener.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | public interface ContactChangeListener { 4 | void onNewContact(IMContact c); 5 | 6 | void onContactUpdate(IMContact contact); 7 | 8 | void onContactRemove(IMContact contact); 9 | } 10 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/DataStorage.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import java.util.List; 4 | 5 | import pro.glideim.sdk.api.group.GroupInfoBean; 6 | import pro.glideim.sdk.api.user.UserInfoBean; 7 | 8 | public interface DataStorage { 9 | 10 | long getDefaultAccountUid(); 11 | 12 | void storeToken(long uid, String token); 13 | 14 | String loadToken(long uid); 15 | 16 | void storeTempUserInfo(UserInfoBean userInfoBean); 17 | 18 | UserInfoBean loadTempUserInfo(long uid); 19 | 20 | void storeTempGroupInfo(GroupInfoBean groupInfoBean); 21 | 22 | GroupInfoBean loadTempGroupInfo(long gid); 23 | 24 | void storeSession(long uid, IMSession session); 25 | 26 | List loadSessions(long uid); 27 | 28 | List loadMessage(long uid, int type, long to); 29 | 30 | void storeMessage(IMMessage message); 31 | } 32 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/DefaultDataStoreImpl.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import pro.glideim.sdk.api.group.GroupInfoBean; 9 | import pro.glideim.sdk.api.user.UserInfoBean; 10 | 11 | public class DefaultDataStoreImpl implements DataStorage { 12 | 13 | 14 | private static final Map sTempUserInfo = new HashMap<>(); 15 | private static final Map sTempGroupInfo = new HashMap<>(); 16 | private static final Map> sTempSession = new HashMap<>(); 17 | 18 | private String token = ""; 19 | private long uid = 0; 20 | 21 | @Override 22 | public long getDefaultAccountUid() { 23 | return uid; 24 | } 25 | 26 | @Override 27 | public void storeToken(long uid, String token) { 28 | this.uid = uid; 29 | this.token = token; 30 | } 31 | 32 | @Override 33 | public String loadToken(long uid) { 34 | return token; 35 | } 36 | 37 | @Override 38 | public void storeTempUserInfo(UserInfoBean userInfoBean) { 39 | sTempUserInfo.put(userInfoBean.getUid(), userInfoBean); 40 | } 41 | 42 | @Override 43 | public UserInfoBean loadTempUserInfo(long uid) { 44 | return sTempUserInfo.get(uid); 45 | } 46 | 47 | @Override 48 | public void storeTempGroupInfo(GroupInfoBean groupInfoBean) { 49 | sTempGroupInfo.put(groupInfoBean.getGid(), groupInfoBean); 50 | } 51 | 52 | @Override 53 | public GroupInfoBean loadTempGroupInfo(long gid) { 54 | return sTempGroupInfo.get(gid); 55 | } 56 | 57 | @Override 58 | public void storeSession(long uid, IMSession session) { 59 | if (!sTempSession.containsKey(uid)) { 60 | sTempSession.put(uid, new HashMap<>()); 61 | } 62 | sTempSession.get(uid).put(session.to, session); 63 | } 64 | 65 | @Override 66 | public List loadSessions(long uid) { 67 | if (!sTempSession.containsKey(uid)) { 68 | sTempSession.put(uid, new HashMap<>()); 69 | } 70 | return new ArrayList<>(sTempSession.get(uid).values()); 71 | } 72 | 73 | @Override 74 | public List loadMessage(long uid, int type, long to) { 75 | return new ArrayList<>(); 76 | } 77 | 78 | @Override 79 | public void storeMessage(IMMessage message) { 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/GlideException.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | public class GlideException extends Exception { 4 | public GlideException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/IMContact.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import io.reactivex.Single; 4 | import pro.glideim.sdk.api.user.ContactsBean; 5 | import pro.glideim.sdk.api.user.UserInfoBean; 6 | import pro.glideim.sdk.utils.SLogger; 7 | 8 | public class IMContact { 9 | 10 | public static final int TYPE_GROUP = 2; 11 | public static final int TYPE_USER = 1; 12 | 13 | public String title; 14 | public String avatar; 15 | public long id; 16 | public int type; 17 | private IMAccount account; 18 | 19 | public static IMContact fromContactsBean(ContactsBean contactsBean, IMContactList contactList, IMAccount account) { 20 | if (contactsBean.getType() == TYPE_GROUP) { 21 | return new IMGroupContact(account, contactList,contactsBean); 22 | } 23 | IMContact c = new IMContact(); 24 | c.type = contactsBean.getType(); 25 | c.id = contactsBean.getId(); 26 | c.title = contactsBean.getRemark(); 27 | c.account = account; 28 | return c; 29 | } 30 | 31 | public Single update() { 32 | if (type == Constants.SESSION_TYPE_USER) { 33 | return GlideIM.getUserInfo(id) 34 | .doOnSuccess(this::setDetail) 35 | .map(userInfoBeans -> IMContact.this); 36 | } 37 | SLogger.d("IMContacts", "unknown contacts type " + type); 38 | return Single.just(this); 39 | } 40 | 41 | private void setDetail(UserInfoBean userInfoBean) { 42 | title = userInfoBean.getNickname(); 43 | avatar = userInfoBean.getAvatar(); 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "IMContacts{" + 49 | "title='" + title + '\'' + 50 | ", avatar='" + avatar + '\'' + 51 | ", id=" + id + 52 | ", type=" + type + 53 | '}'; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/IMContactList.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.TreeMap; 6 | 7 | import pro.glideim.sdk.utils.SLogger; 8 | 9 | public class IMContactList { 10 | 11 | private final TreeMap contactsUser = new TreeMap<>(); 12 | private final TreeMap contactsGroup = new TreeMap<>(); 13 | private final IMAccount account; 14 | private final List contactChangeListeners = new ArrayList<>(); 15 | 16 | public IMContactList(IMAccount account) { 17 | this.account = account; 18 | } 19 | 20 | public void addContactChangeListener(ContactChangeListener l) { 21 | this.contactChangeListeners.add(l); 22 | } 23 | 24 | public void removeContactChangeListener(ContactChangeListener l) { 25 | this.contactChangeListeners.remove(l); 26 | } 27 | 28 | public IMContact getUser(long uid) { 29 | return contactsUser.get(uid); 30 | } 31 | 32 | public IMGroupContact getGroup(long gid) { 33 | return contactsGroup.get(gid); 34 | } 35 | 36 | public void removeGroup(long gid) { 37 | IMContact contact = contactsGroup.remove(gid); 38 | onRemove(contact); 39 | } 40 | 41 | public void removeUser(long uid) { 42 | IMContact contact = contactsUser.remove(uid); 43 | onRemove(contact); 44 | } 45 | 46 | private void onRemove(IMContact c) { 47 | for (ContactChangeListener l : contactChangeListeners) { 48 | l.onContactRemove(c); 49 | } 50 | } 51 | 52 | void onUpdate(IMContact c) { 53 | for (ContactChangeListener l : contactChangeListeners) { 54 | l.onContactUpdate(c); 55 | } 56 | } 57 | 58 | public void addContacts(IMContact contact) { 59 | switch (contact.type) { 60 | case IMContact.TYPE_GROUP: 61 | if (!(contact instanceof IMGroupContact)) { 62 | SLogger.e("IMContactList", new IllegalArgumentException("group contact not instance of IMGroupContact")); 63 | return; 64 | } 65 | contactsGroup.put(contact.id, ((IMGroupContact) contact)); 66 | break; 67 | case IMContact.TYPE_USER: 68 | contactsUser.put(contact.id, contact); 69 | break; 70 | default: 71 | SLogger.e("IMContactList", new IllegalArgumentException("unknown contact type")); 72 | return; 73 | } 74 | for (ContactChangeListener l : contactChangeListeners) { 75 | l.onNewContact(contact); 76 | } 77 | } 78 | 79 | public List getAll() { 80 | return new ArrayList<>(contactsUser.values()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/IMGroupNotifyMessage.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import pro.glideim.sdk.messages.GroupNotify; 4 | import pro.glideim.sdk.messages.GroupNotifyMemberChanges; 5 | 6 | public class IMGroupNotifyMessage extends IMMessage { 7 | 8 | public GroupNotify notify; 9 | 10 | public IMGroupNotifyMessage(IMAccount account, GroupNotify notify) { 11 | super(account); 12 | this.notify = notify; 13 | this.setMid(notify.getMid()); 14 | this.setCliSeq(0); 15 | this.setFrom(0); 16 | this.setTo(notify.getGid()); 17 | this.setSeq(notify.getSeq()); 18 | this.setType(Constants.MESSAGE_TYPE_GROUP_NOTIFY); 19 | this.setSendAt(notify.getTimestamp()); 20 | this.setContent("-"); 21 | this.setTarget(Constants.SESSION_TYPE_GROUP, notify.getGid()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/IMMessageListener.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import pro.glideim.sdk.push.NewContactsMessage; 4 | 5 | public interface IMMessageListener { 6 | void onNotify(String msg); 7 | 8 | void onNewMessage(IMMessage message); 9 | 10 | void onNewContact(NewContactsMessage c); 11 | 12 | void onKickOut(); 13 | 14 | void onTokenInvalid(); 15 | } 16 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/Logger.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | public interface Logger { 4 | void d(String tag, String log); 5 | 6 | void e(String tag, Throwable t); 7 | } 8 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/MessageChangeListener.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | public interface MessageChangeListener { 6 | void onChange(long mid, @NonNull IMMessage message); 7 | 8 | void onInsertMessage(long mid, @NonNull IMMessage message); 9 | 10 | void onNewMessage(@NonNull IMMessage message); 11 | } 12 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/Pair.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | public class Pair { 4 | public final K k; 5 | public final V v; 6 | 7 | public Pair(K k, V v) { 8 | this.k = k; 9 | this.v = v; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/ParameterizedTypeImpl.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import java.lang.reflect.ParameterizedType; 4 | import java.lang.reflect.Type; 5 | 6 | public class ParameterizedTypeImpl implements ParameterizedType { 7 | private final Class raw; 8 | private final Type[] args; 9 | 10 | public ParameterizedTypeImpl(Class raw, Type[] args) { 11 | this.raw = raw; 12 | this.args = args != null ? args : new Type[0]; 13 | } 14 | 15 | @Override 16 | public Type[] getActualTypeArguments() { 17 | return args; 18 | } 19 | 20 | @Override 21 | public Type getRawType() { 22 | return raw; 23 | } 24 | 25 | @Override 26 | public Type getOwnerType() { 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/SessionUpdateListener.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | public interface SessionUpdateListener { 4 | void onUpdate(IMSession session); 5 | 6 | void onNewSession(IMSession session); 7 | } -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/SilentObserver.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import org.json.JSONStringer; 6 | 7 | import io.reactivex.Observer; 8 | import io.reactivex.SingleObserver; 9 | import io.reactivex.disposables.Disposable; 10 | import pro.glideim.sdk.utils.SLogger; 11 | 12 | public class SilentObserver implements Observer, SingleObserver { 13 | 14 | @Override 15 | public void onSubscribe(@NonNull Disposable d) { 16 | 17 | } 18 | 19 | @Override 20 | public void onSuccess(@NonNull T t) { 21 | onNext(t); 22 | } 23 | 24 | @Override 25 | public void onNext(@NonNull T t) { 26 | 27 | } 28 | 29 | @Override 30 | public void onError(@NonNull Throwable e) { 31 | StackTraceElement stackTraceElement = e.getStackTrace()[0]; 32 | SLogger.d("SilentObserver", e.getMessage() + " : " + stackTraceElement.toString()); 33 | } 34 | 35 | @Override 36 | public void onComplete() { 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/Response.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api; 2 | 3 | public class Response { 4 | private int code; 5 | private String msg; 6 | private T data; 7 | 8 | public boolean success(){ 9 | return code == 100; 10 | } 11 | 12 | public int getCode() { 13 | return code; 14 | } 15 | 16 | public void setCode(int code) { 17 | this.code = code; 18 | } 19 | 20 | public String getMsg() { 21 | return msg; 22 | } 23 | 24 | public void setMsg(String msg) { 25 | this.msg = msg; 26 | } 27 | 28 | public T getData() { 29 | return data; 30 | } 31 | 32 | public void setData(T data) { 33 | this.data = data; 34 | } 35 | } -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/app/AppApi.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.app; 2 | 3 | import io.reactivex.Observable; 4 | import pro.glideim.sdk.api.Response; 5 | import pro.glideim.sdk.http.RetrofitManager; 6 | import retrofit2.http.GET; 7 | 8 | public interface AppApi { 9 | AppApi API = RetrofitManager.create(AppApi.class); 10 | 11 | @GET("app/release") 12 | Observable> getReleaseInfo(); 13 | } 14 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/app/ReleaseInfoBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.app; 2 | 3 | public class ReleaseInfoBean { 4 | private long versionCode; 5 | private String versionName; 6 | private long updateAt; 7 | private String downloadUrl; 8 | private String description; 9 | 10 | public long getVersionCode() { 11 | return versionCode; 12 | } 13 | 14 | public void setVersionCode(long versionCode) { 15 | this.versionCode = versionCode; 16 | } 17 | 18 | public String getVersionName() { 19 | return versionName; 20 | } 21 | 22 | public void setVersionName(String versionName) { 23 | this.versionName = versionName; 24 | } 25 | 26 | public long getUpdateAt() { 27 | return updateAt; 28 | } 29 | 30 | public void setUpdateAt(long updateAt) { 31 | this.updateAt = updateAt; 32 | } 33 | 34 | public String getDownloadUrl() { 35 | return downloadUrl; 36 | } 37 | 38 | public void setDownloadUrl(String downloadUrl) { 39 | this.downloadUrl = downloadUrl; 40 | } 41 | 42 | public String getDescription() { 43 | return description; 44 | } 45 | 46 | public void setDescription(String description) { 47 | this.description = description; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/auth/AuthApi.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.auth; 2 | 3 | import io.reactivex.Observable; 4 | import pro.glideim.sdk.api.Response; 5 | import pro.glideim.sdk.http.RetrofitManager; 6 | import retrofit2.http.Body; 7 | import retrofit2.http.POST; 8 | 9 | public interface AuthApi { 10 | 11 | AuthApi API = RetrofitManager.create(AuthApi.class); 12 | 13 | @POST("auth/register") 14 | Observable> register(@Body RegisterDto d); 15 | 16 | @POST("auth/signin") 17 | Observable> login(@Body LoginDto d); 18 | 19 | @POST("auth/logout") 20 | Observable> logout(); 21 | 22 | @POST("auth/token") 23 | Observable> auth(@Body AuthDto d); 24 | } 25 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/auth/AuthBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.auth; 2 | 3 | import java.util.List; 4 | 5 | public class AuthBean { 6 | private String token; 7 | private int uid; 8 | private List servers; 9 | 10 | public List getServers() { 11 | return servers; 12 | } 13 | 14 | public void setServers(List servers) { 15 | this.servers = servers; 16 | } 17 | 18 | public String getToken() { 19 | return token; 20 | } 21 | 22 | public void setToken(String token) { 23 | this.token = token; 24 | } 25 | 26 | public int getUid() { 27 | return uid; 28 | } 29 | 30 | public void setUid(int uid) { 31 | this.uid = uid; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/auth/AuthDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.auth; 2 | 3 | public class AuthDto { 4 | private String token; 5 | private int device; 6 | 7 | public AuthDto(String token, int device) { 8 | this.token = token; 9 | this.device = device; 10 | } 11 | 12 | public String getToken() { 13 | return token; 14 | } 15 | 16 | public void setToken(String token) { 17 | this.token = token; 18 | } 19 | 20 | public int getDevice() { 21 | return device; 22 | } 23 | 24 | public void setDevice(int device) { 25 | this.device = device; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/auth/LoginDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.auth; 2 | 3 | public class LoginDto { 4 | private String account; 5 | private String password; 6 | private int device; 7 | 8 | public LoginDto(String account, String password, int device) { 9 | this.account = account; 10 | this.password = password; 11 | this.device = device; 12 | } 13 | 14 | public String getAccount() { 15 | return account; 16 | } 17 | 18 | public void setAccount(String account) { 19 | this.account = account; 20 | } 21 | 22 | public String getPassword() { 23 | return password; 24 | } 25 | 26 | public void setPassword(String password) { 27 | this.password = password; 28 | } 29 | 30 | public int getDevice() { 31 | return device; 32 | } 33 | 34 | public void setDevice(int device) { 35 | this.device = device; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/auth/RegisterDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.auth; 2 | 3 | public class RegisterDto { 4 | private String account; 5 | private String password; 6 | 7 | public RegisterDto(String account, String password) { 8 | this.account = account; 9 | this.password = password; 10 | } 11 | 12 | public String getAccount() { 13 | return account; 14 | } 15 | 16 | public void setAccount(String account) { 17 | this.account = account; 18 | } 19 | 20 | public String getPassword() { 21 | return password; 22 | } 23 | 24 | public void setPassword(String password) { 25 | this.password = password; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/AddGroupMemberDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | import java.util.List; 4 | 5 | public class AddGroupMemberDto { 6 | private long gid; 7 | private List uid; 8 | 9 | public AddGroupMemberDto(long gid, List uid) { 10 | this.gid = gid; 11 | this.uid = uid; 12 | } 13 | 14 | public long getGid() { 15 | return gid; 16 | } 17 | 18 | public void setGid(long gid) { 19 | this.gid = gid; 20 | } 21 | 22 | public List getUid() { 23 | return uid; 24 | } 25 | 26 | public void setUid(List uid) { 27 | this.uid = uid; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/CreateGroupBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | public class CreateGroupBean { 4 | private long gid; 5 | 6 | public long getGid() { 7 | return gid; 8 | } 9 | 10 | public void setGid(long gid) { 11 | this.gid = gid; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/CreateGroupDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | public class CreateGroupDto { 4 | private String name; 5 | 6 | public CreateGroupDto(String name) { 7 | this.name = name; 8 | } 9 | 10 | public String getName() { 11 | return name; 12 | } 13 | 14 | public void setName(String name) { 15 | this.name = name; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/GetGroupInfoDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | import java.util.List; 4 | 5 | public class GetGroupInfoDto { 6 | private List gid; 7 | 8 | public GetGroupInfoDto(List gid) { 9 | this.gid = gid; 10 | } 11 | 12 | public List getGid() { 13 | return gid; 14 | } 15 | 16 | public void setGid(List gid) { 17 | this.gid = gid; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/GetGroupMemberDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | public class GetGroupMemberDto { 4 | private long gid; 5 | 6 | public GetGroupMemberDto(long gid) { 7 | this.gid = gid; 8 | } 9 | 10 | public long getGid() { 11 | return gid; 12 | } 13 | 14 | public void setGid(long gid) { 15 | this.gid = gid; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/GroupApi.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | import java.util.List; 4 | 5 | import io.reactivex.Observable; 6 | import pro.glideim.sdk.api.Response; 7 | import pro.glideim.sdk.http.RetrofitManager; 8 | import retrofit2.http.Body; 9 | import retrofit2.http.POST; 10 | 11 | public interface GroupApi { 12 | 13 | GroupApi API = RetrofitManager.create(GroupApi.class); 14 | 15 | @POST("group/info") 16 | Observable>> getGroupInfo(@Body GetGroupInfoDto d); 17 | 18 | @POST("group/members") 19 | Observable>> getGroupMember(@Body GetGroupMemberDto d); 20 | 21 | @POST("group/members/invite") 22 | Observable> inviteMember(@Body AddGroupMemberDto d); 23 | 24 | @POST("group/members/remove") 25 | Observable> removeMember(@Body RemoveMemberDto d); 26 | 27 | @POST("group/create") 28 | Observable> createGroup(@Body CreateGroupDto d); 29 | 30 | @POST("group/join") 31 | Observable> joinGroup(@Body JoinGroupDto d); 32 | } 33 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/GroupInfoBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | public class GroupInfoBean { 4 | private String name; 5 | private Long gid; 6 | private String avatar; 7 | 8 | public String getName() { 9 | return name; 10 | } 11 | 12 | public void setName(String name) { 13 | this.name = name; 14 | } 15 | 16 | public Long getGid() { 17 | return gid; 18 | } 19 | 20 | public void setGid(Long gid) { 21 | this.gid = gid; 22 | } 23 | 24 | public String getAvatar() { 25 | return avatar; 26 | } 27 | 28 | public void setAvatar(String avatar) { 29 | this.avatar = avatar; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/GroupMemberBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | public class GroupMemberBean { 4 | private long uid; 5 | private int type; 6 | private String remarkName; 7 | 8 | public long getUid() { 9 | return uid; 10 | } 11 | 12 | public void setUid(long uid) { 13 | this.uid = uid; 14 | } 15 | 16 | public int getType() { 17 | return type; 18 | } 19 | 20 | public void setType(int type) { 21 | this.type = type; 22 | } 23 | 24 | public String getRemarkName() { 25 | return remarkName; 26 | } 27 | 28 | public void setRemarkName(String remarkName) { 29 | this.remarkName = remarkName; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/JoinGroupDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | public class JoinGroupDto { 4 | private Long gid; 5 | 6 | public JoinGroupDto(Long gid) { 7 | this.gid = gid; 8 | } 9 | 10 | public Long getGid() { 11 | return gid; 12 | } 13 | 14 | public void setGid(Long gid) { 15 | this.gid = gid; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/group/RemoveMemberDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.group; 2 | 3 | import java.util.List; 4 | 5 | public class RemoveMemberDto { 6 | private long gid; 7 | private List uid; 8 | 9 | public RemoveMemberDto(long gid, List uid) { 10 | this.gid = gid; 11 | this.uid = uid; 12 | } 13 | 14 | public long getGid() { 15 | return gid; 16 | } 17 | 18 | public void setGid(long gid) { 19 | this.gid = gid; 20 | } 21 | 22 | public List getUid() { 23 | return uid; 24 | } 25 | 26 | public void setUid(List uid) { 27 | this.uid = uid; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/AckOfflineMsgDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | import java.util.List; 4 | 5 | public class AckOfflineMsgDto { 6 | private List mid; 7 | 8 | public AckOfflineMsgDto(List mid) { 9 | this.mid = mid; 10 | } 11 | 12 | public List getMid() { 13 | return mid; 14 | } 15 | 16 | public void setMid(List mid) { 17 | this.mid = mid; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/GetChatHistoryDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | public class GetChatHistoryDto { 4 | private long uid; 5 | private long beforeMid; 6 | 7 | public GetChatHistoryDto(long uid, long beforeMid) { 8 | this.uid = uid; 9 | this.beforeMid = beforeMid; 10 | } 11 | 12 | public long getUid() { 13 | return uid; 14 | } 15 | 16 | public void setUid(long uid) { 17 | this.uid = uid; 18 | } 19 | 20 | public long getBeforeMid() { 21 | return beforeMid; 22 | } 23 | 24 | public void setBeforeMid(long beforeMid) { 25 | this.beforeMid = beforeMid; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/GetGroupMessageStateDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | public class GetGroupMessageStateDto { 4 | private Long gid; 5 | 6 | 7 | public GetGroupMessageStateDto(Long gid) { 8 | this.gid = gid; 9 | } 10 | 11 | public Long getGid() { 12 | return gid; 13 | } 14 | 15 | public void setGid(Long gid) { 16 | this.gid = gid; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/GetGroupMsgHistoryDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | public class GetGroupMsgHistoryDto { 4 | private long gid; 5 | private long beforeSeq; 6 | 7 | public GetGroupMsgHistoryDto(long gid) { 8 | this.gid = gid; 9 | } 10 | 11 | public GetGroupMsgHistoryDto(long gid, long beforeSeq) { 12 | this.gid = gid; 13 | this.beforeSeq = beforeSeq; 14 | } 15 | 16 | public long getGid() { 17 | return gid; 18 | } 19 | 20 | public void setGid(long gid) { 21 | this.gid = gid; 22 | } 23 | 24 | public long getBeforeSeq() { 25 | return beforeSeq; 26 | } 27 | 28 | public void setBeforeSeq(long beforeSeq) { 29 | this.beforeSeq = beforeSeq; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/GetSessionDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | public class GetSessionDto { 4 | private long to; 5 | 6 | public GetSessionDto(long to) { 7 | this.to = to; 8 | } 9 | 10 | public long getTo() { 11 | return to; 12 | } 13 | 14 | public void setTo(long to) { 15 | this.to = to; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/GetUserMsgDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | import java.util.List; 4 | 5 | public class GetUserMsgDto { 6 | private List uid; 7 | 8 | public GetUserMsgDto(List uid) { 9 | this.uid = uid; 10 | } 11 | 12 | public List getUid() { 13 | return uid; 14 | } 15 | 16 | public void setUid(List uid) { 17 | this.uid = uid; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/GroupMessageBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | public class GroupMessageBean { 4 | 5 | private long mid; 6 | private long sender; 7 | private long gid; 8 | private int type; 9 | private long seq; 10 | private long sendAt; 11 | private String content; 12 | private int status; 13 | private long recallBy; 14 | 15 | public long getRecallBy() { 16 | return recallBy; 17 | } 18 | 19 | public void setRecallBy(long recallBy) { 20 | this.recallBy = recallBy; 21 | } 22 | 23 | public int getStatus() { 24 | return status; 25 | } 26 | 27 | public void setStatus(int status) { 28 | this.status = status; 29 | } 30 | 31 | public long getSeq() { 32 | return seq; 33 | } 34 | 35 | public void setSeq(long seq) { 36 | this.seq = seq; 37 | } 38 | 39 | public long getMid() { 40 | return mid; 41 | } 42 | 43 | public void setMid(long mid) { 44 | this.mid = mid; 45 | } 46 | 47 | public long getSender() { 48 | return sender; 49 | } 50 | 51 | public void setSender(long sender) { 52 | this.sender = sender; 53 | } 54 | 55 | public long getGid() { 56 | return gid; 57 | } 58 | 59 | public void setGid(long gid) { 60 | this.gid = gid; 61 | } 62 | 63 | public int getType() { 64 | return type; 65 | } 66 | 67 | public void setType(int type) { 68 | this.type = type; 69 | } 70 | 71 | public long getSendAt() { 72 | return sendAt; 73 | } 74 | 75 | public void setSendAt(long sendAt) { 76 | this.sendAt = sendAt; 77 | } 78 | 79 | public String getContent() { 80 | return content; 81 | } 82 | 83 | public void setContent(String content) { 84 | this.content = content; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/GroupMessageStateBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | public class GroupMessageStateBean { 4 | private Long gid; 5 | private long lastMID; 6 | private long lastSeq; 7 | private long lastMsgAt; 8 | 9 | public Long getGid() { 10 | return gid; 11 | } 12 | 13 | public void setGid(Long gid) { 14 | this.gid = gid; 15 | } 16 | 17 | public long getLastMID() { 18 | return lastMID; 19 | } 20 | 21 | public void setLastMID(long lastMID) { 22 | this.lastMID = lastMID; 23 | } 24 | 25 | public long getLastSeq() { 26 | return lastSeq; 27 | } 28 | 29 | public void setLastSeq(long lastSeq) { 30 | this.lastSeq = lastSeq; 31 | } 32 | 33 | public long getLastMsgAt() { 34 | return lastMsgAt; 35 | } 36 | 37 | public void setLastMsgAt(long lastMsgAt) { 38 | this.lastMsgAt = lastMsgAt; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/MessageBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | public class MessageBean { 4 | private long mid; 5 | private long cliSeq; 6 | private long from; 7 | private long to; 8 | private int type; 9 | private long sendAt; 10 | private long createAt; 11 | private String content; 12 | private int status; 13 | 14 | public int getStatus() { 15 | return status; 16 | } 17 | 18 | public void setStatus(int status) { 19 | this.status = status; 20 | } 21 | 22 | public long getMid() { 23 | return mid; 24 | } 25 | 26 | public void setMid(long mid) { 27 | this.mid = mid; 28 | } 29 | 30 | public long getCliSeq() { 31 | return cliSeq; 32 | } 33 | 34 | public void setCliSeq(long cliSeq) { 35 | this.cliSeq = cliSeq; 36 | } 37 | 38 | public long getFrom() { 39 | return from; 40 | } 41 | 42 | public void setFrom(long from) { 43 | this.from = from; 44 | } 45 | 46 | public long getTo() { 47 | return to; 48 | } 49 | 50 | public void setTo(long to) { 51 | this.to = to; 52 | } 53 | 54 | public int getType() { 55 | return type; 56 | } 57 | 58 | public void setType(int type) { 59 | this.type = type; 60 | } 61 | 62 | public long getSendAt() { 63 | return sendAt; 64 | } 65 | 66 | public void setSendAt(long sendAt) { 67 | this.sendAt = sendAt; 68 | } 69 | 70 | public long getCreateAt() { 71 | return createAt; 72 | } 73 | 74 | public void setCreateAt(long createAt) { 75 | this.createAt = createAt; 76 | } 77 | 78 | public String getContent() { 79 | return content; 80 | } 81 | 82 | public void setContent(String content) { 83 | this.content = content; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/MessageIDBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | public class MessageIDBean { 4 | private long mid; 5 | 6 | public long getMid() { 7 | return mid; 8 | } 9 | 10 | public void setMid(long mid) { 11 | this.mid = mid; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/MsgApi.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | import java.util.List; 4 | 5 | import io.reactivex.Observable; 6 | import pro.glideim.sdk.api.Response; 7 | import pro.glideim.sdk.http.RetrofitManager; 8 | import retrofit2.http.Body; 9 | import retrofit2.http.POST; 10 | 11 | public interface MsgApi { 12 | 13 | MsgApi API = RetrofitManager.create(MsgApi.class); 14 | 15 | @POST("msg/id") 16 | Observable> getMessageID(); 17 | 18 | @POST("msg/chat/recent") 19 | Observable>> getRecentChatMessage(); 20 | 21 | @POST("msg/chat/user") 22 | Observable>> getChatMessageByUsers(@Body GetUserMsgDto d); 23 | 24 | @POST("msg/chat/history") 25 | Observable>> getChatMessageHistory(@Body GetChatHistoryDto d); 26 | 27 | @POST("msg/group/recent") 28 | Observable>> getRecentGroupMessage(@Body GetGroupMsgHistoryDto d); 29 | 30 | @POST("msg/group/history") 31 | Observable>> getGroupMessageHistory(@Body GetGroupMsgHistoryDto d); 32 | 33 | @POST("msg/group/state") 34 | Observable> getGroupMessageState(@Body GetGroupMessageStateDto d); 35 | 36 | @POST("msg/group/state/all") 37 | Observable>> getAllGroupMessageState(); 38 | 39 | @POST("msg/chat/offline") 40 | Observable>> getOfflineMsg(); 41 | 42 | @POST("msg/chat/offline/ack") 43 | Observable> ackOfflineMsg(@Body AckOfflineMsgDto d); 44 | 45 | @POST("session/recent") 46 | Observable>> getRecentSession(); 47 | 48 | @POST("session/get") 49 | Observable> getSession(@Body GetSessionDto d); 50 | 51 | @POST("session/update") 52 | Observable> updateSession(@Body GetSessionDto d); 53 | } 54 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/SessionBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | public class SessionBean { 4 | private long uid1; 5 | private long uid2; 6 | private long lastMid; 7 | private long updateAt; 8 | private long createAt; 9 | 10 | public long getCreateAt() { 11 | return createAt; 12 | } 13 | 14 | public void setCreateAt(long createAt) { 15 | this.createAt = createAt; 16 | } 17 | 18 | public long getUid1() { 19 | return uid1; 20 | } 21 | 22 | public void setUid1(long uid1) { 23 | this.uid1 = uid1; 24 | } 25 | 26 | public long getUid2() { 27 | return uid2; 28 | } 29 | 30 | public void setUid2(long uid2) { 31 | this.uid2 = uid2; 32 | } 33 | 34 | public long getLastMid() { 35 | return lastMid; 36 | } 37 | 38 | public void setLastMid(long lastMid) { 39 | this.lastMid = lastMid; 40 | } 41 | 42 | public long getUpdateAt() { 43 | return updateAt; 44 | } 45 | 46 | public void setUpdateAt(long updateAt) { 47 | this.updateAt = updateAt; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/msg/UserMsgBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | import java.util.List; 4 | 5 | public class UserMsgBean { 6 | private long uid; 7 | private List messages; 8 | 9 | public long getUid() { 10 | return uid; 11 | } 12 | 13 | public void setUid(long uid) { 14 | this.uid = uid; 15 | } 16 | 17 | public List getMessages() { 18 | return messages; 19 | } 20 | 21 | public void setMessages(List messages) { 22 | this.messages = messages; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/user/ApprovalContactsDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | public class ApprovalContactsDto { 4 | private long uid; 5 | private boolean agree; 6 | private boolean deny; 7 | private String comment; 8 | 9 | public ApprovalContactsDto(long uid, boolean agree, boolean deny, String comment) { 10 | this.uid = uid; 11 | this.agree = agree; 12 | this.deny = deny; 13 | this.comment = comment; 14 | } 15 | 16 | public long getUid() { 17 | return uid; 18 | } 19 | 20 | public void setUid(long uid) { 21 | this.uid = uid; 22 | } 23 | 24 | public boolean isAgree() { 25 | return agree; 26 | } 27 | 28 | public void setAgree(boolean agree) { 29 | this.agree = agree; 30 | } 31 | 32 | public boolean isDeny() { 33 | return deny; 34 | } 35 | 36 | public void setDeny(boolean deny) { 37 | this.deny = deny; 38 | } 39 | 40 | public String getComment() { 41 | return comment; 42 | } 43 | 44 | public void setComment(String comment) { 45 | this.comment = comment; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/user/ContactsBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | public class ContactsBean { 4 | private long id; 5 | private int type; 6 | private String remark; 7 | 8 | public long getId() { 9 | return id; 10 | } 11 | 12 | public void setId(long id) { 13 | this.id = id; 14 | } 15 | 16 | public int getType() { 17 | return type; 18 | } 19 | 20 | public void setType(int type) { 21 | this.type = type; 22 | } 23 | 24 | public String getRemark() { 25 | return remark; 26 | } 27 | 28 | public void setRemark(String remark) { 29 | this.remark = remark; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/user/ContactsUidDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | public class ContactsUidDto { 4 | private long uid; 5 | private String remark; 6 | 7 | public ContactsUidDto(long uid, String remark) { 8 | this.uid = uid; 9 | this.remark = remark; 10 | } 11 | 12 | public long getUid() { 13 | return uid; 14 | } 15 | 16 | public void setUid(long uid) { 17 | this.uid = uid; 18 | } 19 | 20 | public String getRemark() { 21 | return remark; 22 | } 23 | 24 | public void setRemark(String remark) { 25 | this.remark = remark; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/user/GetUserInfoDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | import java.util.List; 4 | 5 | public class GetUserInfoDto { 6 | private List uid; 7 | 8 | public GetUserInfoDto(List uid) { 9 | this.uid = uid; 10 | } 11 | 12 | public List getUid() { 13 | return uid; 14 | } 15 | 16 | public void setUid(List uid) { 17 | this.uid = uid; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/user/ProfileBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | public class ProfileBean { 4 | private long uid; 5 | private String account; 6 | private String nickname; 7 | private String avatar; 8 | 9 | public long getUid() { 10 | return uid; 11 | } 12 | 13 | public void setUid(long uid) { 14 | this.uid = uid; 15 | } 16 | 17 | public String getAccount() { 18 | return account; 19 | } 20 | 21 | public void setAccount(String account) { 22 | this.account = account; 23 | } 24 | 25 | public String getNickname() { 26 | return nickname; 27 | } 28 | 29 | public void setNickname(String nickname) { 30 | this.nickname = nickname; 31 | } 32 | 33 | public String getAvatar() { 34 | return avatar; 35 | } 36 | 37 | public void setAvatar(String avatar) { 38 | this.avatar = avatar; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/user/RegisterDto.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | public class RegisterDto { 4 | private String account; 5 | private String password; 6 | 7 | public RegisterDto(String account, String password) { 8 | this.account = account; 9 | this.password = password; 10 | } 11 | 12 | public String getAccount() { 13 | return account; 14 | } 15 | 16 | public void setAccount(String account) { 17 | this.account = account; 18 | } 19 | 20 | public String getPassword() { 21 | return password; 22 | } 23 | 24 | public void setPassword(String password) { 25 | this.password = password; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/user/TokenBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | public class TokenBean { 4 | private String token; 5 | private int uid; 6 | 7 | public int getUid() { 8 | return uid; 9 | } 10 | 11 | public void setUid(int uid) { 12 | this.uid = uid; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/user/UserApi.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | import io.reactivex.Observable; 4 | import pro.glideim.sdk.api.Response; 5 | import pro.glideim.sdk.http.RetrofitManager; 6 | import retrofit2.http.Body; 7 | import retrofit2.http.POST; 8 | 9 | import java.util.List; 10 | 11 | public interface UserApi { 12 | 13 | UserApi API = RetrofitManager.create(UserApi.class); 14 | 15 | @POST("contacts/list") 16 | Observable>> getContactsList(); 17 | 18 | @POST("contacts/add") 19 | Observable> addContacts(@Body ContactsUidDto d); 20 | 21 | @POST("contacts/del") 22 | Observable> delContacts(@Body ContactsUidDto d); 23 | 24 | @POST("contacts/approval") 25 | Observable> contactsApproval(@Body ApprovalContactsDto d); 26 | 27 | @POST("user/info") 28 | Observable>> getUserInfo(@Body GetUserInfoDto d); 29 | 30 | @POST("user/profile") 31 | Observable> myProfile(); 32 | 33 | @POST("user/profile/update") 34 | Observable> updateMyProfile(); 35 | } 36 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/api/user/UserInfoBean.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | public class UserInfoBean { 4 | private long uid; 5 | private String nickname; 6 | private String account; 7 | private String avatar; 8 | 9 | public long getUid() { 10 | return uid; 11 | } 12 | 13 | public void setUid(long uid) { 14 | this.uid = uid; 15 | } 16 | 17 | public String getNickname() { 18 | return nickname; 19 | } 20 | 21 | public void setNickname(String nickname) { 22 | this.nickname = nickname; 23 | } 24 | 25 | public String getAccount() { 26 | return account; 27 | } 28 | 29 | public void setAccount(String account) { 30 | this.account = account; 31 | } 32 | 33 | public String getAvatar() { 34 | return avatar; 35 | } 36 | 37 | public void setAvatar(String avatar) { 38 | this.avatar = avatar; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/http/AuthInterceptor.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.http; 2 | 3 | import java.io.IOException; 4 | import java.net.ConnectException; 5 | 6 | import okhttp3.Interceptor; 7 | import okhttp3.Request; 8 | import okhttp3.Response; 9 | import pro.glideim.sdk.GlideIM; 10 | 11 | public class AuthInterceptor implements Interceptor { 12 | 13 | private static final AuthInterceptor instance = new AuthInterceptor(); 14 | 15 | public static AuthInterceptor create() { 16 | return instance; 17 | } 18 | 19 | @Override 20 | public Response intercept(Chain chain) throws IOException { 21 | Request.Builder request = chain.request().newBuilder(); 22 | 23 | String jwtToken = GlideIM.getDataStorage().loadToken(GlideIM.getAccount().uid); 24 | request.addHeader("Authorization", "Bearer " + jwtToken); 25 | return chain.proceed(request.build()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/im/ConnStateListener.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.im; 2 | 3 | public interface ConnStateListener { 4 | void onStateChange(int state, String msg); 5 | } 6 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/im/Heartbeat.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.im; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import io.reactivex.Observable; 6 | import io.reactivex.disposables.Disposable; 7 | import pro.glideim.sdk.messages.Actions; 8 | import pro.glideim.sdk.messages.CommMessage; 9 | import pro.glideim.sdk.utils.SLogger; 10 | import pro.glideim.sdk.ws.WsClient; 11 | 12 | public class Heartbeat implements ConnStateListener { 13 | 14 | private static final String TAG = Heartbeat.class.getSimpleName(); 15 | private final pro.glideim.sdk.im.IMClient client; 16 | private Disposable disposable; 17 | 18 | private Heartbeat(pro.glideim.sdk.im.IMClient client) { 19 | this.client = client; 20 | this.client.getWebSocketClient().addStateListener(this); 21 | } 22 | 23 | public static Heartbeat start(pro.glideim.sdk.im.IMClient client) { 24 | Heartbeat heartbeat = new Heartbeat(client); 25 | heartbeat.start(); 26 | return heartbeat; 27 | } 28 | 29 | @Override 30 | public void onStateChange(int state, String msg) { 31 | if (state == WsClient.STATE_OPENED) { 32 | start(); 33 | } else if (state == WsClient.STATE_CLOSED) { 34 | stop(); 35 | } 36 | } 37 | 38 | public void start() { 39 | stop(); 40 | SLogger.d(TAG, "start"); 41 | Observable.interval(3, TimeUnit.SECONDS) 42 | .doOnSubscribe(disposable -> { 43 | stop(); 44 | this.disposable = disposable; 45 | }) 46 | .doOnNext(aLong -> { 47 | if (client.isConnected()) { 48 | client.send(new CommMessage<>(1, Actions.ACTION_HEARTBEAT, 0, "")); 49 | } else { 50 | stop(); 51 | } 52 | }) 53 | .subscribe(); 54 | } 55 | 56 | public boolean isRunning() { 57 | return disposable.isDisposed(); 58 | } 59 | 60 | public void stop() { 61 | if (disposable != null && !disposable.isDisposed()) { 62 | disposable.dispose(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/im/IMClient.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.im; 2 | 3 | import io.reactivex.Observable; 4 | import io.reactivex.Single; 5 | import pro.glideim.sdk.messages.ChatMessage; 6 | import pro.glideim.sdk.messages.CommMessage; 7 | import pro.glideim.sdk.ws.WsClient; 8 | 9 | public interface IMClient { 10 | void addConnStateListener(ConnStateListener connStateListener); 11 | 12 | void removeConnStateListener(ConnStateListener connStateListener); 13 | 14 | void setMessageListener(MessageListener listener); 15 | 16 | Single connect(); 17 | 18 | boolean isConnected(); 19 | 20 | Observable sendChatMessage(ChatMessage m); 21 | 22 | Observable sendMessage(String action, ChatMessage m); 23 | 24 | Observable sendGroupMessage(ChatMessage m); 25 | 26 | Observable> request(String action, Class clazz, boolean isArray, Object data); 27 | 28 | void disconnect(); 29 | 30 | boolean send(Object obj); 31 | 32 | WsClient getWebSocketClient(); 33 | } 34 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/im/Message.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.im; 2 | 3 | public class Message { 4 | String message; 5 | 6 | public Message(String message) { 7 | this.message = message; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/im/MessageListener.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.im; 2 | 3 | import pro.glideim.sdk.messages.ChatMessage; 4 | import pro.glideim.sdk.messages.CommMessage; 5 | import pro.glideim.sdk.messages.GroupMessage; 6 | 7 | public interface MessageListener { 8 | void onNewMessage(ChatMessage m); 9 | void onGroupMessage(GroupMessage m); 10 | void onControlMessage(CommMessage m); 11 | } 12 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/AckMessage.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | public class AckMessage { 4 | private long mid; 5 | 6 | public long getMid() { 7 | return mid; 8 | } 9 | 10 | public void setMid(long mid) { 11 | this.mid = mid; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/AckRequest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | public class AckRequest { 4 | private long mid; 5 | private long from; 6 | private long seq; 7 | 8 | public AckRequest(long mid, long from, long seq) { 9 | this.mid = mid; 10 | this.from = from; 11 | this.seq = seq; 12 | } 13 | 14 | public long getMid() { 15 | return mid; 16 | } 17 | 18 | public void setMid(long mid) { 19 | this.mid = mid; 20 | } 21 | 22 | public long getFrom() { 23 | return from; 24 | } 25 | 26 | public void setFrom(long from) { 27 | this.from = from; 28 | } 29 | 30 | public long getSeq() { 31 | return seq; 32 | } 33 | 34 | public void setSeq(long seq) { 35 | this.seq = seq; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/Actions.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | public interface Actions { 4 | 5 | // control 6 | String ACTION_HEARTBEAT = "heartbeat"; 7 | 8 | interface Srv { 9 | String ACTION_ACK_MESSAGE = "ack.message"; 10 | String ACTION_ACK_NOTIFY = "ack.notify"; 11 | String ACTION_API_SUCCESS = "api.success"; 12 | 13 | String ACTION_NOTIFY_NEED_AUTH = "notify.auth"; 14 | String ACTION_NEW_CONTACT = "notify.contact"; 15 | String ACTION_KICK_OUT = "notify.kickout"; 16 | String ACTION_NOTIFY_ERROR = "notify.error"; 17 | String ACTION_NOTIFY_GROUP = "notify.group"; 18 | String ACTION_NOTIFY_LOGIN = "notify.login"; 19 | String ACTION_NOTIFY_LOGOUT = "notify.logout"; 20 | 21 | String ACTION_MESSAGE_CHAT = "message.chat"; 22 | String ACTION_MESSAGE_GROUP = "message.group"; 23 | String ACTION_MESSAGE_FAILED = "message.failed.send"; 24 | String ACTION_MESSAGE_CHAT_RECALL = "message.chat.recall"; 25 | String ACTION_MESSAGE_GROUP_RECALL = "message.group.recall"; 26 | } 27 | 28 | interface Cli { 29 | String ACTION_ACK_REQUEST = "ack.request"; 30 | String ACTION_API_USER_AUTH = "api.user.auth"; 31 | String ACTION_API_LOGOUT = "api.user.logout"; 32 | String ACTION_ACK_GROUP_MSG = "ack.group.msg"; 33 | String ACTION_MESSAGE_CHAT_RETRY = "message.chat.retry"; 34 | String ACTION_MESSAGE_CHAT_RESEND = "message.chat.resend"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/ChatMessage.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | public class ChatMessage { 4 | 5 | public static final int STATE_INIT = -1; 6 | public static final int STATE_CREATED = 1; 7 | public static final int STATE_SRV_SENDING = 2; 8 | public static final int STATE_RCV_SENDING = 3; 9 | public static final int STATE_SRV_RECEIVED = 4; 10 | public static final int STATE_RCV_RECEIVED = 5; 11 | public static final int STATE_SRV_FAILED = 6; 12 | public static final int STATE_RCV_FAILED = 7; 13 | 14 | public static final int STATE_UPDATED = 1000; 15 | 16 | private long mid; 17 | private long cSeq; 18 | private long from; 19 | private long to; 20 | private int type; 21 | private String content; 22 | private long cTime; 23 | private int status; 24 | 25 | private transient int state; 26 | 27 | public int getState() { 28 | return state; 29 | } 30 | 31 | public ChatMessage setState(int state) { 32 | this.state = state; 33 | return this; 34 | } 35 | 36 | public int getStatus() { 37 | return status; 38 | } 39 | 40 | public void setStatus(int status) { 41 | this.status = status; 42 | } 43 | 44 | public long getFrom() { 45 | return from; 46 | } 47 | 48 | public void setFrom(long from) { 49 | this.from = from; 50 | } 51 | 52 | public long getMid() { 53 | return mid; 54 | } 55 | 56 | public void setMid(long mid) { 57 | this.mid = mid; 58 | } 59 | 60 | public long getcSeq() { 61 | return cSeq; 62 | } 63 | 64 | public void setcSeq(long cSeq) { 65 | this.cSeq = cSeq; 66 | } 67 | 68 | public long getTo() { 69 | return to; 70 | } 71 | 72 | public void setTo(long to) { 73 | this.to = to; 74 | } 75 | 76 | public int getType() { 77 | return type; 78 | } 79 | 80 | public void setType(int type) { 81 | this.type = type; 82 | } 83 | 84 | public String getContent() { 85 | return content; 86 | } 87 | 88 | public void setContent(String content) { 89 | this.content = content; 90 | } 91 | 92 | public long getcTime() { 93 | return cTime; 94 | } 95 | 96 | public void setcTime(long cTime) { 97 | this.cTime = cTime; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/CommMessage.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | import java.lang.reflect.Type; 4 | 5 | import pro.glideim.sdk.http.RetrofitManager; 6 | 7 | public class CommMessage { 8 | private int ver; 9 | private String action; 10 | private long seq; 11 | private T data; 12 | private String origin; 13 | 14 | public CommMessage(int ver, String action, long seq, T data) { 15 | this.ver = ver; 16 | this.action = action; 17 | this.seq = seq; 18 | this.data = data; 19 | } 20 | 21 | public CommMessage deserialize(Type t) { 22 | if (origin.isEmpty()) { 23 | throw new IllegalStateException("the common message origin data is empty"); 24 | } 25 | return RetrofitManager.fromJson(t, origin); 26 | } 27 | 28 | public void setOrigin(String origin) { 29 | this.origin = origin; 30 | } 31 | 32 | public boolean success() { 33 | return action.equals(Actions.Srv.ACTION_API_SUCCESS); 34 | } 35 | 36 | public int getVer() { 37 | return ver; 38 | } 39 | 40 | public void setVer(int ver) { 41 | this.ver = ver; 42 | } 43 | 44 | public String getAction() { 45 | return action; 46 | } 47 | 48 | public void setAction(String action) { 49 | this.action = action; 50 | } 51 | 52 | public long getSeq() { 53 | return seq; 54 | } 55 | 56 | public void setSeq(long seq) { 57 | this.seq = seq; 58 | } 59 | 60 | public T getData() { 61 | return data; 62 | } 63 | 64 | public void setData(T data) { 65 | this.data = data; 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return "CommMessage{" + 71 | "ver=" + ver + 72 | ", action='" + action + '\'' + 73 | ", seq=" + seq + 74 | ", data=" + data + 75 | '}'; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/GroupMessage.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | public class GroupMessage { 4 | 5 | private long mid; 6 | private long from; 7 | private long to; 8 | private long seq; 9 | private int type; 10 | private String content; 11 | private long sendAt; 12 | private int status; 13 | 14 | public int getStatus() { 15 | return status; 16 | } 17 | 18 | public void setStatus(int status) { 19 | this.status = status; 20 | } 21 | 22 | public long getMid() { 23 | return mid; 24 | } 25 | 26 | public void setMid(long mid) { 27 | this.mid = mid; 28 | } 29 | 30 | public long getFrom() { 31 | return from; 32 | } 33 | 34 | public void setFrom(long from) { 35 | this.from = from; 36 | } 37 | 38 | public long getTo() { 39 | return to; 40 | } 41 | 42 | public void setTo(long to) { 43 | this.to = to; 44 | } 45 | 46 | public long getSeq() { 47 | return seq; 48 | } 49 | 50 | public void setSeq(long seq) { 51 | this.seq = seq; 52 | } 53 | 54 | public int getType() { 55 | return type; 56 | } 57 | 58 | public void setType(int type) { 59 | this.type = type; 60 | } 61 | 62 | public String getContent() { 63 | return content; 64 | } 65 | 66 | public void setContent(String content) { 67 | this.content = content; 68 | } 69 | 70 | public long getSendAt() { 71 | return sendAt; 72 | } 73 | 74 | public void setSendAt(long sendAt) { 75 | this.sendAt = sendAt; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/GroupNotify.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | public class GroupNotify { 4 | 5 | public static final int TYPE_MEMBER_ADDED = 1; 6 | public static final int TYPE_MEMBER_REMOVED = 2; 7 | 8 | private long mid; 9 | private long gid; 10 | private long type; 11 | private long timestamp; 12 | private long seq; 13 | private T data; 14 | 15 | public long getMid() { 16 | return mid; 17 | } 18 | 19 | public void setMid(long mid) { 20 | this.mid = mid; 21 | } 22 | 23 | public long getTimestamp() { 24 | return timestamp; 25 | } 26 | 27 | public void setTimestamp(long timestamp) { 28 | this.timestamp = timestamp; 29 | } 30 | 31 | public long getSeq() { 32 | return seq; 33 | } 34 | 35 | public void setSeq(long seq) { 36 | this.seq = seq; 37 | } 38 | 39 | public long getGid() { 40 | return gid; 41 | } 42 | 43 | public void setGid(long gid) { 44 | this.gid = gid; 45 | } 46 | 47 | public long getType() { 48 | return type; 49 | } 50 | 51 | public void setType(long type) { 52 | this.type = type; 53 | } 54 | 55 | public T getData() { 56 | return data; 57 | } 58 | 59 | public void setData(T data) { 60 | this.data = data; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/GroupNotifyMemberChanges.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | import java.util.List; 4 | 5 | public class GroupNotifyMemberChanges { 6 | private List uid; 7 | 8 | public List getUid() { 9 | return uid; 10 | } 11 | 12 | public void setUid(List uid) { 13 | this.uid = uid; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/GroupNotifyMemberRemoved.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | import java.util.List; 4 | 5 | public class GroupNotifyMemberRemoved { 6 | private List uid; 7 | 8 | public List getUid() { 9 | return uid; 10 | } 11 | 12 | public void setUid(List uid) { 13 | this.uid = uid; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/messages/RecallMessage.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.messages; 2 | 3 | public class RecallMessage { 4 | private long reCallBy; 5 | private long mid; 6 | 7 | public RecallMessage(long reCallBy, long mid) { 8 | this.reCallBy = reCallBy; 9 | this.mid = mid; 10 | } 11 | 12 | public long getMid() { 13 | return mid; 14 | } 15 | 16 | public void setMid(long mid) { 17 | this.mid = mid; 18 | } 19 | 20 | public long getReCallBy() { 21 | return reCallBy; 22 | } 23 | 24 | public void setReCallBy(long reCallBy) { 25 | this.reCallBy = reCallBy; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/push/NewContactsMessage.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.push; 2 | 3 | public class NewContactsMessage { 4 | private long id; 5 | private int type; 6 | private long from; 7 | private int fromType; 8 | 9 | 10 | public int getFromType() { 11 | return fromType; 12 | } 13 | 14 | public void setFromType(int fromType) { 15 | this.fromType = fromType; 16 | } 17 | 18 | public long getFrom() { 19 | return from; 20 | } 21 | 22 | public void setFrom(long from) { 23 | this.from = from; 24 | } 25 | 26 | public long getId() { 27 | return id; 28 | } 29 | 30 | public void setId(long id) { 31 | this.id = id; 32 | } 33 | 34 | public int getType() { 35 | return type; 36 | } 37 | 38 | public void setType(int type) { 39 | this.type = type; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/utils/RxUtils.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.utils; 2 | 3 | import io.reactivex.ObservableTransformer; 4 | import io.reactivex.SingleTransformer; 5 | import io.reactivex.functions.Function; 6 | import io.reactivex.schedulers.Schedulers; 7 | import pro.glideim.sdk.GlideException; 8 | import pro.glideim.sdk.api.Response; 9 | import pro.glideim.sdk.messages.CommMessage; 10 | 11 | public class RxUtils { 12 | public static ObservableTransformer silentScheduler() { 13 | return upstream -> upstream.subscribeOn(Schedulers.io()).observeOn(Schedulers.newThread()); 14 | } 15 | 16 | public static Function, T> bodyConverter() { 17 | return r -> { 18 | if (!r.success()) { 19 | throw new GlideException(r.getCode() + "," + r.getMsg()); 20 | } 21 | return r.getData(); 22 | }; 23 | } 24 | 25 | public static SingleTransformer silentSchedulerSingle() { 26 | return upstream -> upstream.subscribeOn(Schedulers.io()).observeOn(Schedulers.newThread()); 27 | } 28 | 29 | public static Function, T> bodyConverterForWsMsg() { 30 | return r -> { 31 | if (!r.success()) { 32 | throw new GlideException(r.getData().toString()); 33 | } 34 | return r.getData(); 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/utils/SLogger.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.utils; 2 | 3 | import pro.glideim.sdk.GlideException; 4 | import pro.glideim.sdk.Logger; 5 | 6 | public class SLogger { 7 | 8 | private static pro.glideim.sdk.Logger l = new pro.glideim.sdk.Logger() { 9 | @Override 10 | public void d(String tag, String log) { 11 | System.out.println("GlideIMSdk:" + tag + ": " + log); 12 | } 13 | 14 | @Override 15 | public void e(String tag, Throwable t) { 16 | System.err.println("GlideIMSdk:" + tag + ": " + t.getMessage()); 17 | t.printStackTrace(); 18 | } 19 | }; 20 | 21 | public static void setLogger(Logger logger){ 22 | l = logger; 23 | } 24 | 25 | private SLogger() { 26 | } 27 | 28 | public static pro.glideim.sdk.Logger getLogger() { 29 | return l; 30 | } 31 | 32 | public static void d(String tag, String log) { 33 | l.d(tag, log); 34 | } 35 | 36 | public static void e(String tag, Throwable t) { 37 | l.e(tag, t); 38 | } 39 | 40 | public static void e(String tag, String log) { 41 | l.e(tag, new GlideException(log)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/ws/HeartbeatHandler.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.ws; 2 | 3 | import io.netty.channel.ChannelHandler; 4 | import io.netty.channel.ChannelHandlerContext; 5 | 6 | public class HeartbeatHandler implements ChannelHandler { 7 | @Override 8 | public void handlerAdded(ChannelHandlerContext ctx) throws Exception { 9 | 10 | } 11 | 12 | @Override 13 | public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { 14 | 15 | } 16 | 17 | @Override 18 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/ws/MessageListener.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.ws; 2 | 3 | public interface MessageListener { 4 | void onNewMessage(String msg); 5 | } 6 | -------------------------------------------------------------------------------- /glide-im-sdk/src/main/java/pro/glideim/sdk/ws/WsClient.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.ws; 2 | 3 | import io.reactivex.Single; 4 | import pro.glideim.sdk.im.ConnStateListener; 5 | 6 | public interface WsClient { 7 | 8 | int STATE_CLOSED = 1; 9 | int STATE_OPENED = 2; 10 | int STATE_CONNECTING = 3; 11 | 12 | Single connect(); 13 | 14 | void disconnect(); 15 | 16 | boolean isConnected(); 17 | 18 | int getState(); 19 | 20 | boolean write(Object msg); 21 | 22 | void addStateListener(ConnStateListener listener); 23 | 24 | void removeStateListener(ConnStateListener listener); 25 | 26 | void setMessageListener(MessageListener listener); 27 | } 28 | -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/GlideIMTest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import org.junit.jupiter.api.AfterEach; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | import pro.glideim.sdk.api.group.CreateGroupBean; 13 | import pro.glideim.sdk.api.user.UserInfoBean; 14 | 15 | class GlideIMTest { 16 | 17 | @BeforeEach 18 | void setUp() throws InterruptedException { 19 | GlideIM.init("http://192.168.1.123:8081/api/"); 20 | GlideIM.getAccount().getIMClient().connect().blockingGet(); 21 | } 22 | 23 | @AfterEach 24 | void tearDown() { 25 | } 26 | 27 | 28 | @Test 29 | void login() { 30 | GlideIM.login("abc", "abc", 1) 31 | .subscribe(new TestObserver<>()); 32 | } 33 | 34 | @Test 35 | void createGroup() { 36 | GlideIM.createGroup("HelloGroup") 37 | .subscribe(new TestResObserver() { 38 | @Override 39 | public void onNext(@NonNull CreateGroupBean createGroupBean) { 40 | System.out.println("createGroup.onNext: " + createGroupBean.getGid()); 41 | } 42 | }); 43 | } 44 | 45 | @Test 46 | public void getUserInfo() { 47 | GlideIM.getUserInfo(Arrays.asList(543602L, 543603L)) 48 | .subscribe(new TestResObserver>() { 49 | @Override 50 | public void onNext(@NonNull List userInfoBeans) { 51 | 52 | for (UserInfoBean datum : userInfoBeans) { 53 | System.out.println(datum.getNickname()); 54 | } 55 | } 56 | }); 57 | } 58 | } -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/IMClientTest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import io.reactivex.Observable; 4 | import io.reactivex.Observer; 5 | import io.reactivex.disposables.Disposable; 6 | import io.reactivex.schedulers.Schedulers; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.junit.jupiter.api.AfterEach; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import pro.glideim.sdk.api.auth.LoginDto; 12 | import pro.glideim.sdk.api.auth.AuthBean; 13 | import pro.glideim.sdk.http.RetrofitManager; 14 | import pro.glideim.sdk.messages.ChatMessage; 15 | import pro.glideim.sdk.messages.CommMessage; 16 | import pro.glideim.sdk.im.IMClientImpl; 17 | 18 | class IMClientTest { 19 | 20 | IMClientImpl imClient = IMClientImpl.create("ws://localhost:8080/ws"); 21 | 22 | @BeforeEach 23 | void setUp() throws InterruptedException { 24 | RetrofitManager.init("http://localhost/api/"); 25 | Boolean aBoolean = imClient.connect().blockingGet(); 26 | Thread.sleep(1000); 27 | } 28 | 29 | @AfterEach 30 | void down() { 31 | imClient.disconnect(); 32 | } 33 | 34 | @Test 35 | void connect() throws InterruptedException { 36 | LoginDto d = new LoginDto("abc", "abc", 1); 37 | Observable> ob = imClient.request("api.user.login", AuthBean.class, false, d); 38 | ob.observeOn(Schedulers.single()) 39 | .subscribe(new Observer>() { 40 | @Override 41 | public void onSubscribe(@NotNull Disposable d) { 42 | System.out.println("IMClientTest.onSubscribe"); 43 | } 44 | 45 | @Override 46 | public void onNext(@NotNull CommMessage tokenBean) { 47 | System.out.println("IMClientTest.onNext\t" + tokenBean); 48 | } 49 | 50 | @Override 51 | public void onError(@NotNull Throwable e) { 52 | System.out.println("IMClientTest.onError: " + e.getMessage()); 53 | } 54 | 55 | @Override 56 | public void onComplete() { 57 | System.out.println("IMClientTest.onComplete"); 58 | } 59 | }); 60 | Thread.sleep(5000); 61 | } 62 | 63 | @Test 64 | void sendChatMessage() throws InterruptedException { 65 | ChatMessage c = new ChatMessage(); 66 | c.setTo(543619); 67 | c.setcSeq(1); 68 | c.setContent("hello"); 69 | c.setType(1); 70 | c.setMid(12343); 71 | c.setcTime(System.currentTimeMillis()); 72 | Observable o = imClient.sendChatMessage(c); 73 | o.subscribe(new TestObserver<>()); 74 | Thread.sleep(4000); 75 | } 76 | 77 | @Test 78 | void send() { 79 | 80 | } 81 | } -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/MockUserTest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.junit.jupiter.api.AfterEach; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import io.reactivex.Observable; 9 | import io.reactivex.Observer; 10 | import io.reactivex.disposables.Disposable; 11 | import pro.glideim.sdk.api.auth.AuthApi; 12 | import pro.glideim.sdk.api.auth.AuthBean; 13 | import pro.glideim.sdk.api.auth.LoginDto; 14 | import pro.glideim.sdk.api.auth.RegisterDto; 15 | import pro.glideim.sdk.http.RetrofitManager; 16 | import pro.glideim.sdk.im.IMClientImpl; 17 | import pro.glideim.sdk.messages.ChatMessage; 18 | import pro.glideim.sdk.messages.CommMessage; 19 | 20 | public class MockUserTest { 21 | 22 | IMClientImpl imClient = IMClientImpl.create("ws://localhost:8080/ws"); 23 | 24 | @BeforeEach 25 | void setup() throws InterruptedException { 26 | 27 | RetrofitManager.init("http://localhost:8081/api/"); 28 | imClient.connect().blockingGet(); 29 | // imClient.setMessageListener(m -> { 30 | // System.out.println("On Receive Message ===>>> " + RetrofitManager.toJson(m)); 31 | // }); 32 | 33 | Thread.sleep(1000); 34 | } 35 | 36 | @AfterEach 37 | void setdown() { 38 | imClient.disconnect(); 39 | } 40 | 41 | @Test 42 | void register() { 43 | AuthApi.API.register(new RegisterDto("aaa", "aaa")).subscribe(new TestObserver<>()); 44 | } 45 | 46 | @Test 47 | void login() throws InterruptedException { 48 | LoginDto d = new LoginDto("aaa", "aaa", 1); 49 | Observable> request = imClient.request("api.user.login", AuthBean.class, false, d); 50 | request.subscribe(new TestObserver<>()); 51 | 52 | Thread.sleep(1000); 53 | ChatMessage c = new ChatMessage(); 54 | c.setTo(5436191); 55 | c.setcSeq(1); 56 | c.setContent("hello"); 57 | c.setType(1); 58 | c.setMid(123431); 59 | c.setcTime(System.currentTimeMillis()); 60 | Observable o = imClient.sendChatMessage(c); 61 | o.subscribe(new Observer() { 62 | @Override 63 | public void onSubscribe(@NotNull Disposable d) { 64 | 65 | } 66 | 67 | @Override 68 | public void onNext(@NotNull ChatMessage message) { 69 | System.out.println("send.onNext:" + message.getState()); 70 | } 71 | 72 | @Override 73 | public void onError(@NotNull Throwable e) { 74 | System.out.println("send.onError: " + e.getMessage()); 75 | } 76 | 77 | @Override 78 | public void onComplete() { 79 | 80 | } 81 | }); 82 | 83 | Thread.sleep(60000); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/TestObserver.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import io.reactivex.Observer; 6 | import io.reactivex.SingleObserver; 7 | import io.reactivex.disposables.Disposable; 8 | import org.jetbrains.annotations.NotNull; 9 | import pro.glideim.sdk.http.RetrofitManager; 10 | 11 | public class TestObserver implements Observer , SingleObserver { 12 | @Override 13 | public void onSubscribe(@NotNull Disposable d) { 14 | System.out.println("TestObserver.onSubscribe"); 15 | } 16 | 17 | @Override 18 | public void onSuccess(@NonNull T t) { 19 | System.out.println("TestObserver.onSuccess"); 20 | System.out.println(RetrofitManager.toJson(t)); 21 | } 22 | 23 | @Override 24 | public void onNext(@NotNull T t) { 25 | System.out.println("TestObserver.onNext"); 26 | System.out.println(RetrofitManager.toJson(t)); 27 | } 28 | 29 | @Override 30 | public void onError(@NotNull Throwable e) { 31 | System.out.println("TestObserver.onError"); 32 | e.printStackTrace(); 33 | } 34 | 35 | @Override 36 | public void onComplete() { 37 | System.out.println("TestObserver.onComplete"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/TestResObserver.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import io.reactivex.Observer; 8 | import io.reactivex.SingleObserver; 9 | import io.reactivex.disposables.Disposable; 10 | 11 | public abstract class TestResObserver implements Observer, SingleObserver { 12 | @Override 13 | public void onSuccess(@NonNull T t) { 14 | onNext(t); 15 | } 16 | 17 | @Override 18 | public void onSubscribe(@NotNull Disposable d) { 19 | System.out.println("TestResObserver.onSubscribe"); 20 | } 21 | 22 | @Override 23 | public void onError(@NotNull Throwable e) { 24 | System.out.println("TestResObserver.onError"); 25 | e.printStackTrace(); 26 | } 27 | 28 | 29 | @Override 30 | public void onComplete() { 31 | System.out.println("TestResObserver.onComplete"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/api/app/AppApiTest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.app; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import pro.glideim.sdk.DefaultDataStoreImpl; 7 | import pro.glideim.sdk.GlideIM; 8 | import pro.glideim.sdk.TestResObserver; 9 | import pro.glideim.sdk.api.Response; 10 | import pro.glideim.sdk.http.RetrofitManager; 11 | 12 | class AppApiTest { 13 | 14 | 15 | @BeforeEach 16 | void tearDown() { 17 | RetrofitManager.init("http://localhost:8081/api/"); 18 | GlideIM.init("http://localhost:8081/api/"); 19 | GlideIM.getInstance().setDataStorage(new DefaultDataStoreImpl()); 20 | } 21 | 22 | @Test 23 | void getReleaseInfo() { 24 | AppApi.API.getReleaseInfo() 25 | .subscribe(new TestResObserver>() { 26 | @Override 27 | public void onNext(Response releaseInfoBeanResponse) { 28 | System.out.println(RetrofitManager.toJson(releaseInfoBeanResponse.getData())); 29 | } 30 | }); 31 | } 32 | } -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/api/auth/AuthApiTest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.auth; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | import pro.glideim.sdk.TestObserver; 6 | import pro.glideim.sdk.http.RetrofitManager; 7 | 8 | class AuthApiTest { 9 | 10 | @BeforeEach 11 | void tearDown() { 12 | RetrofitManager.init("http://localhost:8081/api/"); 13 | } 14 | 15 | @Test 16 | void register() { 17 | RegisterDto d = new RegisterDto("love2", "password"); 18 | AuthApi.API.register(d).subscribe(new TestObserver<>()); 19 | } 20 | 21 | @Test 22 | void login() { 23 | LoginDto d = new LoginDto("love2","password", 1); 24 | AuthApi.API.login(d).subscribe(new TestObserver<>()); 25 | } 26 | 27 | @Test 28 | void logout() { 29 | AuthApi.API.logout().subscribe(new TestObserver<>()); 30 | } 31 | } -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/api/msg/MsgApiTest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.msg; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import pro.glideim.sdk.IMMessage; 9 | import pro.glideim.sdk.TestObserver; 10 | import pro.glideim.sdk.http.RetrofitManager; 11 | import pro.glideim.sdk.utils.RxUtils; 12 | 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | class MsgApiTest { 17 | 18 | @BeforeEach 19 | void setUp() { 20 | RetrofitManager.init("http://localhost:8081/api/"); 21 | } 22 | 23 | @Test 24 | void recentMsg() { 25 | MsgApi.API.getChatMessageByUsers(new GetUserMsgDto(Arrays.asList(1, 2, 3, 4, 5, 6))).subscribe(new TestObserver<>()); 26 | } 27 | 28 | @Test 29 | void history() { 30 | MsgApi.API.getChatMessageHistory(new GetChatHistoryDto(2,0)) 31 | .map(RxUtils.bodyConverter()) 32 | .subscribe(new TestObserver>(){ 33 | @Override 34 | public void onNext(@NonNull List messageBeans) { 35 | System.out.println("history.onNext:"+messageBeans.toString()); 36 | } 37 | }); 38 | } 39 | 40 | @Test 41 | void getOfflineMsg() { 42 | 43 | } 44 | 45 | @Test 46 | void ackOfflineMsg() { 47 | } 48 | 49 | @Test 50 | void getRecentSession() { 51 | MsgApi.API.getRecentSession().subscribe(new TestObserver<>()); 52 | } 53 | 54 | @Test 55 | void getSession() { 56 | MsgApi.API.getSession(new GetSessionDto(2)).subscribe(new TestObserver<>()); 57 | } 58 | 59 | @Test 60 | void updateSession() { 61 | MsgApi.API.updateSession(new GetSessionDto(2)).subscribe(new TestObserver<>()); 62 | } 63 | } -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/api/user/UserApiTest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.api.user; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | import pro.glideim.sdk.TestObserver; 6 | import pro.glideim.sdk.http.RetrofitManager; 7 | 8 | import java.util.Arrays; 9 | 10 | class UserApiTest { 11 | 12 | @BeforeEach 13 | void tearDown() { 14 | RetrofitManager.init("http://localhost:8081/api/"); 15 | } 16 | 17 | @Test 18 | void getContactsList() { 19 | UserApi.API.getContactsList().subscribe(new TestObserver<>()); 20 | } 21 | 22 | @Test 23 | void addContacts() { 24 | UserApi.API.addContacts(new ContactsUidDto(543614, "")).subscribe(new TestObserver<>()); 25 | } 26 | 27 | @Test 28 | void delContacts() { 29 | 30 | } 31 | 32 | @Test 33 | void contactsApproval() { 34 | } 35 | 36 | @Test 37 | void getUserInfo() { 38 | UserApi.API.getUserInfo(new GetUserInfoDto(Arrays.asList(1L, 2L, 543614L))).subscribe(new TestObserver<>()); 39 | } 40 | 41 | @Test 42 | void myProfile() { 43 | 44 | } 45 | 46 | @Test 47 | void updateMyProfile() { 48 | } 49 | } -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/im/RetrofitWsClientTest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.im; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import pro.glideim.sdk.http.RetrofitManager; 7 | import pro.glideim.sdk.ws.RetrofitWsClient; 8 | 9 | import java.util.concurrent.ExecutionException; 10 | 11 | class RetrofitWsClientTest { 12 | 13 | @BeforeEach 14 | void setUp() { 15 | RetrofitManager.init("http://localhost:8081/api/"); 16 | } 17 | 18 | @Test 19 | void connect() throws InterruptedException { 20 | RetrofitWsClient c = new RetrofitWsClient("ws://localhost:8080/ws"); 21 | c.connect().blockingGet(); 22 | 23 | // c.sendMessage(new CommMessage(1, "api.user.login", 1, new LoginDto("abc", "abc", 1))); 24 | Thread.sleep(10000); 25 | } 26 | } -------------------------------------------------------------------------------- /glide-im-sdk/src/test/java/pro/glideim/sdk/ws/NettyTest.java: -------------------------------------------------------------------------------- 1 | package pro.glideim.sdk.ws; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import io.reactivex.Single; 6 | 7 | class NettyTest { 8 | 9 | @Test 10 | void connect2() throws InterruptedException { 11 | Single connect = new NettyWsClient("ws://localhost:8080/ws").connect(); 12 | connect.blockingGet(); 13 | Thread.sleep(3000); 14 | } 15 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | android.enableBuildCache=false -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glide-im/Glide-IM-Android/19a8f741ceab19dfe12c0cd1c115adce26d8cf4f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Dec 02 11:23:34 CST 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glide-im/Glide-IM-Android/19a8f741ceab19dfe12c0cd1c115adce26d8cf4f/img/3.png -------------------------------------------------------------------------------- /img/a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glide-im/Glide-IM-Android/19a8f741ceab19dfe12c0cd1c115adce26d8cf4f/img/a.jpg -------------------------------------------------------------------------------- /img/b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glide-im/Glide-IM-Android/19a8f741ceab19dfe12c0cd1c115adce26d8cf4f/img/b.jpg -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | dependencyResolutionManagement { 2 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 3 | repositories { 4 | google() 5 | mavenCentral() 6 | jcenter() // Warning: this repository is going to shut down soon 7 | } 8 | } 9 | rootProject.name = "Glide-IM" 10 | include ':app' 11 | include ':glide-im-sdk' 12 | --------------------------------------------------------------------------------