├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ └── app-release.apk ├── src │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── king │ │ │ └── easychat │ │ │ └── ExampleInstrumentedTest.kt │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── ic_launcher-web.png │ │ ├── java │ │ │ └── com │ │ │ │ └── king │ │ │ │ └── easychat │ │ │ │ ├── App.kt │ │ │ │ ├── api │ │ │ │ └── ApiService.kt │ │ │ │ ├── app │ │ │ │ ├── Constants.kt │ │ │ │ ├── account │ │ │ │ │ ├── LoginActivity.kt │ │ │ │ │ ├── LoginViewModel.kt │ │ │ │ │ ├── RegisterActivity.kt │ │ │ │ │ ├── RegisterViewModel.kt │ │ │ │ │ ├── UpdatePwdActivity.kt │ │ │ │ │ └── UpdatePwdViewModel.kt │ │ │ │ ├── adapter │ │ │ │ │ ├── BindingAdapter.kt │ │ │ │ │ ├── BindingHolder.kt │ │ │ │ │ ├── ChatAdapter.kt │ │ │ │ │ ├── GroupChatAdapter.kt │ │ │ │ │ └── MessageAdapter.kt │ │ │ │ ├── base │ │ │ │ │ ├── BaseActivity.kt │ │ │ │ │ ├── BaseFragment.kt │ │ │ │ │ ├── MessageModel.kt │ │ │ │ │ └── MessageViewModel.kt │ │ │ │ ├── chat │ │ │ │ │ ├── ChatActivity.kt │ │ │ │ │ ├── ChatModel.kt │ │ │ │ │ ├── ChatViewModel.kt │ │ │ │ │ ├── GroupChatActivity.kt │ │ │ │ │ ├── GroupChatModel.kt │ │ │ │ │ └── GroupChatViewModel.kt │ │ │ │ ├── code │ │ │ │ │ ├── CodeActivity.kt │ │ │ │ │ ├── CodeViewModel.kt │ │ │ │ │ └── ScanCodeActivity.kt │ │ │ │ ├── friend │ │ │ │ │ ├── FriendFragment.kt │ │ │ │ │ ├── FriendModel.kt │ │ │ │ │ ├── FriendViewModel.kt │ │ │ │ │ ├── UserProfileActivity.kt │ │ │ │ │ └── UserProfileViewModel.kt │ │ │ │ ├── group │ │ │ │ │ ├── GroupFragment.kt │ │ │ │ │ ├── GroupMemberActivity.kt │ │ │ │ │ ├── GroupMemberViewModel.kt │ │ │ │ │ ├── GroupModel.kt │ │ │ │ │ ├── GroupProfileActivity.kt │ │ │ │ │ ├── GroupProfileViewModel.kt │ │ │ │ │ └── GroupViewModel.kt │ │ │ │ ├── home │ │ │ │ │ ├── HomeActivity.kt │ │ │ │ │ ├── HomeFragment.kt │ │ │ │ │ ├── HomeModel.kt │ │ │ │ │ └── HomeViewModel.kt │ │ │ │ ├── me │ │ │ │ │ ├── MeFragment.kt │ │ │ │ │ ├── MeViewModel.kt │ │ │ │ │ ├── about │ │ │ │ │ │ └── AboutActivity.kt │ │ │ │ │ └── user │ │ │ │ │ │ ├── ChangeUserInfoActivity.kt │ │ │ │ │ │ ├── ChangeUserInfoViewModel.kt │ │ │ │ │ │ ├── UserInfoActivity.kt │ │ │ │ │ │ └── UserInfoViewModel.kt │ │ │ │ ├── photo │ │ │ │ │ └── PhotoViewActivity.kt │ │ │ │ ├── search │ │ │ │ │ ├── SearchActivity.kt │ │ │ │ │ └── SearchViewModel.kt │ │ │ │ ├── service │ │ │ │ │ └── HeartBeatService.kt │ │ │ │ ├── splash │ │ │ │ │ ├── SplashActivity.kt │ │ │ │ │ └── SplashViewModel.kt │ │ │ │ └── web │ │ │ │ │ └── WebActivity.kt │ │ │ │ ├── bean │ │ │ │ ├── AppVersion.kt │ │ │ │ ├── Group.kt │ │ │ │ ├── GroupMessageDbo.kt │ │ │ │ ├── Message.kt │ │ │ │ ├── MessageDbo.kt │ │ │ │ ├── Operator.kt │ │ │ │ ├── RecentChat.kt │ │ │ │ ├── RecentGroupChat.kt │ │ │ │ ├── Result.kt │ │ │ │ ├── Search.kt │ │ │ │ └── User.kt │ │ │ │ ├── binding │ │ │ │ └── BindingAdapter.kt │ │ │ │ ├── config │ │ │ │ └── ConfigModule.kt │ │ │ │ ├── dao │ │ │ │ ├── AppDatabase.kt │ │ │ │ ├── GroupDao.kt │ │ │ │ ├── GroupMessageDao.kt │ │ │ │ ├── MessageDao.kt │ │ │ │ ├── RecentChatDao.kt │ │ │ │ ├── RecentGroupChatDao.kt │ │ │ │ └── UserDao.kt │ │ │ │ ├── di │ │ │ │ ├── component │ │ │ │ │ └── ApplicationComponent.kt │ │ │ │ └── module │ │ │ │ │ ├── ActivityModule.kt │ │ │ │ │ ├── ApplicationModule.kt │ │ │ │ │ ├── FragmentModule.kt │ │ │ │ │ └── ViewModelModule.kt │ │ │ │ ├── glide │ │ │ │ ├── GlideEngine.kt │ │ │ │ ├── GlideModule.kt │ │ │ │ └── ImageLoader.kt │ │ │ │ ├── netty │ │ │ │ ├── ChannelInitial.kt │ │ │ │ ├── NettyClient.kt │ │ │ │ ├── codec │ │ │ │ │ ├── PacketDecoder.kt │ │ │ │ │ ├── PacketEncoder.kt │ │ │ │ │ ├── PacketHelper.kt │ │ │ │ │ └── Spliter.kt │ │ │ │ ├── handle │ │ │ │ │ ├── AcceptGroupRespHandler.kt │ │ │ │ │ ├── AcceptRespHandler.kt │ │ │ │ │ ├── AddUserRespHandler.kt │ │ │ │ │ ├── AddUserSelfRespHandler.kt │ │ │ │ │ ├── AllowGroupRespHandler.kt │ │ │ │ │ ├── ApplyGroupRespHandler.kt │ │ │ │ │ ├── ApplyGroupSelfRespHandler.kt │ │ │ │ │ ├── CreateGroupRespHandler.kt │ │ │ │ │ ├── GroupMessageRespHandler.kt │ │ │ │ │ ├── HeartBeatRespHandler.kt │ │ │ │ │ ├── InviteGroupRespHandler.kt │ │ │ │ │ ├── InviteGroupSelfRespHandler.kt │ │ │ │ │ ├── LoginRespHandler.kt │ │ │ │ │ ├── MessageRespHandler.kt │ │ │ │ │ ├── MessageSelfRespHandler.kt │ │ │ │ │ ├── RegisterRespHandler.kt │ │ │ │ │ └── RespHandler.kt │ │ │ │ └── packet │ │ │ │ │ ├── MessageType.kt │ │ │ │ │ ├── Packet.kt │ │ │ │ │ ├── PacketType.kt │ │ │ │ │ ├── req │ │ │ │ │ ├── AcceptGroupReq.kt │ │ │ │ │ ├── AcceptReq.kt │ │ │ │ │ ├── AddUserReq.kt │ │ │ │ │ ├── AllowGroupReq.kt │ │ │ │ │ ├── ApplyGroupReq.kt │ │ │ │ │ ├── CreateGroupReq.kt │ │ │ │ │ ├── GroupMessageReq.kt │ │ │ │ │ ├── HeartBeatReq.kt │ │ │ │ │ ├── InviteGroupReq.kt │ │ │ │ │ ├── LoginReq.kt │ │ │ │ │ ├── LogoutReq.kt │ │ │ │ │ ├── MessageReq.kt │ │ │ │ │ ├── RegisterReq.kt │ │ │ │ │ ├── SyncMessageReq.kt │ │ │ │ │ └── UpdatePasswdReq.kt │ │ │ │ │ └── resp │ │ │ │ │ ├── AcceptGroupResp.kt │ │ │ │ │ ├── AcceptResp.kt │ │ │ │ │ ├── AddUserResp.kt │ │ │ │ │ ├── AddUserSelfResp.kt │ │ │ │ │ ├── AllowGroupResp.kt │ │ │ │ │ ├── ApplyGroupResp.kt │ │ │ │ │ ├── ApplyGroupSelfResp.kt │ │ │ │ │ ├── CreateGroupResp.kt │ │ │ │ │ ├── GroupMessageResp.kt │ │ │ │ │ ├── HeartBeatResp.kt │ │ │ │ │ ├── InviteGroupResp.kt │ │ │ │ │ ├── InviteGroupSelfResp.kt │ │ │ │ │ ├── LoginResp.kt │ │ │ │ │ ├── LogoutResp.kt │ │ │ │ │ ├── MessageResp.kt │ │ │ │ │ ├── MessageSelfResp.kt │ │ │ │ │ ├── RegisterResp.kt │ │ │ │ │ └── UpdatePasswdResp.kt │ │ │ │ ├── temp │ │ │ │ ├── TempActivity.kt │ │ │ │ ├── TempFragment.kt │ │ │ │ └── TempViewModel.kt │ │ │ │ ├── util │ │ │ │ ├── AES.kt │ │ │ │ ├── BitmapUtil.kt │ │ │ │ ├── Cache.kt │ │ │ │ ├── CheckUtil.kt │ │ │ │ ├── Event.kt │ │ │ │ ├── FileUtil.kt │ │ │ │ ├── JsonUtil.kt │ │ │ │ ├── KeyboardUtils.java │ │ │ │ └── SystemBarHelper.java │ │ │ │ └── view │ │ │ │ ├── DragBubbleView.java │ │ │ │ └── EasySwipeMenuLayout.java │ │ └── res │ │ │ ├── anim │ │ │ ├── anim_in.xml │ │ │ ├── anim_out.xml │ │ │ ├── splash_in.xml │ │ │ ├── translate_left_in.xml │ │ │ ├── translate_left_out.xml │ │ │ ├── translate_right_in.xml │ │ │ └── translate_right_out.xml │ │ │ ├── color │ │ │ └── bottom_menu_selector.xml │ │ │ ├── drawable-v21 │ │ │ └── white_selector.xml │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable-xhdpi │ │ │ └── ec_welcome.9.png │ │ │ ├── drawable-xxhdpi │ │ │ ├── btn_back_normal.png │ │ │ ├── btn_back_pressed.png │ │ │ ├── btn_bg_normal.9.png │ │ │ ├── btn_bg_pressed.9.png │ │ │ ├── btn_black_back_normal.png │ │ │ ├── btn_black_back_pressed.png │ │ │ ├── btn_clear.png │ │ │ ├── btn_close_normal.png │ │ │ ├── btn_close_pressed.png │ │ │ ├── btn_delete_normal.png │ │ │ ├── btn_delete_pressed.png │ │ │ ├── btn_menu_normal.png │ │ │ ├── btn_menu_pressed.png │ │ │ ├── btn_more_normal.png │ │ │ ├── btn_more_pressed.png │ │ │ ├── btn_none.png │ │ │ ├── btn_scan_normal.png │ │ │ ├── btn_scan_pressed.png │ │ │ ├── btn_search_normal.png │ │ │ ├── btn_search_pressed.png │ │ │ ├── default_avatar.png │ │ │ ├── ec_about.png │ │ │ ├── ec_about_line.png │ │ │ ├── ec_add.png │ │ │ ├── ec_chat_bubble_left.9.png │ │ │ ├── ec_chat_bubble_right.9.png │ │ │ ├── ec_create_group_normal.png │ │ │ ├── ec_create_group_pressed.png │ │ │ ├── ec_delete.png │ │ │ ├── ec_detail_normal.png │ │ │ ├── ec_detail_pressed.png │ │ │ ├── ec_edit_box_bg.9.png │ │ │ ├── ec_empty.png │ │ │ ├── ec_heart.png │ │ │ ├── ec_keyboard.png │ │ │ ├── ec_modify_password.png │ │ │ ├── ec_next.png │ │ │ ├── ec_next_white.png │ │ │ ├── ec_off.png │ │ │ ├── ec_on.png │ │ │ ├── ec_qrcode.png │ │ │ ├── ec_save_normal.png │ │ │ ├── ec_save_pressed.png │ │ │ ├── ec_smile.png │ │ │ ├── ec_version.png │ │ │ ├── explosion_five.png │ │ │ ├── explosion_four.png │ │ │ ├── explosion_one.png │ │ │ ├── explosion_three.png │ │ │ ├── explosion_two.png │ │ │ ├── ic_about_image.png │ │ │ ├── ic_close.png │ │ │ ├── ic_github.png │ │ │ ├── ic_hide.png │ │ │ ├── ic_menu_about.png │ │ │ ├── ic_menu_logout.png │ │ │ ├── ic_none.png │ │ │ ├── ic_password.png │ │ │ ├── ic_search.png │ │ │ ├── ic_show.png │ │ │ ├── ic_user.png │ │ │ ├── input_bg_focus.9.png │ │ │ ├── input_bg_normal.9.png │ │ │ ├── login_slogan.png │ │ │ ├── logo.png │ │ │ ├── menu_friend_normal.png │ │ │ ├── menu_friend_selected.png │ │ │ ├── menu_group_normal.png │ │ │ ├── menu_group_selected.png │ │ │ ├── menu_me_normal.png │ │ │ ├── menu_me_selected.png │ │ │ ├── menu_message_normal.png │ │ │ └── menu_message_selected.png │ │ │ ├── drawable │ │ │ ├── btn_back_selector.xml │ │ │ ├── btn_bg_selector.xml │ │ │ ├── btn_black_back_selector.xml │ │ │ ├── btn_clear_selector.xml │ │ │ ├── btn_close_selector.xml │ │ │ ├── btn_create_group_selector.xml │ │ │ ├── btn_delete_selector.xml │ │ │ ├── btn_detail_selector.xml │ │ │ ├── btn_flash_selector.xml │ │ │ ├── btn_menu_selector.xml │ │ │ ├── btn_password_eye_selector.xml │ │ │ ├── btn_save_selector.xml │ │ │ ├── btn_scan_selector.xml │ │ │ ├── btn_search_selector.xml │ │ │ ├── edit_bg_line_normal.xml │ │ │ ├── edit_bg_line_pressed.xml │ │ │ ├── edit_bg_line_selector.xml │ │ │ ├── ic_clear_selector.xml │ │ │ ├── ic_launcher_background.xml │ │ │ ├── line_drawable.xml │ │ │ ├── line_drawable_8.xml │ │ │ ├── line_drawable_xh_none.xml │ │ │ ├── logo_layer.xml │ │ │ ├── menu_friend_selector.xml │ │ │ ├── menu_group_selector.xml │ │ │ ├── menu_me_selector.xml │ │ │ ├── menu_message_selector.xml │ │ │ ├── search_bg.xml │ │ │ ├── splash_layer.xml │ │ │ ├── web_progress_bar.xml │ │ │ ├── white_bottom_layer.xml │ │ │ ├── white_layer.xml │ │ │ └── white_selector.xml │ │ │ ├── layout │ │ │ ├── about_activity.xml │ │ │ ├── change_user_info_activity.xml │ │ │ ├── chat_activity.xml │ │ │ ├── code_activity.xml │ │ │ ├── create_group_dialog.xml │ │ │ ├── friend_fragment.xml │ │ │ ├── group_chat_activity.xml │ │ │ ├── group_fragment.xml │ │ │ ├── group_member_activity.xml │ │ │ ├── group_profile_activity.xml │ │ │ ├── home_activity.xml │ │ │ ├── home_fragment.xml │ │ │ ├── home_toolbar.xml │ │ │ ├── layout_empty.xml │ │ │ ├── login_activity.xml │ │ │ ├── me_fragment.xml │ │ │ ├── photo_view_activity.xml │ │ │ ├── register_activity.xml │ │ │ ├── rv_chat_item.xml │ │ │ ├── rv_chat_right_item.xml │ │ │ ├── rv_friend_item.xml │ │ │ ├── rv_group_chat_item.xml │ │ │ ├── rv_group_chat_right_item.xml │ │ │ ├── rv_group_item.xml │ │ │ ├── rv_item.xml │ │ │ ├── rv_message_item.xml │ │ │ ├── rv_search_user_item.xml │ │ │ ├── rv_user_item.xml │ │ │ ├── scan_code_activity.xml │ │ │ ├── scan_toolbar.xml │ │ │ ├── search_user_activity.xml │ │ │ ├── splash_activity.xml │ │ │ ├── toolbar.xml │ │ │ ├── update_pwd_activity.xml │ │ │ ├── user_info_activity.xml │ │ │ ├── user_profile_activity.xml │ │ │ ├── vp_photo_item.xml │ │ │ └── web_activity.xml │ │ │ ├── menu │ │ │ └── about_me.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values-v21 │ │ │ ├── dimens.xml │ │ │ └── styles.xml │ │ │ ├── values │ │ │ ├── attrs.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── ic_launcher_background.xml │ │ │ ├── ids.xml │ │ │ ├── integers.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ │ └── xml │ │ │ └── network_security_config.xml │ └── test │ │ └── java │ │ └── com │ │ └── king │ │ └── easychat │ │ └── ExampleUnitTest.kt └── tinker-support.gradle ├── art ├── GIF.gif ├── GIF2.gif └── QR_EasyChat.png ├── build.gradle ├── doc └── 接口文档.docx ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── versions.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | dist: trusty 3 | jdk: oraclejdk8 4 | sudo: false 5 | 6 | env: 7 | global: 8 | - ANDROID_API_LEVEL=29 9 | - ANDROID_BUILD_TOOLS_VERSION=29.0.2 10 | - TRAVIS_SECURE_ENV_VARS=true 11 | 12 | before_install: 13 | - chmod +x gradlew 14 | - mkdir "$ANDROID_HOME/licenses" || true 15 | # Hack to accept Android licenses 16 | - yes | sdkmanager "platforms;android-$ANDROID_API_LEVEL" 17 | 18 | 19 | android: 20 | components: 21 | # The BuildTools version used by your project 22 | - tools 23 | - platform-tools 24 | - build-tools-$ANDROID_BUILD_TOOLS_VERSION 25 | # The SDK version used to compile your project 26 | - android-$ANDROID_API_LEVEL 27 | - extra-android-m2repository 28 | - extra-google-android-support 29 | 30 | script: 31 | - ./gradlew clean 32 | - ./gradlew assembleRelease -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## EasyChat 2 | 3 | ![Image](app/src/main/ic_launcher-web.png) 4 | 5 | [![Download](https://img.shields.io/badge/download-App-blue.svg)](https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/master/app/release/app-release.apk) 6 | [![API](https://img.shields.io/badge/API-16%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=16) 7 | [![License](https://img.shields.io/badge/license-Apche%202.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0) 8 | [![QQGroup](https://img.shields.io/badge/QQGroup-20867961-blue.svg)](http://shang.qq.com/wpa/qunwpa?idkey=8fcc6a2f88552ea44b1411582c94fd124f7bb3ec227e2a400dbbfaad3dc2f5ad) 9 | 10 | 11 | EasyChat for Android 是一个开源的社交类的App。主要包含消息、好友、群组等相关的社交核心功能。部分界面参照了QQ、微信等相关社交APP。更多精彩详情,请直接[下载App](https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/master/app/release/app-release.apk)进行体验吧。 12 | 13 | > App整体架构主要采用MVVM模式, 基于 [MVVMFrame](https://github.com/jenly1314/MVVMFrame) 框架搭建。 14 | 15 | ### 核心技术点 16 | 17 | * JetPack(Lifecycle,LiveData,ViewModel,Room) 18 | * Dagger 19 | * DataBinding 20 | * Netty 21 | 22 | ## Gif 展示 23 | ![Image](art/GIF.gif) 24 | ![Image](art/GIF2.gif) 25 | 26 | > 你也可以直接 [下载App](https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/master/app/release/app-release.apk) 体验效果 27 | 28 | 29 | ## 版本记录 30 | 31 | #### 2019-10-31 v1.0.0 初始版本 32 | * EasyChat完成主要核心功能 33 | 34 | ## EasyChat相关开源项目 35 | 36 | ##### 服务端:[EasyChatServer](https://github.com/yetel/EasyChatServer) 37 | ##### JavaFX客户端:[EasyChatJavaFXClient](https://github.com/yetel/EasyChatJavaFXClient) 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /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 22 | -------------------------------------------------------------------------------- /app/release/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/release/app-release.apk -------------------------------------------------------------------------------- /app/src/androidTest/java/com/king/easychat/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.runner.AndroidJUnit4 5 | import com.king.easychat.netty.packet.Packet 6 | 7 | import org.junit.Test 8 | import org.junit.runner.RunWith 9 | 10 | import org.junit.Assert.* 11 | import java.io.File 12 | import java.io.IOException 13 | 14 | /** 15 | * Instrumented test, which will execute on an Android device. 16 | * 17 | * See [testing documentation](http://d.android.com/tools/testing). 18 | */ 19 | @RunWith(AndroidJUnit4::class) 20 | class ExampleInstrumentedTest { 21 | @Test 22 | fun useAppContext() { 23 | // Context of the app under test. 24 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 25 | assertEquals("com.king.easychat", appContext.packageName) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/api/ApiService.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.api 2 | 3 | import com.king.easychat.bean.* 4 | import retrofit2.Call 5 | import retrofit2.http.* 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | interface ApiService { 11 | 12 | /** 13 | * 获取用户信息 14 | */ 15 | @GET("user/{userId}") 16 | fun getUser(@Header("token")token : String,@Path("userId")userId: String): Call> 17 | 18 | /** 19 | * 获取好友列表 20 | */ 21 | @GET("users") 22 | fun getFriends(@Header("token")token : String): Call>> 23 | 24 | /** 25 | * 获取群组信息 26 | */ 27 | @GET("group/{groupId}") 28 | fun getGroup(@Header("token")token : String,@Path("groupId")groupId: String): Call> 29 | 30 | 31 | /** 32 | * 获取群列表 33 | */ 34 | @GET("groups") 35 | fun getGroups(@Header("token")token : String): Call>> 36 | 37 | /** 38 | * 获取群用户列表 39 | */ 40 | @GET("query/member/{groupId}") 41 | fun getGroupMembers(@Header("token")token : String,@Path("groupId")groupId : String): Call>> 42 | 43 | /** 44 | * 上传图片 45 | */ 46 | @POST("image/upload") 47 | fun uploadImage(@Header("token")token : String,@Body params: Map): Call> 48 | 49 | /** 50 | * 修改用户信息 51 | */ 52 | @PUT("user/update") 53 | fun updateUserInfo(@Header("token")token : String,@Body params: Map): Call> 54 | 55 | /** 56 | * 修改用户密码 57 | */ 58 | @FormUrlEncoded 59 | @PUT("update/password") 60 | fun updateUserPassword(@Header("token")token : String,@Field("oldPassword")oldPassword: String,@Field("newPassword")newPassword: String): Call> 61 | 62 | /** 63 | * 搜索 64 | */ 65 | @GET("fuzzy/allQuery") 66 | fun search(@Header("token")token : String,@Query("key")keyword: String,@Query("currentPage")currentPage : Int, @Query("pageSize")pageSize: Int): Call>> 67 | 68 | /** 69 | * 修改好友备注名称 70 | */ 71 | @FormUrlEncoded 72 | @PUT("update/friend/remark") 73 | fun updateFriendRemark(@Header("token")token : String,@Field("friendId")friendId : String,@Field("remark")remark : String): Call> 74 | 75 | 76 | /** 77 | * 版本检测 78 | */ 79 | @GET("system/checkVersion") 80 | fun checkVersion(@Query("versionCode")versionCode : String): Call> 81 | 82 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/account/LoginViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.account 2 | 3 | import android.app.Application 4 | import com.king.anetty.Netty 5 | import com.king.easychat.app.Constants 6 | import com.king.easychat.netty.NettyClient 7 | import com.king.easychat.netty.packet.req.LoginReq 8 | import com.king.frame.mvvmframe.base.BaseModel 9 | import com.king.frame.mvvmframe.base.DataViewModel 10 | import javax.inject.Inject 11 | 12 | /** 13 | * @author Jenly 14 | */ 15 | class LoginViewModel @Inject constructor(application: Application, model: BaseModel?) : DataViewModel(application, model){ 16 | 17 | var loginReq: LoginReq? = null 18 | 19 | val onSendMessageListener = Netty.OnSendMessageListener { msg, success -> 20 | hideLoading() 21 | if(success){ 22 | sendSingleLiveEvent(Constants.EVENT_SUCCESS) 23 | } 24 | } 25 | 26 | override fun onCreate() { 27 | super.onCreate() 28 | 29 | 30 | NettyClient.INSTANCE.setOnConnectListener(object: Netty.OnConnectListener{ 31 | override fun onSuccess() { 32 | 33 | } 34 | 35 | override fun onFailed() { 36 | hideLoading() 37 | } 38 | 39 | override fun onError(e: Exception?) { 40 | hideLoading() 41 | } 42 | 43 | }) 44 | NettyClient.INSTANCE.setOnSendMessageListener(onSendMessageListener) 45 | 46 | } 47 | 48 | override fun onDestroy() { 49 | NettyClient.INSTANCE.setOnSendMessageListener(null) 50 | super.onDestroy() 51 | } 52 | 53 | fun login(username: String,password: String){ 54 | showLoading() 55 | loginReq = LoginReq(null,username,password) 56 | if(!NettyClient.INSTANCE.isConnected()){ 57 | NettyClient.INSTANCE.setOnConnectListener(object: Netty.OnConnectListener{ 58 | override fun onSuccess() { 59 | NettyClient.INSTANCE.sendMessage(loginReq!!) 60 | hideLoading() 61 | } 62 | 63 | override fun onFailed() { 64 | hideLoading() 65 | } 66 | 67 | override fun onError(e: Exception?) { 68 | hideLoading() 69 | } 70 | 71 | }) 72 | NettyClient.INSTANCE.connect() 73 | 74 | }else{ 75 | NettyClient.INSTANCE.sendMessage(loginReq!!) 76 | } 77 | 78 | 79 | } 80 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/account/UpdatePwdViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.account 2 | 3 | import android.app.Application 4 | import com.king.easychat.App 5 | import com.king.easychat.R 6 | import com.king.easychat.api.ApiService 7 | import com.king.easychat.bean.Result 8 | import com.king.easychat.bean.User 9 | import com.king.frame.mvvmframe.base.BaseModel 10 | import com.king.frame.mvvmframe.base.DataViewModel 11 | import com.king.frame.mvvmframe.base.livedata.StatusEvent 12 | import com.king.frame.mvvmframe.http.callback.ApiCallback 13 | import retrofit2.Call 14 | import timber.log.Timber 15 | import javax.inject.Inject 16 | 17 | /** 18 | * @author Jenly 19 | */ 20 | class UpdatePwdViewModel @Inject constructor(application: Application, model: BaseModel?) : DataViewModel(application, model){ 21 | 22 | /** 23 | * 更新用户信息 24 | */ 25 | fun updateUserPassword(oldPassword: String, newPassword: String){ 26 | 27 | val app = getApplication() 28 | val token = app.getToken() 29 | updateStatus(StatusEvent.Status.LOADING) 30 | getRetrofitService(ApiService::class.java) 31 | .updateUserPassword(token,oldPassword,newPassword) 32 | .enqueue(object: ApiCallback>(){ 33 | override fun onResponse(call: Call>?, result: Result?) { 34 | result?.let { 35 | if(it.isSuccess()){ 36 | updateStatus(StatusEvent.Status.SUCCESS) 37 | }else{ 38 | sendMessage(it.desc) 39 | Timber.d(it.desc) 40 | updateStatus(StatusEvent.Status.FAILURE) 41 | } 42 | } ?: run { 43 | updateStatus(StatusEvent.Status.FAILURE) 44 | sendMessage(R.string.result_failure) 45 | } 46 | 47 | } 48 | 49 | override fun onError(call: Call>?, t: Throwable) { 50 | updateStatus(StatusEvent.Status.ERROR) 51 | sendMessage(t.message) 52 | } 53 | 54 | }) 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/adapter/BindingAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.adapter 2 | 3 | import androidx.annotation.Nullable 4 | import com.chad.library.adapter.base.BaseQuickAdapter 5 | import com.king.easychat.BR 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | open class BindingAdapter : BaseQuickAdapter { 11 | 12 | constructor(layoutResId: Int, @Nullable data: List) : super(layoutResId, data) 13 | 14 | constructor(@Nullable data: List) : super(data) 15 | 16 | constructor(layoutResId: Int) : super(layoutResId) 17 | 18 | override fun convert(helper: BindingHolder, item: T) { 19 | helper.mBinding?.let { 20 | it.setVariable(BR.data,item) 21 | it.executePendingBindings() 22 | } 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/adapter/BindingHolder.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.adapter 2 | 3 | import android.view.View 4 | import androidx.databinding.DataBindingUtil 5 | import androidx.databinding.ViewDataBinding 6 | import com.chad.library.adapter.base.BaseViewHolder 7 | 8 | /** 9 | * @author Jenly 10 | */ 11 | class BindingHolder(view: View) : BaseViewHolder(view) { 12 | 13 | var mBinding: ViewDataBinding? = null 14 | init { 15 | try { 16 | mBinding = DataBindingUtil.bind(view)!! 17 | } catch (e: Exception) { 18 | 19 | } 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/adapter/ChatAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.adapter 2 | 3 | import com.chad.library.adapter.base.BaseMultiItemQuickAdapter 4 | import com.king.easychat.BR 5 | import com.king.easychat.R 6 | import com.king.easychat.glide.ImageLoader 7 | import com.king.easychat.netty.packet.resp.MessageResp 8 | 9 | /** 10 | * @author Jenly 11 | */ 12 | class ChatAdapter(var friendImageUrl : String?,var myImageUrl : String?): BaseMultiItemQuickAdapter(null) { 13 | 14 | var curTime = System.currentTimeMillis() 15 | 16 | init { 17 | 18 | addItemType(MessageResp.Left, R.layout.rv_chat_item) 19 | addItemType(MessageResp.Right, R.layout.rv_chat_right_item) 20 | } 21 | 22 | override fun convert(helper: BindingHolder, item: MessageResp?) { 23 | helper.mBinding?.let { 24 | when(item?.itemType){ 25 | MessageResp.Left -> ImageLoader.displayImage(mContext,helper.getView(R.id.ivAvatar),friendImageUrl,R.drawable.default_avatar) 26 | MessageResp.Right -> ImageLoader.displayImage(mContext,helper.getView(R.id.ivAvatar),myImageUrl,R.drawable.default_avatar) 27 | } 28 | helper.addOnClickListener(R.id.ivContent) 29 | helper.addOnClickListener(R.id.ivAvatar) 30 | it.setVariable(BR.curTime,curTime) 31 | it.setVariable(BR.data,item) 32 | it.executePendingBindings() 33 | } 34 | } 35 | 36 | 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/adapter/GroupChatAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.adapter 2 | 3 | import com.chad.library.adapter.base.BaseMultiItemQuickAdapter 4 | import com.king.easychat.BR 5 | import com.king.easychat.R 6 | import com.king.easychat.glide.ImageLoader 7 | import com.king.easychat.netty.packet.resp.GroupMessageResp 8 | import com.king.easychat.netty.packet.resp.MessageResp 9 | 10 | /** 11 | * @author Jenly 12 | */ 13 | class GroupChatAdapter: BaseMultiItemQuickAdapter { 14 | 15 | var curTime = System.currentTimeMillis() 16 | 17 | constructor() : super(null){ 18 | addItemType(GroupMessageResp.Left, R.layout.rv_group_chat_item) 19 | addItemType(GroupMessageResp.Right, R.layout.rv_group_chat_right_item) 20 | } 21 | 22 | override fun convert(helper: BindingHolder, item: GroupMessageResp?) { 23 | helper.mBinding?.let { 24 | when(item?.itemType){ 25 | MessageResp.Left -> ImageLoader.displayImage(mContext,helper.getView(R.id.ivAvatar),null,R.drawable.default_avatar) 26 | MessageResp.Right -> ImageLoader.displayImage(mContext,helper.getView(R.id.ivAvatar),null,R.drawable.default_avatar) 27 | } 28 | helper.addOnClickListener(R.id.ivContent) 29 | helper.addOnClickListener(R.id.ivAvatar) 30 | it.setVariable(BR.data,item) 31 | it.setVariable(BR.curTime,curTime) 32 | it.executePendingBindings() 33 | } 34 | } 35 | 36 | 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/adapter/MessageAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.adapter 2 | 3 | import com.king.easychat.BR 4 | import com.king.easychat.R 5 | import com.king.easychat.app.home.HomeViewModel 6 | import com.king.easychat.bean.Message 7 | import com.king.easychat.view.DragBubbleView 8 | 9 | /** 10 | * @author Jenly 11 | */ 12 | class MessageAdapter(val userId: String,val viewModel: HomeViewModel) : BindingAdapter(R.layout.rv_message_item) { 13 | 14 | var curTime = System.currentTimeMillis() 15 | 16 | override fun convert(helper: BindingHolder, item: Message) { 17 | helper.getView(R.id.dbvCount).setOnBubbleStateListener(object : DragBubbleView.OnBubbleStateListener{ 18 | override fun onDrag() { 19 | } 20 | 21 | override fun onMove() { 22 | } 23 | 24 | override fun onRestore() { 25 | } 26 | 27 | override fun onDismiss() { 28 | when(item.messageMode){ 29 | Message.userMode -> viewModel.updateMessageRead(userId,item.id!!) 30 | Message.groupMode -> viewModel.updateGroupMessageRead(userId,item.id!!) 31 | } 32 | } 33 | 34 | }) 35 | 36 | helper.addOnClickListener(R.id.clContent) 37 | helper.addOnClickListener(R.id.llDelete) 38 | 39 | 40 | helper.mBinding?.let { 41 | it.setVariable(BR.curTime,curTime) 42 | it.setVariable(BR.data,item) 43 | it.executePendingBindings() 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/chat/ChatModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.chat 2 | 3 | import com.king.easychat.app.base.MessageModel 4 | import com.king.easychat.bean.MessageDbo 5 | import com.king.frame.mvvmframe.data.IDataRepository 6 | import javax.inject.Inject 7 | 8 | /** 9 | * @author Jenly 10 | */ 11 | class ChatModel @Inject constructor(repository: IDataRepository?) : MessageModel(repository){ 12 | 13 | /** 14 | * 根据好友id获取聊天记录 15 | */ 16 | fun queryMessageByFriendId(userId : String, friendId : String, currentPage : Int, pageSize: Int) : List { 17 | return getMessageDao().getMessageBySenderId(userId, friendId,friendId, (currentPage-1) * pageSize, pageSize).sortedBy { it.dateTime } 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/chat/ChatViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.chat 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.MutableLiveData 5 | import com.king.easychat.app.Constants 6 | import com.king.easychat.app.base.MessageViewModel 7 | import com.king.easychat.netty.NettyClient 8 | import com.king.easychat.netty.packet.MessageType 9 | import com.king.easychat.netty.packet.req.MessageReq 10 | import com.king.easychat.netty.packet.resp.MessageResp 11 | import kotlinx.coroutines.Dispatchers 12 | import kotlinx.coroutines.GlobalScope 13 | import kotlinx.coroutines.launch 14 | import timber.log.Timber 15 | import javax.inject.Inject 16 | 17 | /** 18 | * @author Jenly 19 | */ 20 | class ChatViewModel @Inject constructor(application: Application, model: ChatModel?) : MessageViewModel(application, model){ 21 | 22 | var messageLiveData = MutableLiveData>() 23 | 24 | override fun onCreate() { 25 | super.onCreate() 26 | } 27 | 28 | 29 | /** 30 | * 根据好友id获取聊天记录 31 | */ 32 | fun queryMessageByFriendId(userId : String, friendId : String, currentPage : Int, pageSize: Int) { 33 | 34 | GlobalScope.launch(Dispatchers.IO) { 35 | var list = mModel.queryMessageByFriendId(userId,friendId,currentPage,pageSize) 36 | Timber.d("message:$list") 37 | messageLiveData.postValue(list.map { it.toMessageResp() }) 38 | } 39 | sendSingleLiveEvent(Constants.REFRESH_SUCCESS) 40 | 41 | } 42 | 43 | /** 44 | * 发送桃心 45 | */ 46 | fun sendHeart(receiver: String){ 47 | NettyClient.INSTANCE.sendMessage(MessageReq(receiver,MessageType.HEART.toString(),MessageType.HEART)) 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/chat/GroupChatModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.chat 2 | 3 | import com.king.easychat.app.base.MessageModel 4 | import com.king.easychat.bean.GroupMessageDbo 5 | import com.king.frame.mvvmframe.data.IDataRepository 6 | import javax.inject.Inject 7 | 8 | /** 9 | * @author Jenly 10 | */ 11 | class GroupChatModel @Inject constructor(repository: IDataRepository?) : MessageModel(repository){ 12 | 13 | /** 14 | * 根据群聊id获取聊天记录 15 | */ 16 | fun queryMessageByGroupId(userId : String, groupId : String, currentPage : Int, pageSize : Int) : List { 17 | return getGroupMessageDao().getGroupMessageByGroupId(userId, groupId, (currentPage-1) * pageSize, pageSize).sortedBy { it.dateTime } 18 | } 19 | 20 | 21 | 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/chat/GroupChatViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.chat 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.MutableLiveData 5 | import com.king.easychat.app.Constants 6 | import com.king.easychat.app.base.MessageViewModel 7 | import com.king.easychat.netty.NettyClient 8 | import com.king.easychat.netty.packet.MessageType 9 | import com.king.easychat.netty.packet.req.GroupMessageReq 10 | import com.king.easychat.netty.packet.resp.GroupMessageResp 11 | import kotlinx.coroutines.Dispatchers 12 | import kotlinx.coroutines.GlobalScope 13 | import kotlinx.coroutines.launch 14 | import javax.inject.Inject 15 | 16 | /** 17 | * @author Jenly 18 | */ 19 | class GroupChatViewModel @Inject constructor(application: Application, model: GroupChatModel?) : MessageViewModel(application, model){ 20 | 21 | var groupMessageLiveData = MutableLiveData>() 22 | 23 | /** 24 | * 查询群组聊天记录 25 | */ 26 | fun queryMessageByGroupId(userId : String, groupId : String, currentPage : Int, pageSize : Int){ 27 | GlobalScope.launch(Dispatchers.IO) { 28 | var list = mModel.queryMessageByGroupId(userId,groupId,currentPage,pageSize) 29 | groupMessageLiveData.postValue(list.map { it.toGroupMessageResp() }) 30 | } 31 | sendSingleLiveEvent(Constants.REFRESH_SUCCESS) 32 | } 33 | 34 | /** 35 | * 发送桃心 36 | */ 37 | fun sendHeart(receiver: String){ 38 | NettyClient.INSTANCE.sendMessage(GroupMessageReq(receiver,MessageType.HEART.toString(),MessageType.HEART)) 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/code/CodeActivity.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.code 2 | 3 | import android.os.Bundle 4 | import com.king.easychat.R 5 | import com.king.easychat.app.Constants 6 | import com.king.easychat.app.base.BaseActivity 7 | import com.king.easychat.databinding.CodeActivityBinding 8 | import kotlinx.android.synthetic.main.code_activity.* 9 | import kotlinx.android.synthetic.main.toolbar.* 10 | 11 | /** 12 | * @author Jenly 13 | */ 14 | class CodeActivity : BaseActivity(){ 15 | 16 | override fun initData(savedInstanceState: Bundle?) { 17 | tvTitle.setText(R.string.qrcode) 18 | 19 | var userId = intent.getStringExtra(Constants.KEY_ID) 20 | var avatar = intent.getStringExtra(Constants.KEY_IMAGE_URL) 21 | val type = intent.getIntExtra(Constants.KEY_TYPE,Constants.USER_TYPE) 22 | mViewModel.updateQRCode(context,userId,avatar,type,ivCode) 23 | 24 | tvTips.setText(if(type == Constants.GROUP_TYPE) R.string.tips_group_qrcode else R.string.tips_user_qrcode ) 25 | } 26 | 27 | override fun getLayoutId(): Int { 28 | return R.layout.code_activity 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/code/CodeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.code 2 | 3 | import android.app.Application 4 | import android.content.Context 5 | import android.graphics.Bitmap 6 | import android.graphics.BitmapFactory 7 | import android.widget.ImageView 8 | import com.king.easychat.R 9 | import com.king.easychat.app.Constants 10 | import com.king.easychat.glide.GlideApp 11 | import com.king.easychat.util.BitmapUtil 12 | import com.king.frame.mvvmframe.base.BaseModel 13 | import com.king.frame.mvvmframe.base.DataViewModel 14 | import com.king.zxing.util.CodeUtils 15 | import kotlinx.coroutines.Dispatchers 16 | import kotlinx.coroutines.GlobalScope 17 | import kotlinx.coroutines.launch 18 | import kotlinx.coroutines.withContext 19 | import javax.inject.Inject 20 | 21 | /** 22 | * @author Jenly 23 | */ 24 | class CodeViewModel @Inject constructor(application: Application, model: BaseModel?) : DataViewModel(application, model){ 25 | 26 | fun updateQRCode(context: Context,id: String,avatar: String?,type: Int,iv: ImageView){ 27 | GlobalScope.launch(Dispatchers.Main) { 28 | var codeContent = "" 29 | if(type == Constants.GROUP_TYPE){ 30 | codeContent = Constants.GROUP_CODE_PREFIX + id 31 | } else{ 32 | codeContent = Constants.USER_CODE_PREFIX + id 33 | } 34 | val code = withContext(Dispatchers.IO){ 35 | var logo : Bitmap? = null 36 | if(avatar != null){ 37 | var bmp: Bitmap? = null 38 | var file = GlideApp.with(context).load(avatar).downloadOnly(100,100).get() 39 | if(file != null){ 40 | bmp = BitmapFactory.decodeFile(file.absolutePath) 41 | }else{ 42 | bmp = BitmapFactory.decodeResource(context.resources, R.drawable.logo) 43 | } 44 | 45 | logo = BitmapUtil.getOvalBitmap(bmp) 46 | } 47 | 48 | CodeUtils.createQRCode(codeContent,400,logo) 49 | } 50 | 51 | GlideApp.with(context).load(code).into(iv) 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/friend/FriendModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.friend 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import com.king.easychat.api.ApiService 5 | import com.king.easychat.app.base.MessageModel 6 | import com.king.easychat.bean.Result 7 | import com.king.easychat.bean.User 8 | import com.king.frame.mvvmframe.bean.Resource 9 | import com.king.frame.mvvmframe.data.IDataRepository 10 | import com.king.frame.mvvmframe.http.callback.ApiCallback 11 | import kotlinx.coroutines.Dispatchers 12 | import kotlinx.coroutines.GlobalScope 13 | import kotlinx.coroutines.launch 14 | import retrofit2.Call 15 | import javax.inject.Inject 16 | 17 | /** 18 | * @author Jenly 19 | */ 20 | class FriendModel @Inject constructor(repository: IDataRepository?) : MessageModel(repository){ 21 | 22 | val friendResource = MutableLiveData>>() 23 | 24 | 25 | fun getFriends(token: String){ 26 | friendResource.value = Resource.loading() 27 | getRetrofitService(ApiService::class.java) 28 | .getFriends(token) 29 | .enqueue(object : ApiCallback>>(){ 30 | override fun onResponse(call: Call>>?, result: Result>?) { 31 | result?.let { 32 | if(it.isSuccess()){ 33 | friendResource.value = Resource.success(it.data) 34 | saveUsers(it.data) 35 | return 36 | }else{ 37 | friendResource.value = Resource.failure(result.desc) 38 | } 39 | 40 | } ?: run { 41 | friendResource.value = Resource.failure(null) 42 | } 43 | 44 | 45 | } 46 | 47 | override fun onError(call: Call>>?, t: Throwable?) { 48 | friendResource.value = Resource.error(t) 49 | } 50 | 51 | }) 52 | 53 | } 54 | 55 | fun saveUsers(users: List?){ 56 | users?.let { 57 | GlobalScope.launch(Dispatchers.IO) { 58 | with(getUserDao()){ 59 | deleteAll() 60 | insert(it) 61 | } 62 | } 63 | } 64 | 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/friend/FriendViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.friend 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.LiveData 5 | import androidx.lifecycle.MediatorLiveData 6 | import com.king.easychat.App 7 | import com.king.easychat.bean.User 8 | import com.king.frame.mvvmframe.base.BaseViewModel 9 | import com.king.frame.mvvmframe.bean.Resource 10 | import javax.inject.Inject 11 | 12 | /** 13 | * @author Jenly 14 | */ 15 | class FriendViewModel @Inject constructor(application: Application, model: FriendModel?) : BaseViewModel(application, model){ 16 | 17 | var friendsLiveData = MediatorLiveData>() 18 | 19 | var source : LiveData>>? = null 20 | 21 | override fun onCreate() { 22 | super.onCreate() 23 | getFriends() 24 | } 25 | 26 | fun retry(){ 27 | getFriends() 28 | } 29 | 30 | /** 31 | * 获取好友列表 32 | */ 33 | fun getFriends(){ 34 | val token = getApplication().getToken() 35 | mModel.getFriends(token!!) 36 | source?.let { 37 | friendsLiveData.removeSource(it) 38 | } 39 | source = mModel.friendResource 40 | friendsLiveData.addSource(source!!) { 41 | updateStatus(it.status) 42 | if(it.isSuccess){ 43 | friendsLiveData.postValue(it.data) 44 | }else { 45 | if(it.isFailure){ 46 | sendMessage(it.message) 47 | } 48 | friendsLiveData.addSource(mModel.getUsers()) {friendsLiveData::postValue} 49 | } 50 | 51 | } 52 | 53 | } 54 | 55 | 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/group/GroupMemberViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.group 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.MutableLiveData 5 | import com.king.easychat.App 6 | import com.king.easychat.R 7 | import com.king.easychat.api.ApiService 8 | import com.king.easychat.bean.Result 9 | import com.king.easychat.bean.User 10 | import com.king.frame.mvvmframe.base.BaseModel 11 | import com.king.frame.mvvmframe.base.DataViewModel 12 | import com.king.frame.mvvmframe.base.livedata.StatusEvent 13 | import com.king.frame.mvvmframe.http.callback.ApiCallback 14 | import retrofit2.Call 15 | import javax.inject.Inject 16 | 17 | /** 18 | * @author Jenly 19 | */ 20 | class GroupMemberViewModel @Inject constructor(application: Application, model: BaseModel?) : DataViewModel(application, model){ 21 | 22 | 23 | val usersLiveData = MutableLiveData>() 24 | lateinit var groupId : String 25 | 26 | fun retry(){ 27 | getGroupMembers(groupId) 28 | } 29 | 30 | /** 31 | * 获取群成员信息 32 | */ 33 | fun getGroupMembers(groupId: String){ 34 | updateStatus(StatusEvent.Status.LOADING) 35 | val token = getApplication().getToken() 36 | mModel.getRetrofitService(ApiService::class.java) 37 | .getGroupMembers(token,groupId) 38 | .enqueue(object : ApiCallback>>(){ 39 | override fun onResponse(call: Call>>?, result: Result>?) { 40 | result?.let { 41 | if(it.isSuccess()){ 42 | updateStatus(StatusEvent.Status.SUCCESS) 43 | usersLiveData.value = it.data 44 | }else{ 45 | sendMessage(it.desc) 46 | updateStatus(StatusEvent.Status.FAILURE) 47 | } 48 | 49 | } ?: run{ 50 | updateStatus(StatusEvent.Status.FAILURE) 51 | sendMessage(R.string.result_failure) 52 | } 53 | } 54 | 55 | override fun onError(call: Call>>?, t: Throwable?) { 56 | updateStatus(StatusEvent.Status.ERROR) 57 | sendMessage(t?.message) 58 | } 59 | 60 | }) 61 | 62 | } 63 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/group/GroupModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.group 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import com.king.easychat.api.ApiService 5 | import com.king.easychat.app.base.MessageModel 6 | import com.king.easychat.bean.Group 7 | import com.king.easychat.bean.Result 8 | import com.king.frame.mvvmframe.bean.Resource 9 | import com.king.frame.mvvmframe.data.IDataRepository 10 | import com.king.frame.mvvmframe.http.callback.ApiCallback 11 | import kotlinx.coroutines.Dispatchers 12 | import kotlinx.coroutines.GlobalScope 13 | import kotlinx.coroutines.launch 14 | import retrofit2.Call 15 | import javax.inject.Inject 16 | 17 | /** 18 | * @author Jenly 19 | */ 20 | class GroupModel @Inject constructor(repository: IDataRepository?): MessageModel(repository){ 21 | 22 | 23 | val groupResource = MutableLiveData>>() 24 | 25 | /** 26 | * 获取群组列表 27 | */ 28 | fun getGroups(token: String){ 29 | groupResource.value = Resource.loading() 30 | getRetrofitService(ApiService::class.java) 31 | .getGroups(token) 32 | .enqueue(object : ApiCallback>>(){ 33 | override fun onResponse(call: Call>>?, result: Result>?) { 34 | result?.let { 35 | if(it.isSuccess()){ 36 | groupResource.value = Resource.success(it.data) 37 | saveGroups(it.data) 38 | return 39 | }else{ 40 | groupResource.value = Resource.failure(result.desc) 41 | } 42 | 43 | } ?: run { 44 | groupResource.value = Resource.failure(null) 45 | } 46 | 47 | 48 | } 49 | 50 | override fun onError(call: Call>>?, t: Throwable?) { 51 | groupResource.value = Resource.error(t) 52 | } 53 | 54 | }) 55 | 56 | } 57 | 58 | fun saveGroups(users: List?){ 59 | users?.let { 60 | GlobalScope.launch(Dispatchers.IO) { 61 | with(getGroupDao()){ 62 | deleteAll() 63 | insert(it) 64 | } 65 | } 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/group/GroupViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.group 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.LiveData 5 | import androidx.lifecycle.MediatorLiveData 6 | import com.king.easychat.App 7 | import com.king.easychat.bean.Group 8 | import com.king.easychat.netty.NettyClient 9 | import com.king.easychat.netty.packet.req.CreateGroupReq 10 | import com.king.frame.mvvmframe.base.BaseViewModel 11 | import com.king.frame.mvvmframe.bean.Resource 12 | import javax.inject.Inject 13 | 14 | /** 15 | * @author Jenly 16 | */ 17 | class GroupViewModel @Inject constructor(application: Application, model: GroupModel?) : BaseViewModel(application, model){ 18 | 19 | var groupsLiveData = MediatorLiveData>() 20 | 21 | var source : LiveData>>? = null 22 | 23 | override fun onCreate() { 24 | super.onCreate() 25 | getGroups() 26 | } 27 | 28 | fun retry(){ 29 | getGroups() 30 | } 31 | 32 | /** 33 | * 获取群组列表 34 | */ 35 | fun getGroups(){ 36 | val token = getApplication().getToken() 37 | mModel.getGroups(token!!) 38 | source?.let { 39 | groupsLiveData.removeSource(it) 40 | } 41 | source = mModel.groupResource 42 | groupsLiveData.addSource(source!!){ 43 | updateStatus(it.status) 44 | if(it.isSuccess){ 45 | groupsLiveData.postValue(it.data) 46 | }else { 47 | if(it.isFailure){ 48 | sendMessage(it.message) 49 | } 50 | groupsLiveData.addSource(mModel.getGroups()){groupsLiveData::postValue} 51 | } 52 | } 53 | 54 | } 55 | 56 | fun createGroup(groupName: String){ 57 | NettyClient.INSTANCE.sendMessage(CreateGroupReq(groupName,null)) 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/photo/PhotoViewActivity.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.photo 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.core.view.ViewCompat 6 | import androidx.viewpager2.widget.ViewPager2 7 | import com.chad.library.adapter.base.BaseQuickAdapter 8 | import com.king.easychat.R 9 | import com.king.easychat.app.Constants 10 | import com.king.easychat.app.adapter.BindingAdapter 11 | import com.king.easychat.app.base.BaseActivity 12 | import com.king.easychat.databinding.PhotoViewActivityBinding 13 | import com.king.frame.mvvmframe.base.DataViewModel 14 | import kotlinx.android.synthetic.main.photo_view_activity.* 15 | 16 | /** 17 | * @author Jenly 18 | */ 19 | class PhotoViewActivity : BaseActivity() { 20 | 21 | var size = 0 22 | 23 | companion object{ 24 | const val IMAGE = "image" 25 | } 26 | 27 | val mAdapter by lazy { BindingAdapter(R.layout.vp_photo_item) } 28 | 29 | override fun initData(savedInstanceState: Bundle?) { 30 | ViewCompat.setTransitionName(vp, IMAGE) 31 | val list = intent.getStringArrayListExtra(Constants.KEY_LIST) 32 | list?.let { 33 | size = it.size 34 | if(it.size>1){ 35 | tvPage.visibility = View.VISIBLE 36 | }else{ 37 | tvPage.visibility = View.GONE 38 | } 39 | 40 | } 41 | vp.adapter = mAdapter 42 | vp.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback(){ 43 | override fun onPageSelected(position: Int) { 44 | super.onPageSelected(position) 45 | updatePage(position+1,size) 46 | } 47 | }) 48 | mAdapter.onItemClickListener = BaseQuickAdapter.OnItemClickListener { adapter, view, position -> onBackPressed() } 49 | mAdapter.replaceData(list) 50 | 51 | } 52 | 53 | 54 | override fun getLayoutId(): Int { 55 | return R.layout.photo_view_activity 56 | } 57 | 58 | private fun updatePage(position: Int,size: Int){ 59 | tvPage.text = "$position/$size" 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/search/SearchViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.search 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.MutableLiveData 5 | import com.king.easychat.App 6 | import com.king.easychat.R 7 | import com.king.easychat.api.ApiService 8 | import com.king.easychat.bean.Result 9 | import com.king.easychat.bean.Search 10 | import com.king.frame.mvvmframe.base.BaseModel 11 | import com.king.frame.mvvmframe.base.DataViewModel 12 | import com.king.frame.mvvmframe.base.livedata.StatusEvent 13 | import com.king.frame.mvvmframe.http.callback.ApiCallback 14 | import retrofit2.Call 15 | import timber.log.Timber 16 | import javax.inject.Inject 17 | 18 | /** 19 | * @author Jenly 20 | */ 21 | class SearchViewModel @Inject constructor(application: Application, model: BaseModel?) : DataViewModel(application,model){ 22 | 23 | val searchsLiveData = MutableLiveData>() 24 | 25 | /** 26 | * 搜索 27 | */ 28 | fun search(keyword: String,curPage: Int,pageSize: Int){ 29 | val token = getApplication().getToken() 30 | updateStatus(StatusEvent.Status.LOADING) 31 | getRetrofitService(ApiService::class.java) 32 | .search(token,keyword,curPage,pageSize) 33 | .enqueue(object : ApiCallback>>(){ 34 | override fun onResponse(call: Call>>?, result: Result>?) { 35 | result?.let { 36 | if(it.isSuccess()){ 37 | updateStatus(StatusEvent.Status.SUCCESS) 38 | searchsLiveData.value = it.data 39 | }else{ 40 | sendMessage(it.desc) 41 | Timber.d(it.desc) 42 | updateStatus(StatusEvent.Status.FAILURE) 43 | } 44 | } ?: run { 45 | updateStatus(StatusEvent.Status.FAILURE) 46 | sendMessage(R.string.result_failure) 47 | } 48 | } 49 | 50 | override fun onError(call: Call>>?, t: Throwable) { 51 | updateStatus(StatusEvent.Status.ERROR) 52 | sendMessage(t.message) 53 | } 54 | 55 | }) 56 | 57 | } 58 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/app/splash/SplashViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.app.splash 2 | 3 | import android.app.Application 4 | import com.king.easychat.netty.NettyClient 5 | import com.king.easychat.netty.packet.req.LoginReq 6 | import com.king.frame.mvvmframe.base.BaseModel 7 | import com.king.frame.mvvmframe.base.DataViewModel 8 | import javax.inject.Inject 9 | 10 | /** 11 | * @author Jenly 12 | */ 13 | class SplashViewModel @Inject constructor(application: Application, model: BaseModel?) : DataViewModel(application, model){ 14 | 15 | 16 | override fun onCreate() { 17 | super.onCreate() 18 | 19 | } 20 | 21 | fun login(loginReq: LoginReq){ 22 | NettyClient.INSTANCE.sendMessage(loginReq) 23 | } 24 | 25 | 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/AppVersion.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | /** 4 | * @author Jenly 5 | */ 6 | class AppVersion { 7 | /** 版本码 */ 8 | val versionCode: Int? = null 9 | /** 版本名称 */ 10 | val versionName: String? = null 11 | /** 版本更新描述 */ 12 | val versionDesc: String? = null 13 | /** 下载链接 */ 14 | val downloadUrl: String? = null 15 | /** 是否强制升级 */ 16 | val isForcedUpgrade: Boolean = false 17 | 18 | /** 发布时间 */ 19 | val releaseTime: String? = null 20 | 21 | override fun toString(): String { 22 | return "AppVersion(versionCode=$versionCode, versionName=$versionName, versionDesc=$versionDesc, downloadUrl=$downloadUrl, isForcedUpgrade=$isForcedUpgrade, releaseTime=$releaseTime)" 23 | } 24 | 25 | 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/Group.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | import android.os.Parcelable 4 | import androidx.room.Entity 5 | import androidx.room.Ignore 6 | import androidx.room.Index 7 | import androidx.room.PrimaryKey 8 | import kotlinx.android.parcel.Parcelize 9 | 10 | 11 | /** 12 | * @author: Zed 13 | * date: 2019/08/22. 14 | * description: 15 | */ 16 | @Entity(indices = [Index(value = ["groupId"], unique = true)]) 17 | @Parcelize 18 | class Group(val groupId: String,var groupName: String,var avatar: String?,var mainUserId: String?) : Parcelable { 19 | 20 | @PrimaryKey(autoGenerate = true) 21 | var id: Int = 0 22 | 23 | @Ignore var memberNum: Int = 0 24 | 25 | fun getMemberNumber(): String{ 26 | return memberNum.toString() 27 | } 28 | 29 | override fun equals(other: Any?): Boolean { 30 | if (this === other) return true 31 | if (javaClass != other?.javaClass) return false 32 | 33 | other as Group 34 | 35 | if (groupId != other.groupId) return false 36 | 37 | return true 38 | } 39 | 40 | override fun hashCode(): Int { 41 | return groupId.hashCode() 42 | } 43 | 44 | override fun toString(): String { 45 | return "Group(groupId='$groupId', groupName='$groupName', avatar=$avatar, mainUserId=$mainUserId, memberNum=$memberNum, id=$id)" 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/GroupMessageDbo.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | import android.os.Parcelable 4 | import androidx.room.Entity 5 | import androidx.room.Index 6 | import androidx.room.PrimaryKey 7 | import com.king.easychat.netty.packet.resp.GroupMessageResp 8 | import kotlinx.android.parcel.Parcelize 9 | 10 | /** 11 | * @author Zed 12 | * date: 2019/10/14. 13 | * description: 14 | */ 15 | @Entity(indices = [Index(value = ["groupId"])]) 16 | @Parcelize 17 | class GroupMessageDbo(val userId : String, val groupId: String, val sender : String, val senderName : String?,var avatar: String?,val message : String, 18 | val send: Boolean = false, val messageType : Int, var dateTime : String,var read: Boolean = false) : Parcelable { 19 | @PrimaryKey(autoGenerate = true) 20 | var id: Long = 0 21 | 22 | fun toGroupMessageResp(): GroupMessageResp { 23 | val resp = GroupMessageResp(sender,senderName,avatar,message,groupId,messageType,userId == sender) 24 | resp.dateTime = dateTime 25 | return resp 26 | } 27 | 28 | override fun toString(): String { 29 | return "GroupMessageDbo(userId='$userId', groupId='$groupId', sender='$sender', senderName=$senderName, avatar=$avatar, message='$message', send=$send, messageType=$messageType, dateTime='$dateTime', read=$read, id=$id)" 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/Message.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | import com.king.base.util.StringUtils 4 | import com.king.easychat.util.AES 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/12. 9 | * description: 消息列表 10 | */ 11 | class Message { 12 | 13 | companion object{ 14 | var userMode = 0 15 | var groupMode = 1 16 | } 17 | 18 | /** 用户id 或者群聊id*/ 19 | var id : String?=null 20 | /** 消息时间 用于排序*/ 21 | var dateTime : String?=null 22 | /** 0 单聊消息 1 群聊消息*/ 23 | var messageMode : Int?=null 24 | 25 | /** 单聊为好友id 群聊为发送者id*/ 26 | var senderId : String?=null 27 | /** 发送的消息内容*/ 28 | var message : String?=null 29 | 30 | /** 0 普通消息 1 图片消息*/ 31 | var messageType : Int?=null 32 | 33 | var name : String? = null 34 | 35 | var avatar: String? = null 36 | 37 | /** 38 | * 未读消息数 39 | */ 40 | var count = 0 41 | 42 | fun getMsg() : String? { 43 | if(messageType ==1){ 44 | return "[图片消息]" 45 | } 46 | message?.let { 47 | return AES.decrypt(it, "${dateTime}ab") 48 | } 49 | return null 50 | } 51 | 52 | fun getShowName(): String?{ 53 | return if(StringUtils.isNotBlank(name)) name else id 54 | } 55 | 56 | override fun toString(): String { 57 | return "Message(id=$id, dateTime=$dateTime, messageMode=$messageMode, senderId=$senderId, message=$message, messageType=$messageType, name=$name, avatar=$avatar, count=$count)" 58 | } 59 | 60 | 61 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/MessageDbo.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | import android.os.Parcelable 4 | import androidx.room.Entity 5 | import androidx.room.Index 6 | import androidx.room.PrimaryKey 7 | import com.king.easychat.netty.packet.resp.MessageResp 8 | import kotlinx.android.parcel.Parcelize 9 | 10 | /** 11 | * @author Zed 12 | * date: 2019/10/14. 13 | * description: 14 | */ 15 | @Entity(indices = [Index(value = ["sender"]), Index(value = ["receiver"])]) 16 | @Parcelize 17 | open class MessageDbo(var userId : String, val sender : String?, val receiver: String? 18 | ,val message : String, val send: Boolean = false 19 | , val messageType : Int, var dateTime : String 20 | ,val senderName : String?,var read: Boolean = false) : Parcelable { 21 | @PrimaryKey(autoGenerate = true) 22 | var id: Long = 0 23 | 24 | fun toMessageResp(): MessageResp{ 25 | var resp = MessageResp(sender,senderName,message,send,messageType) 26 | resp.dateTime = dateTime 27 | return resp 28 | } 29 | 30 | override fun toString(): String { 31 | return "MessageDbo(userId='$userId', sender=$sender, receiver=$receiver, message='$message', send=$send, messageType=$messageType, dateTime='$dateTime', senderName=$senderName, read=$read, id=$id)" 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/Operator.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | import android.os.Parcelable 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @Parcelize 10 | class Operator(val event: Int): Parcelable -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/RecentChat.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | import androidx.room.Entity 4 | import androidx.room.Index 5 | import androidx.room.PrimaryKey 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | @Entity(indices = [Index(value = ["chatId"], unique = true)]) 11 | class RecentChat(val userId: String,val chatId: String,var showName: String?,var avatar: String?,var dateTime: String){ 12 | 13 | @PrimaryKey(autoGenerate = true) 14 | var id: Int = 0 15 | 16 | override fun toString(): String { 17 | return "RecentChat(userId='$userId', chatId='$chatId', showName=$showName, avatar=$avatar, dateTime='$dateTime', id=$id)" 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/RecentGroupChat.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | import androidx.room.Entity 4 | import androidx.room.Index 5 | import androidx.room.PrimaryKey 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | @Entity(indices = [Index(value = ["groupChatId"], unique = true)]) 11 | class RecentGroupChat(val userId: String, var groupChatId: String, var showName: String?, var avatar: String?, var dateTime: String){ 12 | 13 | @PrimaryKey(autoGenerate = true) 14 | var id: Int = 0 15 | 16 | override fun toString(): String { 17 | return "RecentGroupChat(userId='$userId', groupChatId='$groupChatId', showName=$showName, avatar=$avatar, dateTime='$dateTime', id=$id)" 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/Result.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | /** 4 | * @author Jenly 5 | */ 6 | class Result { 7 | 8 | var code : String? = null 9 | 10 | var desc : String? = null 11 | 12 | var data : T? = null 13 | 14 | fun isSuccess(): Boolean{ 15 | return "0" == code 16 | } 17 | 18 | override fun toString(): String { 19 | return "Result(code=$code, desc=$desc, data=$data)" 20 | } 21 | 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/Search.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | import com.king.base.util.StringUtils 4 | 5 | /** 6 | * @author Jenly 7 | */ 8 | class Search { 9 | 10 | companion object{ 11 | const val USER_TYPE = 0 12 | const val GROUP_TYPE = 1 13 | } 14 | 15 | /** 用户id 或者群id */ 16 | var id: String? = null 17 | /** 用户名称或者群名称 */ 18 | var name: String? = null 19 | /** 用户 昵称 */ 20 | var nickName: String? = null 21 | /** 用户图像或者群头像 */ 22 | var avatar: String? = null 23 | /** 类型 0 用户类型 1 群类型 */ 24 | var type: Int = USER_TYPE 25 | 26 | fun getShowName(): String?{ 27 | if(StringUtils.isNotBlank(nickName)){ 28 | return nickName 29 | } 30 | 31 | return name 32 | } 33 | 34 | fun getTypeName(): String?{ 35 | when(type){ 36 | USER_TYPE -> return "用户" 37 | GROUP_TYPE -> return "群组" 38 | } 39 | return "未知" 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/bean/User.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.bean 2 | 3 | import android.os.Parcelable 4 | import androidx.room.Entity 5 | import androidx.room.Index 6 | import kotlinx.android.parcel.Parcelize 7 | import androidx.room.PrimaryKey 8 | 9 | 10 | 11 | 12 | /** 13 | * @author Zed 14 | * date: 2019/10/09. 15 | * description: 16 | */ 17 | @Entity(indices = [Index(value = ["userId"], unique = true)]) 18 | @Parcelize 19 | class User(val userId: String,val userName: String,var nickName: String?,var avatar: String?,var signature: String?, 20 | var remark: String? = null) : Parcelable { 21 | 22 | @PrimaryKey(autoGenerate = true) 23 | var id: Int = 0 24 | 25 | fun getShowName(): String { 26 | remark?.let { 27 | return it 28 | } 29 | nickName?.let { 30 | return it 31 | } 32 | 33 | return userName 34 | } 35 | 36 | override fun toString(): String { 37 | return "User(userId=$userId, userName=$userName, nickName=$nickName, avatar=$avatar, signature=$signature)" 38 | } 39 | 40 | override fun equals(other: Any?): Boolean { 41 | if (this === other) return true 42 | if (javaClass != other?.javaClass) return false 43 | 44 | other as User 45 | 46 | if (userId != other.userId) return false 47 | 48 | return true 49 | } 50 | 51 | override fun hashCode(): Int { 52 | return userId.hashCode() 53 | } 54 | 55 | 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/config/ConfigModule.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.config 2 | 3 | import android.content.Context 4 | import com.king.base.baseurlmanager.BaseUrlManager 5 | import com.king.easychat.app.Constants 6 | import com.king.frame.mvvmframe.config.FrameConfigModule 7 | import com.king.frame.mvvmframe.di.module.ConfigModule 8 | 9 | /** 10 | * @author Jenly 11 | */ 12 | class ConfigModule : FrameConfigModule() { 13 | override fun applyOptions(context: Context, builder: ConfigModule.Builder?) { 14 | if(Constants.isDomain){ 15 | val manager = BaseUrlManager(context) 16 | builder?.baseUrl(Constants.getBaseUrl(manager.baseUrl)) 17 | }else{ 18 | builder?.baseUrl(Constants.BASE_URL) 19 | } 20 | 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/dao/AppDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.dao 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | import com.king.easychat.bean.* 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | @Database(entities = [User::class, Group::class, MessageDbo::class,GroupMessageDbo::class, RecentChat::class,RecentGroupChat::class], version = 1,exportSchema = false) 11 | abstract class AppDatabase : RoomDatabase() { 12 | 13 | abstract fun userDao(): UserDao 14 | abstract fun groupDao(): GroupDao 15 | abstract fun groupMessageDao(): GroupMessageDao 16 | abstract fun messageDao(): MessageDao 17 | 18 | abstract fun recentChatDao(): RecentChatDao 19 | abstract fun recentGroupChatDao(): RecentGroupChatDao 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/dao/GroupDao.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.dao 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.room.* 5 | import com.king.easychat.bean.Group 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | @Dao 11 | interface GroupDao { 12 | 13 | /** 14 | * 插入并去重 15 | */ 16 | @Insert(onConflict = OnConflictStrategy.REPLACE) 17 | fun insert(group: Group) 18 | 19 | @Insert(onConflict = OnConflictStrategy.REPLACE) 20 | fun insert(groups: List) 21 | 22 | @Delete 23 | fun delete(group: Group) 24 | 25 | /** 26 | * 删除所有 27 | */ 28 | @Query("DELETE FROM `group`") 29 | fun deleteAll() 30 | 31 | @Query("DELETE FROM `group` WHERE groupId = :groupId") 32 | fun delete(groupId: String) 33 | 34 | /** 35 | * 查询所有群组列表 36 | */ 37 | @Query("SELECT * FROM `group`") 38 | fun getAllGroups(): LiveData> 39 | 40 | @Query("SELECT * FROM `group`") 41 | fun getGroups(): List 42 | 43 | /** 44 | * 查询群组列表 45 | */ 46 | @Query("SELECT * FROM `group` ORDER BY groupId DESC LIMIT :count") 47 | fun getGroups(count: Int): LiveData> 48 | 49 | /** 50 | * 修改群组 51 | */ 52 | // @Update 53 | // fun updateGroup(group: Group) 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/dao/GroupMessageDao.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.dao 2 | 3 | import androidx.room.* 4 | import com.king.easychat.bean.GroupMessageDbo 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @Dao 10 | interface GroupMessageDao { 11 | /** 12 | * 插入并去重 13 | */ 14 | @Insert(onConflict = OnConflictStrategy.REPLACE) 15 | fun insert(message: GroupMessageDbo) 16 | 17 | @Delete 18 | fun delete(message: GroupMessageDbo) 19 | 20 | /** 21 | * 删除所有 22 | */ 23 | @Query("DELETE FROM GroupMessageDbo") 24 | fun deleteAll() 25 | 26 | /** 27 | * 获取所有的群聊id 28 | */ 29 | @Query("SELECT groupId FROM GroupMessageDbo WHERE userId = :userId GROUP BY groupId") 30 | fun queryAllGroups(userId : String) : List 31 | 32 | /** 33 | * 根据时间倒序查询最近聊天的几个用户 34 | */ 35 | @Query("SELECT * FROM GroupMessageDbo WHERE userId = :userId AND groupId = :groupId order by dateTime desc limit 1") 36 | fun getLastMessageByGroupId(userId : String, groupId: String): GroupMessageDbo? 37 | 38 | /** 39 | * 根据群id获取好友的最近几条聊天记录 40 | */ 41 | @Query("SELECT * FROM GroupMessageDbo WHERE userId = :userId AND groupId = :groupId order by dateTime desc limit :start, :pageSize") 42 | fun getGroupMessageByGroupId(userId : String, groupId : String, start : Int, pageSize : Int) : List 43 | 44 | /** 45 | * 查询未读消息记录数 46 | */ 47 | @Query("SELECT COUNT(*) FROM GroupMessageDbo WHERE userId = :userId AND groupId = :groupId AND read = '0'") 48 | fun getUnreadNumByGroupId(userId : String, groupId : String) : Int 49 | 50 | /** 51 | * 查询未读消息记录数 52 | */ 53 | @Query("SELECT id FROM GroupMessageDbo WHERE userId = :userId AND groupId = :groupId AND read = '0'") 54 | fun getUnreadList(userId : String, groupId : String) : List 55 | 56 | /** 57 | * 更新为已读消息 58 | */ 59 | @Query("UPDATE GroupMessageDbo SET read = '1' WHERE userId =:userId AND groupId = :groupId") 60 | fun updateRead(userId : String, groupId : String) : Int 61 | 62 | /** 63 | * 更新为已读消息 64 | */ 65 | @Query("UPDATE GroupMessageDbo SET read = '1' WHERE userId =:userId") 66 | fun updateRead(userId : String) : Int 67 | 68 | 69 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/dao/MessageDao.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.dao 2 | 3 | import androidx.room.* 4 | import com.king.easychat.bean.MessageDbo 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @Dao 10 | interface MessageDao { 11 | /** 12 | * 插入并去重 13 | */ 14 | @Insert(onConflict = OnConflictStrategy.REPLACE) 15 | fun insert(message: MessageDbo) 16 | 17 | @Delete 18 | fun delete(message: MessageDbo) 19 | 20 | /** 21 | * 删除所有 22 | */ 23 | @Query("DELETE FROM MessageDbo") 24 | fun deleteAll() 25 | 26 | /** 27 | * 获取所有的聊天好友id 28 | */ 29 | @Query("SELECT sender FROM MessageDbo WHERE userId = :userId GROUP BY sender") 30 | fun queryAllFriends(userId : String) : List 31 | 32 | /** 33 | * 根据时间倒序查询最近聊天的几个用户 34 | */ 35 | @Query("SELECT * FROM MessageDbo WHERE userId = :userId AND (sender = :sender OR receiver = :receiver) ORDER BY dateTime DESC LIMIT 1") 36 | fun getLastMessageBySenderId(userId : String, sender: String,receiver: String): MessageDbo? 37 | 38 | /** 39 | * 根据好友id获取好友的最近几条聊天记录 40 | */ 41 | @Query("SELECT * FROM MessageDbo WHERE userId = :userId AND (sender = :senderId OR receiver = :receiver) ORDER BY dateTime DESC LIMIT :start, :pageSize") 42 | fun getMessageBySenderId(userId : String,senderId : String,receiver : String, start : Int, pageSize : Int) : List 43 | 44 | /** 45 | * 查询未读消息记录数 46 | */ 47 | @Query("SELECT COUNT(*) FROM MessageDbo WHERE userId = :userId AND sender = :senderId AND read = '0'") 48 | fun getUnreadNumBySenderId(userId : String, senderId : String) : Int 49 | 50 | /** 51 | * 查询未读消息记录数 52 | */ 53 | @Query("SELECT id FROM MessageDbo WHERE userId = :userId AND sender = :senderId AND read = '0' GROUP BY id") 54 | fun getUnreadList(userId : String, senderId : String) : List 55 | 56 | /** 57 | * 更新为已读消息 58 | */ 59 | @Query("UPDATE MessageDbo SET read = '1' WHERE userId =:userId AND (sender = :senderId OR receiver = :receiver)") 60 | fun updateRead(userId : String, senderId : String,receiver : String) : Int 61 | 62 | /** 63 | * 更新为已读消息 64 | */ 65 | @Query("UPDATE MessageDbo SET read = '1' WHERE userId =:userId") 66 | fun updateRead(userId : String) : Int 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/dao/RecentChatDao.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.dao 2 | 3 | import androidx.room.* 4 | import com.king.easychat.bean.RecentChat 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @Dao 10 | interface RecentChatDao { 11 | 12 | @Insert(onConflict = OnConflictStrategy.REPLACE) 13 | fun insert(data: RecentChat) 14 | 15 | @Query("DELETE FROM RecentChat WHERE userId = :userId AND chatId = :chatId") 16 | fun delete(userId: String,chatId: String) 17 | 18 | @Query("DELETE FROM RecentChat WHERE userId = :userId") 19 | fun delete(userId: String) 20 | 21 | 22 | @Query("SELECT * FROM RecentChat WHERE userId = :userId") 23 | fun getRecentChats(userId: String): List 24 | 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/dao/RecentGroupChatDao.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.dao 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Insert 5 | import androidx.room.OnConflictStrategy 6 | import androidx.room.Query 7 | import com.king.easychat.bean.RecentGroupChat 8 | 9 | /** 10 | * @author Jenly 11 | */ 12 | @Dao 13 | interface RecentGroupChatDao { 14 | 15 | @Insert(onConflict = OnConflictStrategy.REPLACE) 16 | fun insert(data: RecentGroupChat) 17 | 18 | @Query("DELETE FROM RecentGroupChat WHERE userId = :userId AND groupChatId = :groupChatId") 19 | fun delete(userId: String,groupChatId: String) 20 | 21 | @Query("DELETE FROM RecentGroupChat WHERE userId = :userId") 22 | fun delete(userId: String) 23 | 24 | @Query("SELECT * FROM RecentGroupChat WHERE userId = :userId") 25 | fun getRecentGroupChats(userId: String): List 26 | 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/dao/UserDao.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.dao 2 | 3 | import androidx.room.* 4 | import com.king.easychat.bean.User 5 | import androidx.lifecycle.LiveData 6 | 7 | 8 | 9 | /** 10 | * @author Jenly 11 | */ 12 | @Dao 13 | interface UserDao { 14 | 15 | /** 16 | * 插入并去重 17 | */ 18 | @Insert(onConflict = OnConflictStrategy.REPLACE) 19 | fun insert(user: User) 20 | 21 | @Insert(onConflict = OnConflictStrategy.REPLACE) 22 | fun insert(users: List) 23 | 24 | @Delete 25 | fun delete(user: User) 26 | 27 | /** 28 | * 删除所有 29 | */ 30 | @Query("DELETE FROM User") 31 | fun deleteAll() 32 | 33 | @Query("DELETE FROM User WHERE userId = :userId") 34 | fun delete(userId: String) 35 | 36 | /** 37 | * 查询所有用户列表 38 | */ 39 | @Query("SELECT * FROM User") 40 | fun getAllUsers(): LiveData> 41 | 42 | @Query("SELECT * FROM User") 43 | fun getUsers(): List 44 | 45 | /** 46 | * 查询用户列表 47 | */ 48 | @Query("SELECT * FROM User ORDER BY userId DESC LIMIT :count") 49 | fun getUsers(count: Int): LiveData> 50 | 51 | /** 52 | * 修改用户 53 | */ 54 | // @Update 55 | // fun updateUser(user: User) 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/di/component/ApplicationComponent.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.di.component 2 | 3 | import com.king.easychat.App 4 | import com.king.easychat.di.module.ApplicationModule 5 | import com.king.frame.mvvmframe.di.component.AppComponent 6 | import com.king.frame.mvvmframe.di.scope.ApplicationScope 7 | import dagger.Component 8 | 9 | /** 10 | * @author Jenly 11 | */ 12 | @ApplicationScope 13 | @Component(dependencies = [AppComponent::class], modules = [ApplicationModule::class]) 14 | interface ApplicationComponent { 15 | 16 | fun inject(app: App) 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/di/module/ApplicationModule.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.di.module 2 | 3 | import com.king.frame.mvvmframe.di.module.ViewModelFactoryModule 4 | import dagger.Module 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @Module(includes = [ViewModelFactoryModule::class,ViewModelModule::class,ActivityModule::class,FragmentModule::class]) 10 | class ApplicationModule { 11 | 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/di/module/FragmentModule.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.di.module 2 | 3 | import com.king.easychat.app.friend.FriendFragment 4 | import com.king.easychat.app.group.GroupFragment 5 | import com.king.easychat.app.home.HomeFragment 6 | import com.king.easychat.app.me.MeFragment 7 | import com.king.easychat.temp.TempFragment 8 | import com.king.frame.mvvmframe.di.component.BaseFragmentSubcomponent 9 | import dagger.Module 10 | import dagger.android.ContributesAndroidInjector 11 | 12 | /** 13 | * @author Jenly 14 | */ 15 | @Module(subcomponents = [BaseFragmentSubcomponent::class]) 16 | abstract class FragmentModule { 17 | 18 | @ContributesAndroidInjector 19 | abstract fun contributeTempFragment(): TempFragment 20 | 21 | @ContributesAndroidInjector 22 | abstract fun contributeHomeFragment(): HomeFragment 23 | 24 | @ContributesAndroidInjector 25 | abstract fun contributeFriendFragment(): FriendFragment 26 | 27 | @ContributesAndroidInjector 28 | abstract fun contributeGroupFragment(): GroupFragment 29 | 30 | @ContributesAndroidInjector 31 | abstract fun contributeMeFragment(): MeFragment 32 | 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/glide/GlideModule.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.glide 2 | 3 | import android.content.Context 4 | import com.bumptech.glide.GlideBuilder 5 | import com.bumptech.glide.annotation.GlideModule 6 | import com.bumptech.glide.load.engine.DiskCacheStrategy 7 | import com.bumptech.glide.module.AppGlideModule 8 | import com.bumptech.glide.request.RequestOptions 9 | 10 | /** 11 | * @author Jenly 12 | */ 13 | @GlideModule 14 | class GlideModule : AppGlideModule(){ 15 | 16 | override fun applyOptions(context: Context, builder: GlideBuilder) { 17 | super.applyOptions(context, builder) 18 | builder.setDefaultRequestOptions(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.RESOURCE)) 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/glide/ImageLoader.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.glide 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.widget.ImageView 6 | import androidx.fragment.app.Fragment 7 | 8 | /** 9 | * @author Jenly 10 | */ 11 | object ImageLoader { 12 | 13 | 14 | fun displayImage(iv: ImageView,url: String?,defaultImage: Int){ 15 | url?.let { 16 | GlideApp.with(iv).load(url).error(defaultImage).into(iv) 17 | } ?: run { 18 | iv.setImageResource(defaultImage) 19 | } 20 | } 21 | 22 | fun displayImage(context: Context,iv: ImageView,url: String?,defaultImage: Int){ 23 | url?.let { 24 | GlideApp.with(context).load(url).error(defaultImage).into(iv) 25 | } ?: run { 26 | iv.setImageResource(defaultImage) 27 | } 28 | } 29 | 30 | fun displayImage(fragment: Fragment,iv: ImageView,url: String?,defaultImage: Int){ 31 | url?.let { 32 | GlideApp.with(fragment).load(url).error(defaultImage).into(iv) 33 | } ?: run { 34 | iv.setImageResource(defaultImage) 35 | } 36 | } 37 | 38 | fun displayImage(activity: Activity,iv: ImageView,url: String?,defaultImage: Int){ 39 | url?.let { 40 | GlideApp.with(activity).load(url).error(defaultImage).into(iv) 41 | } ?: run { 42 | iv.setImageResource(defaultImage) 43 | } 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/ChannelInitial.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty 2 | 3 | import com.king.easychat.netty.codec.PacketDecoder 4 | import com.king.easychat.netty.codec.PacketEncoder 5 | import com.king.easychat.netty.codec.Spliter 6 | import com.king.easychat.netty.handle.* 7 | import io.netty.channel.ChannelInitializer 8 | import io.netty.channel.socket.SocketChannel 9 | 10 | /** 11 | * @author Jenly 12 | */ 13 | class ChannelInitial : ChannelInitializer(){ 14 | 15 | override fun initChannel(ch: SocketChannel?) { 16 | ch?.pipeline()?.let { 17 | it.addLast(Spliter()) 18 | .addLast(PacketDecoder()) 19 | .addLast(PacketEncoder()) 20 | .addLast(LoginRespHandler()) 21 | .addLast(MessageRespHandler()) 22 | .addLast(MessageSelfRespHandler()) 23 | .addLast(GroupMessageRespHandler()) 24 | .addLast(HeartBeatRespHandler()) 25 | .addLast(AddUserRespHandler()) 26 | .addLast(AddUserSelfRespHandler()) 27 | .addLast(AcceptRespHandler()) 28 | .addLast(CreateGroupRespHandler()) 29 | .addLast(InviteGroupRespHandler()) 30 | .addLast(InviteGroupSelfRespHandler()) 31 | .addLast(AcceptGroupRespHandler()) 32 | .addLast(ApplyGroupRespHandler()) 33 | .addLast(ApplyGroupSelfRespHandler()) 34 | .addLast(AllowGroupRespHandler()) 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/codec/PacketDecoder.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.codec 2 | 3 | import io.netty.buffer.ByteBuf 4 | import io.netty.channel.ChannelHandlerContext 5 | import io.netty.handler.codec.ByteToMessageDecoder 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | class PacketDecoder : ByteToMessageDecoder() { 11 | 12 | override fun decode(ctx: ChannelHandlerContext?, byteBuf: ByteBuf?, out: MutableList?) { 13 | 14 | byteBuf?.let { 15 | out?.add(PacketHelper.decode(it)) 16 | } 17 | 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/codec/PacketEncoder.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.codec 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import io.netty.buffer.ByteBuf 5 | import io.netty.channel.ChannelHandlerContext 6 | import io.netty.handler.codec.MessageToByteEncoder 7 | 8 | /** 9 | * @author Jenly 10 | */ 11 | class PacketEncoder : MessageToByteEncoder() { 12 | 13 | @ExperimentalStdlibApi 14 | override fun encode(ctx: ChannelHandlerContext?, msg: Packet?, out: ByteBuf?) { 15 | out?.let { 16 | msg?.run { 17 | PacketHelper.encode(it,this) 18 | } 19 | } 20 | 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/codec/Spliter.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.codec 2 | 3 | import io.netty.buffer.ByteBuf 4 | import io.netty.channel.ChannelHandlerContext 5 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | class Spliter : LengthFieldBasedFrameDecoder(Int.MAX_VALUE,LENGTH_FIELD_OFFSET,LENGTH_FIELD_LENGTH) { 11 | 12 | companion object{ 13 | const val LENGTH_FIELD_OFFSET = 7 14 | const val LENGTH_FIELD_LENGTH = 4 15 | } 16 | 17 | override fun decode(ctx: ChannelHandlerContext?, byteBuf: ByteBuf): Any { 18 | 19 | val magicNumber = byteBuf.getInt(byteBuf.readerIndex()) 20 | //如果魔数不匹配则直接关闭通道 21 | if(magicNumber != PacketHelper.MAGIC_NUMBER){ 22 | ctx?.channel()?.close() 23 | } 24 | 25 | return super.decode(ctx, byteBuf) 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/AcceptGroupRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.AcceptGroupResp 4 | import com.king.easychat.netty.packet.resp.GroupMessageResp 5 | import com.king.easychat.netty.packet.resp.MessageResp 6 | import io.netty.channel.ChannelHandler 7 | 8 | /** 9 | * @author Zed 10 | * date: 2019/10/12. 11 | * description: 12 | */ 13 | @ChannelHandler.Sharable 14 | class AcceptGroupRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/AcceptRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.AcceptResp 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/12. 9 | * description: 10 | */ 11 | @ChannelHandler.Sharable 12 | class AcceptRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/AddUserRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.* 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/12. 9 | * description: 10 | */ 11 | @ChannelHandler.Sharable 12 | class AddUserRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/AddUserSelfRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.* 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/12. 9 | * description: 10 | */ 11 | @ChannelHandler.Sharable 12 | class AddUserSelfRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/AllowGroupRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.AllowGroupResp 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @ChannelHandler.Sharable 10 | class AllowGroupRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/ApplyGroupRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.ApplyGroupResp 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @ChannelHandler.Sharable 10 | class ApplyGroupRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/ApplyGroupSelfRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.ApplyGroupSelfResp 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @ChannelHandler.Sharable 10 | class ApplyGroupSelfRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/CreateGroupRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.* 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/12. 9 | * description: 10 | */ 11 | @ChannelHandler.Sharable 12 | class CreateGroupRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/GroupMessageRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.GroupMessageResp 4 | import com.king.easychat.netty.packet.resp.MessageResp 5 | import io.netty.channel.ChannelHandler 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | @ChannelHandler.Sharable 11 | class GroupMessageRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/HeartBeatRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.HeartBeatResp 4 | import com.king.easychat.netty.packet.resp.MessageResp 5 | import io.netty.channel.ChannelHandler 6 | import io.netty.channel.ChannelHandlerContext 7 | import timber.log.Timber 8 | 9 | /** 10 | * @author Jenly 11 | */ 12 | @ChannelHandler.Sharable 13 | class HeartBeatRespHandler : RespHandler(){ 14 | // override fun channelRead0(ctx: ChannelHandlerContext?, msg: HeartBeatResp) { 15 | // Timber.d(msg.toString()) 16 | // } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/InviteGroupRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.* 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/12. 9 | * description: 10 | */ 11 | @ChannelHandler.Sharable 12 | class InviteGroupRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/InviteGroupSelfRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.* 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/12. 9 | * description: 10 | */ 11 | @ChannelHandler.Sharable 12 | class InviteGroupSelfRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/LoginRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.LoginResp 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @ChannelHandler.Sharable 10 | class LoginRespHandler : RespHandler() 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/MessageRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.MessageResp 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | @ChannelHandler.Sharable 10 | class MessageRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/MessageSelfRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.* 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/12. 9 | * description: 10 | */ 11 | @ChannelHandler.Sharable 12 | class MessageSelfRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/RegisterRespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.netty.packet.resp.* 4 | import io.netty.channel.ChannelHandler 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/12. 9 | * description: 10 | */ 11 | @ChannelHandler.Sharable 12 | class RegisterRespHandler : RespHandler() -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/handle/RespHandler.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.handle 2 | 3 | import com.king.easychat.app.Constants 4 | import com.king.easychat.bean.Operator 5 | import com.king.easychat.util.Event 6 | import io.netty.channel.ChannelHandlerContext 7 | import io.netty.channel.SimpleChannelInboundHandler 8 | import timber.log.Timber 9 | 10 | /** 11 | * @author Jenly 12 | */ 13 | open class RespHandler : SimpleChannelInboundHandler(){ 14 | override fun channelRead0(ctx: ChannelHandlerContext?, msg: T) { 15 | Timber.d(msg.toString()) 16 | Event.sendEvent(msg) 17 | 18 | if(!ctx?.channel()!!.isActive){ 19 | Event.sendEvent(Operator(Constants.EVENT_NETTY_DISCONNECT)) 20 | } 21 | } 22 | 23 | } 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/MessageType.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet 2 | 3 | /** 4 | * @author Jenly 5 | */ 6 | object MessageType { 7 | const val TEXT = 0 8 | const val IMAGE = 1 9 | 10 | 11 | const val NORMAL = 100 12 | 13 | const val HEART = 101 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/Packet.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet 2 | 3 | import com.king.base.util.TimeUtils 4 | 5 | /** 6 | * @author Jenly 7 | */ 8 | abstract class Packet { 9 | 10 | constructor(): this(TimeUtils.formatDate(System.currentTimeMillis(),TimeUtils.FORMAT_Y_TO_S)) 11 | 12 | constructor(dateTime: String){ 13 | this.dateTime = dateTime 14 | } 15 | 16 | var version = 1 17 | 18 | var dateTime : String 19 | 20 | abstract fun packetType(): Int 21 | 22 | 23 | override fun toString(): String { 24 | return "Packet(version=$version, dateTime='$dateTime')" 25 | } 26 | 27 | 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/PacketType.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet 2 | 3 | /** 4 | * @author Jenly 5 | */ 6 | object PacketType { 7 | 8 | const val LOGIN_REQ = 1 9 | const val LOGIN_RESP = 2 10 | 11 | const val LOGOUT_REQ = 3 12 | const val LOGOUT_RESP = 4 13 | 14 | const val SEND_MESSAGE_REQ = 5 15 | const val SEND_MESSAGE_RESP = 6 16 | 17 | const val ADD_FRIEND_REQ = 7 18 | const val ADD_FRIEND_RESP = 8 19 | const val ADD_USER_SELF_RESP = 9 20 | const val CREATE_GROUP_REQ = 10 21 | const val CREATE_GROUP_RESP = 11 22 | const val INVITE_GROUP_REQ = 12 23 | const val INVITE_GROUP_RESP = 13 24 | const val INVITE_GROUP_SELF_RESP = 14 25 | const val GROUP_MESSAGE_REQ = 15 26 | const val GROUP_MESSAGE_RESP = 16 27 | const val ACCEPT_GROUP_REQ = 17 28 | const val ACCEPT_GROUP_RESP = 18 29 | const val ACCEPT_REQ = 19 30 | const val ACCEPT_RESP = 20 31 | const val REGISTER_REQ = 21 32 | const val REGISTER_RESP = 22 33 | const val UPDATE_PASSWD_REQ = 23 34 | const val UPDATE_PASSWD_RESP = 24 35 | const val MESSAGE_SELF_RESP = 25 36 | const val HEART_BEAT_REQ = 26 37 | const val HEART_BEAT_RESP = 27 38 | const val SYNC_MESSAGE_REQ = 28 39 | const val APPLY_GROUP_REQ = 29 40 | const val APPLY_GROUP_RESP = 30 41 | const val APPLY_GROUP_SELF_RESP = 31 42 | const val ALLOW_GROUP_REQ = 32 43 | const val ALLOW_GROUP_RESP = 33 44 | 45 | 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/AcceptGroupReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/09. 9 | * description: 10 | */ 11 | class AcceptGroupReq(val groupId : String, val inviterId : String, val accept : Boolean) : Packet() { 12 | override fun packetType(): Int { 13 | return PacketType.ACCEPT_GROUP_REQ 14 | } 15 | 16 | override fun toString(): String { 17 | return "AcceptGroupReq(groupId='$groupId', inviterId='$inviterId', accept=$accept)" 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/AcceptReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/09. 9 | * description: 10 | */ 11 | class AcceptReq(val receiver : String, val accept : Boolean) : Packet() { 12 | override fun packetType(): Int { 13 | return PacketType.ACCEPT_REQ 14 | } 15 | 16 | override fun toString(): String { 17 | return "AcceptReq(receiver='$receiver', accept=$accept)" 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/AddUserReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/09. 9 | * description: 10 | */ 11 | class AddUserReq(val addUserId : String) : Packet(){ 12 | override fun packetType(): Int { 13 | return PacketType.ADD_FRIEND_REQ 14 | } 15 | 16 | override fun toString(): String { 17 | return "AddUserReq(addUserId='$addUserId')" 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/AllowGroupReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | class AllowGroupReq(val groupId: String,val userId: String,val allow: Boolean) : Packet(){ 10 | 11 | override fun packetType(): Int { 12 | return PacketType.ALLOW_GROUP_REQ 13 | } 14 | 15 | override fun toString(): String { 16 | return "AllowGroupReq(groupId='$groupId', userId='$userId', allow=$allow)" 17 | } 18 | 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/ApplyGroupReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | class ApplyGroupReq(val groupId: String) : Packet(){ 10 | override fun packetType(): Int { 11 | return PacketType.APPLY_GROUP_REQ 12 | } 13 | 14 | override fun toString(): String { 15 | return "ApplyGroupReq(groupId='$groupId')" 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/CreateGroupReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/09. 9 | * description: 10 | */ 11 | class CreateGroupReq(val groupName : String, val users : List?) : Packet(){ 12 | override fun packetType(): Int { 13 | return PacketType.CREATE_GROUP_REQ 14 | } 15 | 16 | override fun toString(): String { 17 | return "CreateGroupReq(groupName='$groupName', users=$users)" 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/GroupMessageReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.google.gson.annotations.Expose 4 | import com.king.easychat.netty.packet.Packet 5 | import com.king.easychat.netty.packet.PacketType 6 | import com.king.easychat.netty.packet.resp.GroupMessageResp 7 | import com.king.easychat.netty.packet.resp.LoginResp 8 | import com.king.easychat.util.AES 9 | 10 | /** 11 | * @author Zed 12 | * date: 2019/10/09. 13 | * description: 14 | */ 15 | class GroupMessageReq(val groupId : String, @Expose val msg : String, var messageType : Int) : Packet(){ 16 | 17 | val message = AES.encrypt(msg,"${dateTime}ab").toString() 18 | 19 | override fun packetType(): Int { 20 | return PacketType.GROUP_MESSAGE_REQ 21 | } 22 | 23 | fun toGroupMessageResp(userId: String,userName: String?,avatar: String?, isSender: Boolean): GroupMessageResp { 24 | val data = GroupMessageResp(userId,userName,avatar,message,groupId,messageType,isSender) 25 | data.dateTime = dateTime 26 | return data 27 | } 28 | 29 | fun toGroupMessageResp(loginResp: LoginResp?,avatar: String?, isSender: Boolean): GroupMessageResp { 30 | val data = GroupMessageResp(loginResp?.userId!!,loginResp?.userName,avatar,message,groupId,messageType,isSender) 31 | data.dateTime = dateTime 32 | return data 33 | } 34 | 35 | override fun toString(): String { 36 | return "GroupMessageReq(groupId='$groupId', msg='$msg', messageType=$messageType, message='$message')" 37 | } 38 | 39 | 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/HeartBeatReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/09. 9 | * description: 10 | */ 11 | class HeartBeatReq : Packet(){ 12 | override fun packetType(): Int { 13 | return PacketType.HEART_BEAT_REQ 14 | } 15 | 16 | override fun toString(): String { 17 | return "HeartBeatReq(packetType=PacketType.HEART_BEAT_REQ) ${super.toString()}" 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/InviteGroupReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/09. 9 | * description: 10 | */ 11 | class InviteGroupReq(val groupId : String, val users : List) : Packet(){ 12 | override fun packetType(): Int { 13 | return PacketType.INVITE_GROUP_REQ 14 | } 15 | 16 | override fun toString(): String { 17 | return "InviteGroupReq(groupId='$groupId', users=$users)" 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/LoginReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import android.os.Parcelable 4 | import com.king.easychat.netty.packet.Packet 5 | import com.king.easychat.netty.packet.PacketType 6 | import kotlinx.android.parcel.Parcelize 7 | 8 | /** 9 | * @author Jenly 10 | */ 11 | @Parcelize 12 | data class LoginReq(var token: String?,val userName: String?,val password: String?, val sendCacheMessage: Boolean = false) : Packet(), Parcelable { 13 | 14 | 15 | override fun packetType(): Int { 16 | return PacketType.LOGIN_REQ 17 | } 18 | 19 | override fun toString(): String { 20 | return "LoginReq(token='$token', userName='$userName', password='$password', sendCacheMessage=$sendCacheMessage)" 21 | } 22 | 23 | 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/LogoutReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/09. 9 | * description: 10 | */ 11 | class LogoutReq : Packet() { 12 | 13 | override fun packetType(): Int { 14 | return PacketType.LOGOUT_REQ 15 | } 16 | 17 | override fun toString(): String { 18 | return "LogoutReq(PacketType.LOGOUT_REQ)" 19 | } 20 | 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/MessageReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.google.gson.annotations.Expose 4 | import com.king.easychat.netty.packet.Packet 5 | import com.king.easychat.netty.packet.PacketType 6 | import com.king.easychat.netty.packet.resp.LoginResp 7 | import com.king.easychat.netty.packet.resp.MessageResp 8 | import com.king.easychat.util.AES 9 | 10 | /** 11 | * @author Zed 12 | * date: 2019/10/09. 13 | * description: 14 | */ 15 | class MessageReq(val receiver : String,@Expose val msg : String, val messageType : Int = 0) : Packet(){ 16 | 17 | val message = AES.encrypt(msg,"${dateTime}ab").toString() 18 | 19 | override fun packetType(): Int { 20 | return PacketType.SEND_MESSAGE_REQ 21 | } 22 | 23 | fun toMessageResp(userId: String?,userName: String?,isSender: Boolean): MessageResp{ 24 | val data = MessageResp(userId,userName,message,isSender,messageType) 25 | data.dateTime = dateTime 26 | return data 27 | } 28 | 29 | fun toMessageResp(loginResp: LoginResp?,isSender: Boolean): MessageResp{ 30 | val data = MessageResp(loginResp?.userId,loginResp?.userName,message,isSender,messageType) 31 | data.dateTime = dateTime 32 | return data 33 | } 34 | 35 | 36 | override fun toString(): String { 37 | return "MessageReq(receiver='$receiver', msg='$msg', message='$message') ${super.toString()}" 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/RegisterReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/09. 9 | * description: 10 | */ 11 | class RegisterReq(val userName: String, val password: String,val login: Boolean = true) : Packet() { 12 | 13 | override fun packetType(): Int { 14 | return PacketType.REGISTER_REQ 15 | } 16 | 17 | override fun toString(): String { 18 | return "RegisterReq(userName='$userName', password='$password', login=$login)" 19 | } 20 | 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/SyncMessageReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | class SyncMessageReq : Packet(){ 10 | 11 | override fun packetType(): Int { 12 | return PacketType.SYNC_MESSAGE_REQ 13 | } 14 | 15 | override fun toString(): String { 16 | return "SyncMessageReq(PacketType.SYNC_MESSAGE_REQ)" 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/req/UpdatePasswdReq.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.req 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/10/09. 9 | * description: 10 | */ 11 | class UpdatePasswdReq(val oldPassword: String, val newPassword: String) : Packet() { 12 | 13 | override fun packetType(): Int { 14 | return PacketType.UPDATE_PASSWD_REQ 15 | } 16 | 17 | override fun toString(): String { 18 | return "UpdatePasswdReq(oldPassword='$oldPassword', newPassword='$newPassword')" 19 | } 20 | 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/AcceptGroupResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class AcceptGroupResp(val acceptUser: String, val groupId: String, val success: Boolean) : Packet() { 12 | override fun packetType(): Int { 13 | return PacketType.ACCEPT_GROUP_RESP 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/AcceptResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class AcceptResp(val inviterId: String, val invitedId: String,val invitedName: String, val success: Boolean) : Packet() { 12 | override fun packetType(): Int { 13 | return PacketType.ACCEPT_RESP 14 | } 15 | 16 | override fun toString(): String { 17 | return "AcceptResp(inviterId='$inviterId', invitedId='$invitedId', invitedName='$invitedName', success=$success)" 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/AddUserResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class AddUserResp(val inviterId: String,val inviterName: String) : Packet() { 12 | override fun packetType(): Int { 13 | return PacketType.ADD_FRIEND_RESP 14 | } 15 | 16 | override fun toString(): String { 17 | return "AddUserResp(inviterId='$inviterId', inviterName='$inviterName')" 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/AddUserSelfResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class AddUserSelfResp(val inviterId: String, val reason: String, val success: Boolean) : Packet() { 12 | override fun packetType(): Int { 13 | return PacketType.ADD_USER_SELF_RESP 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/AllowGroupResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | class AllowGroupResp(val groupId: String,val allow: Boolean) : Packet(){ 10 | 11 | override fun packetType(): Int { 12 | return PacketType.ALLOW_GROUP_RESP 13 | } 14 | 15 | override fun toString(): String { 16 | return "AllowGroupResp(groupId='$groupId', allow=$allow)" 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/ApplyGroupResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | class ApplyGroupResp(val applyUserId: String,val applyUserName: String,val groupId: String,val groupName: String) : Packet(){ 10 | 11 | override fun packetType(): Int { 12 | return PacketType.APPLY_GROUP_RESP 13 | } 14 | 15 | override fun toString(): String { 16 | return "ApplyGroupResp(applyUserId='$applyUserId', applyUserName='$applyUserName', groupId='$groupId')" 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/ApplyGroupSelfResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | class ApplyGroupSelfResp(val groupId: String,var reason: String?,val success: Boolean) : Packet(){ 10 | 11 | override fun packetType(): Int { 12 | return PacketType.APPLY_GROUP_SELF_RESP 13 | } 14 | 15 | override fun toString(): String { 16 | return "ApplyGroupSelfResp(groupId='$groupId', reason=$reason, success=$success)" 17 | } 18 | 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/CreateGroupResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class CreateGroupResp(val groupName : String, val groupId: String, val reason: String, val success: Boolean) : Packet() { 12 | override fun packetType(): Int { 13 | return PacketType.CREATE_GROUP_RESP 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/GroupMessageResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import android.os.Parcelable 4 | import androidx.room.Entity 5 | import androidx.room.Ignore 6 | import androidx.room.Index 7 | import androidx.room.PrimaryKey 8 | import com.chad.library.adapter.base.entity.MultiItemEntity 9 | import com.king.easychat.bean.GroupMessageDbo 10 | import com.king.easychat.bean.MessageDbo 11 | import com.king.easychat.netty.packet.MessageType 12 | import com.king.easychat.netty.packet.Packet 13 | import com.king.easychat.netty.packet.PacketType 14 | import com.king.easychat.util.AES 15 | import kotlinx.android.parcel.Parcelize 16 | 17 | /** 18 | * @author Zed 19 | * date: 2019/08/19. 20 | * description: 21 | */ 22 | @Parcelize 23 | class GroupMessageResp(val senderId : String,val senderName : String?,var avatar: String?,val message : String,val groupId: String, val messageType : Int, val isSender: Boolean = false) : Packet(), MultiItemEntity, 24 | Parcelable { 25 | 26 | @PrimaryKey(autoGenerate = true) 27 | var id: Int = 0 28 | 29 | companion object{ 30 | const val Left = 1 31 | const val Right = 2 32 | } 33 | 34 | @Ignore 35 | override fun getItemType(): Int { 36 | return if(isSender) Right else Left 37 | } 38 | 39 | // @Expose val msg = AES.decrypt(message,dateTime + "ab").toString() 40 | 41 | override fun packetType(): Int { 42 | return PacketType.GROUP_MESSAGE_RESP 43 | } 44 | 45 | fun getMsg(): String?{ 46 | return AES.decrypt(message,"${dateTime}ab") 47 | } 48 | 49 | override fun toString(): String { 50 | return "GroupMessageResp(senderId='$senderId', senderName='$senderName', message='$message', msg='${getMsg()}', groupId='$groupId') ${super.toString()}" 51 | } 52 | 53 | fun isSelf(self: String): Boolean{ 54 | return self == senderId 55 | } 56 | 57 | 58 | fun toGroupMessageDbo(userId: String,read: Boolean): GroupMessageDbo{ 59 | val data = GroupMessageDbo(userId,groupId,senderId,senderName,avatar,message,isSender,messageType,dateTime,read) 60 | data.dateTime = dateTime 61 | return data 62 | } 63 | 64 | fun isImage():Boolean{ 65 | return messageType == MessageType.IMAGE 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/HeartBeatResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class HeartBeatResp : Packet() { 12 | override fun packetType(): Int { 13 | return PacketType.HEART_BEAT_RESP 14 | } 15 | 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/InviteGroupResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class InviteGroupResp : Packet() { 12 | /** 群名 */ 13 | val groupName: String? = null 14 | /** 群Id */ 15 | val groupId: String? = null 16 | /** 邀请方id */ 17 | val inviteId: String? = null 18 | 19 | override fun packetType(): Int { 20 | return PacketType.INVITE_GROUP_RESP 21 | } 22 | 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/InviteGroupSelfResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class InviteGroupSelfResp : Packet() { 12 | /** 发出邀请成功用户 */ 13 | val successUser: List? = null 14 | val failedUser: List? = null 15 | /** 群名 */ 16 | val groupName: String? = null 17 | /** 群Id */ 18 | val groupId: String? = null 19 | 20 | override fun packetType(): Int { 21 | return PacketType.INVITE_GROUP_SELF_RESP 22 | } 23 | 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/LoginResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | open class LoginResp(val userId: String,val userName: String,val token: String,val success: Boolean,val reason: String = "") : Packet() { 10 | 11 | 12 | override fun packetType(): Int { 13 | return PacketType.LOGIN_RESP 14 | } 15 | 16 | override fun toString(): String { 17 | return "LoginResp(userId='$userId', userName='$userName', token='$token', success=$success, reason='$reason')" 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/LogoutResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class LogoutResp : Packet() { 12 | 13 | override fun packetType(): Int { 14 | return PacketType.LOGOUT_RESP 15 | } 16 | 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/MessageResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import android.os.Parcelable 4 | import androidx.room.Entity 5 | import androidx.room.Index 6 | import androidx.room.PrimaryKey 7 | import com.chad.library.adapter.base.entity.MultiItemEntity 8 | import com.king.easychat.bean.MessageDbo 9 | import com.king.easychat.bean.RecentChat 10 | import com.king.easychat.netty.packet.MessageType 11 | import com.king.easychat.netty.packet.Packet 12 | import com.king.easychat.netty.packet.PacketType 13 | import com.king.easychat.util.AES 14 | import kotlinx.android.parcel.IgnoredOnParcel 15 | import kotlinx.android.parcel.Parcelize 16 | 17 | /** 18 | * @author Zed 19 | * date: 2019/08/19. 20 | * description: 21 | */ 22 | @Parcelize 23 | class MessageResp(val sender : String?,val senderName : String?,val message : String, val isSender: Boolean = false, val messageType : Int) : Packet(), MultiItemEntity, 24 | Parcelable { 25 | 26 | @PrimaryKey(autoGenerate = true) 27 | var id: Int = 0 28 | 29 | companion object{ 30 | const val Left = 1 31 | const val Right = 2 32 | } 33 | 34 | override fun getItemType(): Int { 35 | return if(isSender) Right else Left 36 | } 37 | 38 | // @Expose val msg = AES.decrypt(message,dateTime + "ab").toString() 39 | 40 | override fun packetType(): Int { 41 | return PacketType.SEND_MESSAGE_RESP 42 | } 43 | 44 | fun getMsg(): String?{ 45 | return AES.decrypt(message,"${dateTime}ab") 46 | } 47 | 48 | override fun toString(): String { 49 | return "MessageResp(sender='$sender', senderName='$senderName', message='$message', msg='${getMsg()}') ${super.toString()}" 50 | } 51 | 52 | fun isSelf(self: String): Boolean{ 53 | return self == sender 54 | } 55 | 56 | 57 | fun toMessageDbo(userId: String,friendId: String?,read: Boolean): MessageDbo{ 58 | var receiver = if(isSender) friendId else sender 59 | var data = MessageDbo(userId,sender,receiver,message,isSender,messageType,dateTime,senderName,read) 60 | data.dateTime = dateTime 61 | return data 62 | } 63 | 64 | 65 | fun isImage():Boolean{ 66 | return messageType == MessageType.IMAGE 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/MessageSelfResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class MessageSelfResp : Packet() { 12 | var receiverId: String? = null 13 | var groupId: String? = null 14 | var success: Boolean = false 15 | var reason: String? = null 16 | 17 | override fun packetType(): Int { 18 | return PacketType.MESSAGE_SELF_RESP 19 | } 20 | 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/RegisterResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.PacketType 4 | 5 | /** 6 | * @author Zed 7 | * date: 2019/08/19. 8 | * description: 9 | */ 10 | class RegisterResp constructor(userId: String,userName: String,token: String,success: Boolean,reason: String = "") : LoginResp(userId,userName,token,success,reason) { 11 | 12 | 13 | override fun packetType(): Int { 14 | return PacketType.REGISTER_RESP 15 | } 16 | 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/netty/packet/resp/UpdatePasswdResp.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.netty.packet.resp 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.PacketType 5 | 6 | /** 7 | * @author Zed 8 | * date: 2019/08/19. 9 | * description: 10 | */ 11 | class UpdatePasswdResp : Packet() { 12 | var password: String? = null 13 | var success: Boolean = false 14 | var reason: String? = null 15 | 16 | override fun packetType(): Int { 17 | return PacketType.UPDATE_PASSWD_RESP 18 | } 19 | 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/temp/TempActivity.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.temp 2 | 3 | import android.os.Bundle 4 | import androidx.databinding.ViewDataBinding 5 | import com.king.easychat.app.base.BaseActivity 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | class TempActivity : BaseActivity(){ 11 | 12 | override fun initData(savedInstanceState: Bundle?) { 13 | 14 | } 15 | 16 | override fun getLayoutId(): Int { 17 | return 0 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/temp/TempFragment.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.temp 2 | 3 | import android.os.Bundle 4 | import androidx.databinding.ViewDataBinding 5 | import com.king.easychat.app.account.RegisterViewModel 6 | import com.king.easychat.app.base.BaseFragment 7 | 8 | /** 9 | * @author Jenly 10 | */ 11 | class TempFragment : BaseFragment(){ 12 | 13 | companion object{ 14 | fun newInstance(): TempFragment{ 15 | return TempFragment() 16 | } 17 | } 18 | 19 | override fun initData(savedInstanceState: Bundle?) { 20 | } 21 | 22 | override fun getLayoutId(): Int { 23 | return 0 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/temp/TempViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.temp 2 | 3 | import android.app.Application 4 | import com.king.frame.mvvmframe.base.BaseModel 5 | import com.king.frame.mvvmframe.base.DataViewModel 6 | import javax.inject.Inject 7 | 8 | /** 9 | * @author Jenly 10 | */ 11 | class TempViewModel @Inject constructor(application: Application, model: BaseModel?) : DataViewModel(application, model){ 12 | 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/util/AES.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.util 2 | import android.util.Base64 3 | import javax.crypto.Cipher 4 | import javax.crypto.spec.IvParameterSpec 5 | import javax.crypto.spec.SecretKeySpec 6 | 7 | 8 | /** 9 | * @author Jenly 10 | */ 11 | object AES { 12 | private const val IV_STRING = "ABCD1234EFGH5678" 13 | private const val charset = "UTF-8" 14 | 15 | fun encrypt(content: String, key: String): String? { 16 | try { 17 | val contentBytes = content.toByteArray(charset(charset)) 18 | val keyBytes = key.toByteArray(charset(charset)) 19 | val encryptedBytes = encrypt(contentBytes, keyBytes) 20 | return Base64.encodeToString(encryptedBytes,Base64.DEFAULT) 21 | } catch (e: Exception) { 22 | return null 23 | } 24 | 25 | } 26 | 27 | fun decrypt(content: String, key: String): String? { 28 | try { 29 | val encryptedBytes = Base64.decode(content,Base64.DEFAULT) 30 | val keyBytes = key.toByteArray(charset(charset)) 31 | val decryptedBytes = decrypt(encryptedBytes, keyBytes) 32 | return String(decryptedBytes) 33 | } catch (e: Exception) { 34 | return null 35 | } 36 | 37 | } 38 | 39 | @Throws(Exception::class) 40 | private fun encrypt(contentBytes: ByteArray, keyBytes: ByteArray): ByteArray { 41 | return cipherOperation(contentBytes, keyBytes, Cipher.ENCRYPT_MODE) 42 | } 43 | 44 | @Throws(Exception::class) 45 | private fun decrypt(contentBytes: ByteArray, keyBytes: ByteArray): ByteArray { 46 | return cipherOperation(contentBytes, keyBytes, Cipher.DECRYPT_MODE) 47 | } 48 | 49 | @Throws(Exception::class) 50 | private fun cipherOperation( 51 | contentBytes: ByteArray, 52 | keyBytes: ByteArray, 53 | mode: Int 54 | ): ByteArray { 55 | val secretKey = SecretKeySpec(keyBytes, "AES") 56 | 57 | val initParam = IV_STRING.toByteArray(charset(charset)) 58 | val ivParameterSpec = IvParameterSpec(initParam) 59 | 60 | val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") 61 | cipher.init(mode, secretKey, ivParameterSpec) 62 | 63 | return cipher.doFinal(contentBytes) 64 | } 65 | 66 | 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/util/BitmapUtil.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.util 2 | 3 | import android.graphics.* 4 | 5 | /** 6 | * @author Jenly 7 | */ 8 | object BitmapUtil { 9 | 10 | /** 11 | * 通过PorterDuff模式获取圆角图片 12 | */ 13 | fun getOvalBitmap(bitmap: Bitmap): Bitmap{ 14 | val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888) 15 | val canvas = Canvas(output) 16 | 17 | val color = Color.WHITE 18 | val paint = Paint() 19 | paint.isAntiAlias = true 20 | paint.isFilterBitmap = true 21 | val rect = Rect(0, 0, bitmap.width, bitmap.height) 22 | 23 | val rectF = RectF(rect) 24 | paint.isAntiAlias = true 25 | canvas.drawARGB(0, 0, 0, 0) 26 | paint.color = color 27 | canvas.drawOval(rectF, paint) 28 | paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) 29 | canvas.drawBitmap(bitmap, rect, rect, paint) 30 | 31 | return output 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/util/Cache.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.util 2 | 3 | import com.king.base.util.StringUtils 4 | import com.king.easychat.app.Constants 5 | import com.king.easychat.netty.packet.req.LoginReq 6 | import com.king.easychat.netty.packet.req.RegisterReq 7 | import com.tencent.mmkv.MMKV 8 | 9 | /** 10 | * @author Jenly 11 | */ 12 | object Cache { 13 | 14 | fun put(data: RegisterReq?,token: String){ 15 | data?.let { 16 | MMKV.defaultMMKV().encode(Constants.KEY_USERNAME,it.userName) 17 | } 18 | putToken(token) 19 | 20 | } 21 | 22 | fun put(data: LoginReq?,token: String){ 23 | data?.let { 24 | MMKV.defaultMMKV().encode(Constants.KEY_USERNAME,it.userName) 25 | } 26 | putToken(token) 27 | 28 | } 29 | 30 | fun put(key: String,value: String){ 31 | MMKV.defaultMMKV().encode(key,value) 32 | 33 | } 34 | 35 | fun putToken(token : String?){ 36 | token?.let { 37 | put(Constants.KEY_TOKEN,it) 38 | } 39 | 40 | } 41 | 42 | fun clearToken(){ 43 | MMKV.defaultMMKV().reKey(Constants.KEY_TOKEN) 44 | } 45 | 46 | fun getUsername(): String?{ 47 | return MMKV.defaultMMKV().decodeString(Constants.KEY_USERNAME) 48 | } 49 | 50 | fun getToken(): String?{ 51 | return MMKV.defaultMMKV().decodeString(Constants.KEY_TOKEN) 52 | } 53 | 54 | fun getLoginReq(): LoginReq?{ 55 | var loginReq : LoginReq? = null 56 | MMKV.defaultMMKV().run { 57 | var username: String? = decodeString(Constants.KEY_USERNAME) 58 | var token: String? = decodeString(Constants.KEY_TOKEN) 59 | 60 | if(StringUtils.isNotBlank(token)){ 61 | loginReq = LoginReq(token,username,null) 62 | } 63 | } 64 | 65 | return loginReq 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/util/CheckUtil.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.util 2 | 3 | import java.util.regex.Pattern 4 | 5 | /** 6 | * @author Jenly 7 | */ 8 | object CheckUtil { 9 | 10 | 11 | /** 12 | * 密码验证 6-20位数字,不允许有空格 13 | * 14 | * @param password 15 | * @return 16 | */ 17 | fun isPassword(password: String): Boolean { 18 | val regex = "^(?![0-9]+\$)(?![a-zA-Z]+\$)[0-9A-Za-z]{6,20}\$" 19 | return matcher(password,regex) 20 | } 21 | 22 | fun isUrl(url: String): Boolean{ 23 | val regex = "[hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://" 24 | return matcher(url,regex) 25 | } 26 | 27 | fun matcher(content: String,regex: String): Boolean{ 28 | val p = Pattern.compile(regex) 29 | val m = p.matcher(content) 30 | return m.matches() 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/util/Event.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.util 2 | 3 | import org.greenrobot.eventbus.EventBus 4 | 5 | /** 6 | * @author Jenly 7 | */ 8 | object Event { 9 | 10 | private val event = EventBus.getDefault() 11 | 12 | fun sendEvent(msg: Any,isSticky: Boolean = false){ 13 | if(isSticky){ 14 | event.postSticky(msg) 15 | }else{ 16 | event.post(msg) 17 | } 18 | 19 | } 20 | 21 | fun registerEvent(obj: Any){ 22 | event.register(obj) 23 | } 24 | 25 | fun unregisterEvent(obj: Any){ 26 | event.unregister(obj) 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/util/FileUtil.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.util 2 | 3 | import android.util.Base64 4 | import java.io.* 5 | 6 | /** 7 | * @author Jenly 8 | */ 9 | object FileUtil { 10 | 11 | 12 | fun imageToBase64(filename: String): String{ 13 | return imageToBase64(File(filename)) 14 | } 15 | 16 | fun imageToBase64(file: File): String{ 17 | var bytes = file.toBytes() 18 | bytes?.let { 19 | return Base64.encodeToString(it,Base64.NO_WRAP) 20 | } 21 | 22 | return "" 23 | } 24 | 25 | fun File.toBytes(): ByteArray?{ 26 | val length = length().toInt() 27 | var baos = ByteArrayOutputStream(length) 28 | var ins : InputStream? = null 29 | try { 30 | ins = BufferedInputStream(FileInputStream(this)) 31 | ins?.let { 32 | var buffer = ByteArray(8192) 33 | var read = it.read(buffer) 34 | while (read > 0 ){ 35 | baos.write(buffer,0 ,read) 36 | read = it.read(buffer) 37 | } 38 | } 39 | 40 | }catch (e: Exception){ 41 | 42 | }finally { 43 | try{ 44 | ins?.close() 45 | }catch (e1: Exception){ 46 | 47 | } 48 | } 49 | 50 | return baos.toByteArray() 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/king/easychat/util/JsonUtil.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat.util 2 | 3 | import com.google.gson.Gson 4 | import org.json.JSONObject 5 | 6 | 7 | /** 8 | * @author Jenly 9 | */ 10 | object JsonUtil{ 11 | 12 | private val gson = Gson() 13 | 14 | fun toJson(obj: Any): String{ 15 | return gson.toJson(obj) 16 | } 17 | 18 | @ExperimentalStdlibApi 19 | fun toJsonBytes(obj: Any): ByteArray{ 20 | return toJson(obj).encodeToByteArray() 21 | } 22 | 23 | fun fromJson(json: String,clazz: Class): T{ 24 | return gson.fromJson(json,clazz) 25 | } 26 | 27 | 28 | fun getPacketType(json: String): Int { 29 | val jsonObject = JSONObject(json) 30 | return jsonObject.getInt("command") 31 | } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_in.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_out.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/splash_in.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/res/anim/translate_left_in.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/translate_left_out.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/translate_right_in.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/translate_right_out.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/color/bottom_menu_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/white_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ec_welcome.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xhdpi/ec_welcome.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_back_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_back_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_back_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_back_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_bg_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_bg_normal.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_bg_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_bg_pressed.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_black_back_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_black_back_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_black_back_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_black_back_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_clear.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_close_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_close_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_close_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_close_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_delete_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_delete_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_delete_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_delete_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_menu_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_menu_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_menu_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_menu_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_more_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_more_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_more_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_more_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_none.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_scan_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_scan_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_scan_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_scan_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_search_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_search_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_search_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/btn_search_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/default_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/default_avatar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_about.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_about_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_about_line.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_chat_bubble_left.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_chat_bubble_left.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_chat_bubble_right.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_chat_bubble_right.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_create_group_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_create_group_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_create_group_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_create_group_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_delete.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_detail_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_detail_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_detail_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_detail_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_edit_box_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_edit_box_bg.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_empty.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_heart.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_keyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_keyboard.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_modify_password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_modify_password.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_next.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_next_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_next_white.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_on.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_qrcode.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_save_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_save_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_save_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_save_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_smile.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ec_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ec_version.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/explosion_five.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/explosion_five.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/explosion_four.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/explosion_four.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/explosion_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/explosion_one.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/explosion_three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/explosion_three.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/explosion_two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/explosion_two.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_about_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_about_image.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_close.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_github.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_hide.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_menu_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_menu_about.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_menu_logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_menu_logout.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_none.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_password.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_show.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/ic_user.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/input_bg_focus.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/input_bg_focus.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/input_bg_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/input_bg_normal.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/login_slogan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/login_slogan.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/menu_friend_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/menu_friend_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/menu_friend_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/menu_friend_selected.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/menu_group_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/menu_group_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/menu_group_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/menu_group_selected.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/menu_me_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/menu_me_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/menu_me_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/menu_me_selected.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/menu_message_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/menu_message_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/menu_message_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/drawable-xxhdpi/menu_message_selected.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_back_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_bg_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_black_back_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_clear_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_close_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_create_group_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_delete_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_detail_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_flash_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_menu_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_password_eye_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_save_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_scan_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_search_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/edit_bg_line_normal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/edit_bg_line_pressed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/edit_bg_line_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_clear_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line_drawable_8.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line_drawable_xh_none.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo_layer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_friend_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_group_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_me_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_message_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/search_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/splash_layer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/web_progress_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/white_bottom_layer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/white_layer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/white_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/change_user_info_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 15 | 24 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/code_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 11 | 12 | 17 | 26 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/friend_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 13 | 14 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/group_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 13 | 14 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/group_member_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 13 | 14 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/home_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 13 | 14 | 19 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/home_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 17 | 25 | 36 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_empty.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/photo_view_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 11 | 16 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/rv_group_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 19 | 30 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/rv_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/scan_code_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 13 | 26 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/scan_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 16 | 24 | 35 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/splash_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 17 | 25 | 36 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/vp_photo_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/web_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 12 | 16 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/menu/about_me.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 11 | 14 | 17 | 20 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values-v21/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #4587f0 5 | #4587f0 6 | #4587f0 7 | 8 | #1298ed 9 | 10 | #d0d0d0 11 | 12 | #4587f0 13 | #f2f3f6 14 | 15 | #f2f3f6 16 | 17 | #cccccc 18 | 19 | #333333 20 | #666666 21 | #999999 22 | #808080 23 | #ffffff 24 | 25 | #7fffffff 26 | 27 | #4587f0 28 | 29 | #7fffffff 30 | 31 | #7f000000 32 | 33 | #D93F3C 34 | 35 | #4587f0 36 | #999999 37 | 38 | #f2f3f6 39 | 40 | #ddffffff 41 | 42 | #ffffff 43 | #000000 44 | 45 | #00000000 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #4587F0 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 4 | 30 5 | 26 6 | 20 7 | 20 8 | 30 9 | 20 10 | -------------------------------------------------------------------------------- /app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/test/java/com/king/easychat/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.king.easychat 2 | 3 | import com.king.easychat.netty.packet.Packet 4 | import com.king.easychat.netty.packet.req.GroupMessageReq 5 | import org.junit.Test 6 | 7 | import org.junit.Assert.* 8 | import java.nio.file.Files.isDirectory 9 | import io.netty.util.internal.ResourcesUtil.getFile 10 | import java.io.File 11 | import java.io.IOException 12 | 13 | 14 | /** 15 | * Example local unit test, which will execute on the development machine (host). 16 | * 17 | * See [testing documentation](http://d.android.com/tools/testing). 18 | */ 19 | class ExampleUnitTest { 20 | @Test 21 | fun addition_isCorrect() { 22 | assertEquals(4, 2 + 2) 23 | } 24 | 25 | @Test 26 | fun testPacket() { 27 | var req = GroupMessageReq("123", "456", 1) 28 | println(req.messageType) 29 | println(req.packetType()) 30 | } 31 | @Test 32 | fun testClass() { 33 | val clazz = Packet::class.java 34 | val classes = getClasses(clazz) 35 | println(classes) 36 | } 37 | 38 | /** 39 | * 取得当前类路径下的所有类 40 | * 41 | * @param cls 42 | * @return 43 | * @throws IOException 44 | * @throws ClassNotFoundException 45 | */ 46 | @Throws(IOException::class, ClassNotFoundException::class) 47 | fun getClasses(cls: Class<*>): List> { 48 | val pk = cls.getPackage()!!.name 49 | val path = pk.replace('.', '/') 50 | val classloader = Thread.currentThread().contextClassLoader 51 | val url = classloader!!.getResource(path) 52 | return getClasses(File(url.file), pk) 53 | } 54 | 55 | /** 56 | * 迭代查找类 57 | * 58 | * @param dir 59 | * @param pk 60 | * @return 61 | * @throws ClassNotFoundException 62 | */ 63 | @Throws(ClassNotFoundException::class) 64 | private fun getClasses(dir: File, pk: String): List> { 65 | val classes = ArrayList>() 66 | if (!dir.exists()) { 67 | return classes 68 | } 69 | for (f in dir.listFiles()) { 70 | if (f.isDirectory()) { 71 | classes.addAll(getClasses(f, pk + "." + f.getName())) 72 | } 73 | val name = f.getName() 74 | if (name.endsWith(".class")) { 75 | classes.add(Class.forName(pk + "." + name.substring(0, name.length - 6))) 76 | } 77 | } 78 | return classes 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /art/GIF.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/art/GIF.gif -------------------------------------------------------------------------------- /art/GIF2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/art/GIF2.gif -------------------------------------------------------------------------------- /art/QR_EasyChat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/art/QR_EasyChat.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | apply from: 'versions.gradle' 5 | repositories { 6 | google() 7 | jcenter() 8 | 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.5.1' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin" 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | classpath 'com.tencent.bugly:tinker-support:1.1.5' 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | google() 22 | jcenter() 23 | maven { url 'https://jitpack.io' } 24 | maven { url 'https://dl.bintray.com/jenly/maven' } 25 | 26 | } 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | 33 | ext { 34 | signingEnabled = false 35 | 36 | tinkerEnabled = false 37 | 38 | } 39 | -------------------------------------------------------------------------------- /doc/接口文档.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/doc/接口文档.docx -------------------------------------------------------------------------------- /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 = -Xmx1536m 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 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yetel/EasyChatAndroidClient/393e334c8bb3a14e9d554e5187fbc88a0afc3d43/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Sep 24 14:25:09 CST 2019 2 | distributionBase = GRADLE_USER_HOME 3 | distributionPath = wrapper/dists 4 | zipStoreBase = GRADLE_USER_HOME 5 | zipStorePath = wrapper/dists 6 | distributionUrl = https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | rootProject.name='EasyChat' 3 | -------------------------------------------------------------------------------- /versions.gradle: -------------------------------------------------------------------------------- 1 | //App 2 | def app_version = [:] 3 | app_version.versionCode = 1 4 | app_version.versionName = "1.0.0" 5 | ext.app_version = app_version 6 | 7 | //build version 8 | def build_versions = [:] 9 | build_versions.minSdk = 16 10 | build_versions.targetSdk = 29 11 | build_versions.compileSdk = 29 12 | build_versions.buildTools = "29.0.2" 13 | ext.build_versions = build_versions 14 | 15 | // App dependencies 16 | def versions = [:] 17 | 18 | versions.kotlin = "1.3.50" 19 | versions.appcompat = "1.0.2" 20 | versions.coreKtx = "1.0.2" 21 | versions.material = "1.0.0" 22 | versions.constraintlayout = "1.1.3" 23 | versions.junit = "4.12" 24 | versions.runner = "1.1.1" 25 | versions.espressoCore = "3.1.1" 26 | versions.recyclerview = "1.1.0-beta05" 27 | versions.viewpager2 = "1.0.0-beta05" 28 | versions.debugDb = "1.0.6" 29 | versions.kotlinxCoroutines = "1.3.2" 30 | versions.room = "2.2.0-alpha01" 31 | versions.dagger = "2.23.2" 32 | 33 | versions.mvvmframe = "1.1.0" 34 | versions.nevercrash = "1.0.0" 35 | versions.base = "3.2.1-androidx" 36 | versions.anetty = "1.0.2" 37 | versions.appUpdater = "1.0.5-androidx" 38 | versions.flutteringlayout = "1.1.1" 39 | versions.zxingLite = "1.1.3-androidx" 40 | versions.baseUrlManager = "1.0.1-androidx" 41 | versions.logger = "2.2.0" 42 | versions.eventbus = "3.1.1" 43 | versions.brvah = "2.9.49-androidx" 44 | versions.circleimageview = "3.0.1" 45 | versions.glide = "4.10.0" 46 | versions.matisse = "0.5.3-beta2" 47 | versions.Luban = "1.1.8" 48 | versions.ucrop = "2.2.4" 49 | versions.PhotoView = "2.0.0" 50 | versions.rxpermissions = "0.10.2" 51 | versions.jsbridge = "1.0.4" 52 | versions.mmkv = "1.0.23" 53 | versions.bugly = "1.3.6" 54 | versions.tinker = "1.9.9" 55 | 56 | ext.versions = versions 57 | --------------------------------------------------------------------------------