Commit 9326aaa7 by 王文龙

initial commit

parent 079ccb26
IMTeacher
\ No newline at end of file
......@@ -46,5 +46,15 @@
<option name="name" value="maven4" />
<option name="url" value="https://jitpack.io" />
</remote-repository>
<remote-repository>
<option name="id" value="maven4" />
<option name="name" value="maven4" />
<option name="url" value="http://maven.aliyun.com/nexus/content/repositories/jcenter" />
</remote-repository>
<remote-repository>
<option name="id" value="maven3" />
<option name="name" value="maven3" />
<option name="url" value="http://maven.aliyun.com/nexus/content/groups/public/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
{
"agcgw": {
"websocketbackurl": "connect-ws-drcn.hispace.dbankcloud.cn",
"backurl": "connect-drcn.dbankcloud.cn",
"websocketurl": "connect-ws-drcn.hispace.dbankcloud.com",
"url": "connect-drcn.hispace.hicloud.com"
"agcgw":{
"backurl":"connect-drcn.dbankcloud.cn",
"url":"connect-drcn.hispace.hicloud.com"
},
"client": {
"appType": "1",
"cp_id": "40086000027273766",
"product_id": "736430079244758235",
"client_id": "525214879183811200",
"client_secret": "5C881FEDAAC1553569672C7BAF7C227EAF0FE09964121325B0BA81D3E1ACD1AA",
"project_id": "736430079244758235",
"app_id": "103563811",
"api_key": "CgB6e3x9dUrnhfW7QTy8zKNAopJZKlP2p33BRXsZV1ZQ6QJZkrxI0Ozaz/pjIfNSOVO9cl04nzTBthSirmV5AcFO",
"package_name": "com.offcn.imteacher"
"client":{
"cp_id":"890086000102050749",
"product_id":"736430079244600637",
"client_id":"428619366230131712",
"client_secret":"0D095EC16F9F17A74899448A4F038C0DE64B3E04FF760788B3AD876381BB4D29",
"app_id":"102733647",
"package_name":"com.offcn.im.demo",
"api_key":"CgB6e3x929EyFzS+R9oesSLzvPTkeqrPk3dGPHkKgSm53FQVyD5S/A5bu8D+vSiFiwwSBKZdKqQTYjx1PSgpEXPE"
},
"service": {
"analytics": {
"collector_url": "datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
"resource_id": "p1",
"channel_id": ""
"service":{
"analytics":{
"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
"resource_id":"p1",
"channel_id":""
},
"search": {
"url": "https://search-drcn.cloud.huawei.com"
"cloudstorage":{
"storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn"
},
"cloudstorage": {
"storage_url": "https://agc-storage-drcn.platform.dbankcloud.cn"
},
"ml": {
"mlservice_url": "ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"
"ml":{
"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"
}
},
"region": "CN",
"configuration_version": "1.0"
"region":"CN",
"configuration_version":"1.0"
}
\ No newline at end of file
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
apply plugin: 'org.greenrobot.greendao'
def releaseTimeFull() {
Date date = new Date();
......@@ -12,7 +11,7 @@ android {
compileSdkVersion 29
defaultConfig {
applicationId "com.offcn.imteacher"
applicationId "com.offcn.im.demo"
minSdkVersion 19
targetSdkVersion 29
versionCode 1
......@@ -28,16 +27,16 @@ android {
signingConfigs {
debug {
storeFile file("../keystore/imteacher.keystore")
storePassword "imteacher.keystore"
keyAlias "imteacher.keystore"
keyPassword "imteacher.keystore"
storeFile file("../keystore/zgimdemo.keystore")
storePassword "zgim123456"
keyAlias "zgimalias.keystore"
keyPassword "zgim123456"
}
release {
storeFile file("../keystore/imteacher.keystore")
storePassword "imteacher.keystore"
keyAlias "imteacher.keystore"
keyPassword "imteacher.keystore"
storeFile file("../keystore/zgimdemo.keystore")
storePassword "zgim123456"
keyAlias "zgimalias.keystore"
keyPassword "zgim123456"
}
}
......@@ -48,7 +47,7 @@ android {
buildTypes {
build {
zipAlignEnabled true
zipAlignEnabled false
shrinkResources false
minifyEnabled false
......@@ -62,7 +61,7 @@ android {
}
}
release {
zipAlignEnabled true
zipAlignEnabled false
shrinkResources false
minifyEnabled false
......@@ -71,16 +70,10 @@ android {
applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "imteacher_v${defaultConfig.versionName}_${releaseTimeFull()}_${buildType.name}.apk";
}
outputFileName = "imsdkdemo_v${defaultConfig.versionName}_${releaseTimeFull()}_${buildType.name}.apk";
}
}
}
greendao {
schemaVersion 1
daoPackage 'com.offcn.imclient.greendao.gen'
targetGenDir 'src/main/java'
}
}
......@@ -90,18 +83,14 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.android.support:multidex:1.0.3'
implementation("com.offcn.live:base:2.5.0-s18")
implementation("com.offcn.live:imsdk-kit:1.0.0.45")
// DB
implementation 'org.greenrobot:greendao:3.2.2'
implementation 'com.android.volley:volley:1.1.1'
// bugly
implementation 'com.tencent.bugly:crashreport:latest.release'
//其中latest.release指代最新Bugly SDK版本号,也可以指定明确的版本号,例如2.1.9
implementation 'com.tencent.bugly:nativecrashreport:latest.release'
//其中latest.release指代最新Bugly NDK版本号,也可以指定明确的版本号,例如3.0
// 中公IMSDK
implementation("com.offcn.live:imsdk-kit:1.0.2.14")
// 中公IM基础库,业务需要
implementation("com.offcn.live:base:2.5.0-s18")
}
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.offcn.imclient">
package="com.offcn.im.demo">
<application
android:name=".MyApp"
android:allowBackup="true"
android:icon="@mipmap/ic_logo"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_logo"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
......@@ -23,7 +23,14 @@
</intent-filter>
</activity>
<!-- 主页-->
<!-- 登录页-->
<activity
android:name=".ui.LoginActivity"
android:configChanges="keyboardHidden|screenSize|orientation"
android:screenOrientation="portrait"/>
<!-- 主页,集成了SDK的会话列表页,需要配置-->
<activity
android:name=".ui.MainActivity"
android:configChanges="keyboardHidden|screenSize|orientation"
......@@ -34,27 +41,14 @@
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="com.offcn.imteacher"
android:host="com.offcn.im.demo"
android:pathPrefix="/chatlist"
android:scheme="offcn" />
</intent-filter>
</activity>
<!-- 登录页-->
<activity
android:name=".ui.LoginActivity"
android:configChanges="keyboardHidden|screenSize|orientation"
android:screenOrientation="portrait"></activity>
<!-- 搜索页-->
<activity
android:name=".ui.SearchActivity"
android:configChanges="keyboardHidden|screenSize|orientation"
android:screenOrientation="portrait"></activity>
<!-- 会话聊天页-->
<!-- 会话聊天页,集成了SDK的会话聊天页,需要配置-->
<activity
android:name=".ui.ChatActivity"
android:name="com.offcn.im.demo.ui.ChatActivity"
android:configChanges="keyboardHidden|screenSize|orientation"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
......@@ -64,7 +58,7 @@
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="com.offcn.imteacher"
android:host="com.offcn.im.demo"
android:pathPrefix="/chat/"
android:scheme="offcn" />
</intent-filter>
......@@ -74,11 +68,11 @@
<!-- 中公IM平台appkey-->
<meta-data
android:name="com.offcn.live.im.appkey"
android:value="d5b410cddbcb4f3a972cfdc697daff43" />
android:value="cd211c8f87423a44ba7d56913fb86c91" />
<!-- android:value="offcn_live" />-->
<meta-data
android:name="com.offcn.live.im.appsecret"
android:value="b23f77e463ac4e9388b3c0b4ee9b8ed0" />
android:value="6c2735bee7f8" />
<!-- android:value="offcn_im" />-->
<!--华为推送。根目录下添加 agconnect-services.json,由华为开放平台自行获取-->
......@@ -110,7 +104,7 @@
<!--begin 点击推送通知栏处理配置-->
<activity
android:name=".ui.PushTranslateActivity"
android:name="com.offcn.im.demo.ui.PushTranslateActivity"
android:configChanges="keyboardHidden|screenSize|orientation"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
......
package com.offcn.imclient;
package com.offcn.im.demo;
import android.content.Context;
import com.jyall.base.util.EventBusCenter;
import com.jyall.base.util.EventBusUtil;
import com.jyall.base.util.ValidateUtils;
import com.offcn.imclient.bean.UserBean;
import com.offcn.imclient.util.Constants;
import com.offcn.imclient.util.LoginManager;
import com.offcn.imclient.util.UserBeanDaoManager;
import com.offcn.im.demo.bean.UserBean;
import com.offcn.im.demo.util.Constants;
import com.offcn.im.demo.util.LoginManager;
import com.offcn.im.demo.util.MockData;
import com.offcn.live.im.OIMCallback;
import com.offcn.live.im.OIMSDK;
import com.offcn.live.im.bean.OIMMsg;
import com.offcn.live.im.bean.OIMUserInfo;
import com.offcn.live.im.util.OIMDataManager;
import com.offcn.live.im.util.ZGLLogUtils;
import com.tencent.bugly.crashreport.CrashReport;
import java.util.logging.LogManager;
import androidx.multidex.MultiDex;
import androidx.multidex.MultiDexApplication;
public class MyApp extends MultiDexApplication {
private static final String TAG = MyApp.class.getSimpleName();
// 设置当前环境
private boolean mEnvIsTest = false;
@Override
......@@ -40,20 +40,17 @@ public class MyApp extends MultiDexApplication {
// 初始化 OIMSDK
initOIMSDK();
// bugly
CrashReport.initCrashReport(getApplicationContext(), "8cda8831f2", true);
CrashReport.initCrashReport(getApplicationContext(), "8e4fbab19e", true);
}
private void initOIMSDK() {
UserBeanDaoManager.getInstance().init(this);
// 初始化本地DB,用于存储用户信息。本示例数据直接由 MockData 提供
// UserBeanDaoManager.getInstance().init(this);
// 中公IM 初始化
OIMSDK.init(this, mEnvIsTest);
// 始终打印log 方便调试------------------记得上线前关闭
ZGLLogUtils.setLogEnabled(true);
OIMSDK.getInstance().setOnUnreadMsgCountChangedListener(new OIMCallback.OnUnreadMsgCountChangedListener() {
@Override
public void onCountChanged(int count) {
ZGLLogUtils.e(TAG, "onCountChanged " + count);
EventBusUtil.sendEvent(new EventBusCenter(Constants.EventCode.Code_Count_Changed, count));
}
});
// 中公IM 监听新消息
OIMSDK.getInstance().setOnMsgListener(new OIMCallback.OnReceiveMsgListener() {
@Override
public void onMsg(OIMMsg oimMsg) {
......@@ -61,20 +58,17 @@ public class MyApp extends MultiDexApplication {
EventBusUtil.sendEvent(new EventBusCenter(Constants.EventCode.Code_New_Msg));
}
});
// 中公IM 提供用户信息
OIMSDK.getInstance().setUserInfoProvider(new OIMCallback.OnUserInfoProvider() {
@Override
public OIMUserInfo getUserInfo(String s) {
if (ValidateUtils.isEmpty(s)) {
return null;
}
// 当前登录用户
UserBean destUserBean;
if (s.equals(LoginManager.getUserId(getApplicationContext()))) {
destUserBean = LoginManager.getUser(getApplicationContext());
} else {
destUserBean = UserBeanDaoManager.getInstance().queryStudentByUserId(s);
}
if (destUserBean == null) {
// 从DB中获取到用户信息,返回给SDK
UserBean destUserBean = MockData.getUserById(s);
if(destUserBean == null){
return null;
}
OIMUserInfo userInfo = new OIMUserInfo();
......@@ -83,6 +77,11 @@ public class MyApp extends MultiDexApplication {
userInfo.setAvatar(destUserBean.getAvatar());
return userInfo;
}
@Override
public OIMUserInfo getUserInfoPm(String s, String s1) {
return null;
}
});
}
}
package com.offcn.imclient.adapter;
package com.offcn.im.demo.adapter;
import android.content.Context;
import android.widget.ImageView;
......@@ -7,17 +7,17 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.jyall.base.adapter.BaseRecyclerViewAdapter;
import com.jyall.base.adapter.RecyclerViewHolderUtil;
import com.offcn.imclient.R;
import com.offcn.imclient.bean.UserBean;
import com.offcn.im.demo.R;
import com.offcn.im.demo.bean.UserBean;
import java.util.List;
public class ContactSearchAdapter extends BaseRecyclerViewAdapter<UserBean> {
public ContactSearchAdapter(Context paramContext) {
public class ContactAdapter extends BaseRecyclerViewAdapter<UserBean> {
public ContactAdapter(Context paramContext) {
super(paramContext);
}
public ContactSearchAdapter(Context context, List<UserBean> list) {
public ContactAdapter(Context context, List<UserBean> list) {
super(context, list);
}
......
package com.offcn.imclient.bean;
package com.offcn.im.demo.bean;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
......@@ -37,6 +37,13 @@ public class UserBean implements Serializable {
this.avatar = avatar;
}
public UserBean(String user_id, String name, String avatar, String token) {
this.user_id = user_id;
this.name = name;
this.avatar = avatar;
this.token = token;
}
@Generated(hash = 1773158533)
public UserBean(Long id, String user_id, String name, String username,
String avatar, String avatar_color, String type, String token,
......
package com.offcn.imclient.ui;
package com.offcn.im.demo.ui;
import android.net.Uri;
import android.text.TextUtils;
import com.jyall.base.base.BaseActivity;
import com.jyall.base.util.EventBusCenter;
import com.jyall.base.util.EventBusUtil;
import com.jyall.titleview.TitleView;
import com.jyall.titleview.TitleViewCompatible;
import com.offcn.imclient.R;
import com.offcn.imclient.util.Constants;
import com.offcn.im.demo.R;
import com.offcn.live.imkit.ui.ChatFragment;
/**
......@@ -36,6 +32,7 @@ public class ChatActivity extends BaseActivity {
@Override
protected void initViewsAndEvents() {
// 聊天详情Fragment 需要接收 Uri 参数配置。由 startChat() 方法内部配置,外部直接调用即可
Uri intentUri = getIntent().getData();
if (intentUri == null) {
finish();
......@@ -43,8 +40,6 @@ public class ChatActivity extends BaseActivity {
}
String title = intentUri.getQueryParameter("title");
String targetId = intentUri.getQueryParameter("targetId");
long lastSeq = Long.parseLong(intentUri.getQueryParameter("lastSeq"));
mTitleView = findViewById(R.id.title_view);
mTitleView.setTitleText(TextUtils.isEmpty(title) ? "会话详情" : title);
......@@ -60,11 +55,11 @@ public class ChatActivity extends BaseActivity {
@Override
public void onBackPressed() {
// 先收起键盘
if (mChatFragment != null && mChatFragment.hookOnBackPressed()) {
return;
}
// EventBusUtil.sendEvent(new EventBusCenter(Constants.EventCode.Code_Refresh_Contact));
super.onBackPressed();
}
}
package com.offcn.imclient.ui;
package com.offcn.im.demo.ui;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.jyall.base.base.BaseFragment;
import com.jyall.base.util.CommonUtils;
import com.jyall.base.util.ValidateUtils;
import com.offcn.imclient.R;
import com.offcn.imclient.adapter.ContactListExpandableAdapter;
import com.offcn.imclient.bean.ServerContactBean;
import com.offcn.imclient.bean.ServerContactBeanWrapper;
import com.offcn.imclient.bean.UserBean;
import com.offcn.imclient.util.LoginManager;
import com.offcn.imclient.util.UserBeanDaoManager;
import com.offcn.imclient.util.Utils;
import com.offcn.imclient.view.AnimatedExpandableListView;
import com.offcn.live.im.OIMSDK;
import com.offcn.live.im.bean.OIMSendTypeEnum;
import com.offcn.im.demo.R;
import com.offcn.live.im.util.ZGLLogUtils;
import com.offcn.live.im.util.ZGLNetworkChangeReceiver;
import com.offcn.live.im.util.ZGLParseUtils;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import com.offcn.live.imkit.ui.ChatListFragment;
/**
* 会话列表
......@@ -60,17 +36,10 @@ public class ChatListFragmentWrapper extends BaseFragment {
protected void init(View view) {
mNoNetView = view.findViewById(R.id.container_nonet);
view.findViewById(R.id.search).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!CommonUtils.isFastDoubleClick()) {
startActivity(new Intent(getActivity(), SearchActivity.class));
getActivity().overridePendingTransition(R.anim.push_bottom_in, R.anim.push_bottom_still);
}
}
});
registerReceiver();
initNet();
ChatListFragment chatListFragment = (ChatListFragment) getChildFragmentManager().findFragmentById(R.id.chat_list_fragment);
chatListFragment.setSessionTop("753977asdkjsajdka");
}
@Override
......@@ -81,18 +50,13 @@ public class ChatListFragmentWrapper extends BaseFragment {
@Override
public void onDestroy() {
super.onDestroy();
try {
if (mNetworkChangeReceiver != null) {
getActivity().unregisterReceiver(mNetworkChangeReceiver);
unregisterReceiver();
}
} catch (Exception e) {
}
}
private void initNet() {
/**
* 监听网络
*/
private void registerReceiver() {
mNetworkChangeReceiver = new ZGLNetworkChangeReceiver();
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
......@@ -110,4 +74,15 @@ public class ChatListFragmentWrapper extends BaseFragment {
}
});
}
private void unregisterReceiver() {
try {
if (mNetworkChangeReceiver != null) {
getActivity().unregisterReceiver(mNetworkChangeReceiver);
}
} catch (Exception e) {
}
}
}
package com.offcn.im.demo.ui;
import android.view.View;
import android.widget.AdapterView;
import com.jyall.base.base.BaseFragment;
import com.jyall.base.util.CommonUtils;
import com.offcn.im.demo.R;
import com.offcn.im.demo.adapter.ContactAdapter;
import com.offcn.im.demo.bean.UserBean;
import com.offcn.im.demo.util.LoginManager;
import com.offcn.im.demo.util.MockData;
import com.offcn.live.im.OIMSDK;
import com.offcn.live.im.bean.OIMSendTypeEnum;
import java.util.ArrayList;
import java.util.List;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* 通讯录页。业务页面,由外部完成,因为平台无通讯录
*/
public class ContactListFragment extends BaseFragment {
private static final String TAG = ContactListFragment.class.getSimpleName();
private RecyclerView mRecyclerView;
private List<UserBean> friends = new ArrayList<>();
private ContactAdapter mAdapter;
@Override
protected int getContentViewId() {
return R.layout.fragment_contact_list;
}
@Override
protected boolean setLoadAlways() {
return false;
}
@Override
protected void init(View view) {
mRecyclerView = view.findViewById(R.id.recycler_view);
mAdapter = new ContactAdapter(getContext(), friends);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
mRecyclerView.setLayoutManager(linearLayoutManager);
mRecyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
UserBean userBean = friends.get(position);
if (userBean != null) {
if(userBean.getUser_id().equals(LoginManager.getUserId(getActivity()))){
CommonUtils.showToast(getActivity(), "不能跟自己聊");
}else {
OIMSDK.getInstance().startChat(getActivity(), OIMSendTypeEnum.PRIVATE, userBean.getUser_id(), userBean.getName(), 0);
}
} else {
CommonUtils.showToast(getActivity(), "获取用户信息失败");
}
}
});
getContactList();
}
/**
* 模拟接口,获取通讯录
*/
private void getContactList() {
if (!CommonUtils.isNetConnected(getActivity())) {
return;
}
friends = MockData.getUsers();
mAdapter.addAll(friends);
// 保存信息,供内部SDK刷新UI。正常开发会存储数据库,本示例直接由 MockData 提供,不走持久化。
// UserBeanDaoManager.getInstance().insertMulti(friends);
// 获得通讯录后刷新,供内部SDK刷新会话列表
OIMSDK.getInstance().refreshUserData();
}
}
package com.offcn.im.demo.ui;
import android.content.Intent;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import com.jyall.base.base.BaseActivity;
import com.jyall.base.base.H5Activity;
import com.jyall.base.util.CommonUtils;
import com.jyall.base.util.ValidateUtils;
import com.offcn.im.demo.BuildConfig;
import com.offcn.im.demo.R;
import com.offcn.im.demo.bean.UserBean;
import com.offcn.im.demo.util.LoginManager;
import com.offcn.im.demo.util.MockData;
import com.offcn.im.demo.util.Utils;
import com.offcn.live.im.util.ZGLLogUtils;
import com.offcn.live.im.util.ZGLParseUtils;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
/**
* 登录页。三方业务页面
*/
public class LoginActivity extends BaseActivity {
private static final String TAG = LoginActivity.class.getSimpleName();
Spinner mSpinner;
TextView mTvLogin;
// 假数据
private UserBean mSpinnerUser;
@Override
protected int getContentViewLayoutId() {
return R.layout.activity_login;
}
@Override
protected void initViewsAndEvents() {
mTvLogin = findViewById(R.id.tv_login);
mTvLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
login();
}
});
// 设置假数据
mSpinner = findViewById(R.id.spinner);
String[] userNames = MockData.getUserNames();
ArrayAdapter<String> adapterFrom = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, userNames);
adapterFrom.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSpinner.setAdapter(adapterFrom);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
ZGLLogUtils.e(TAG, "onItemSelected " + position);
String spinnerName = userNames[position];
mSpinnerUser = MockData.getUserByName(spinnerName);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
@Override
protected void loadData() {
}
/**
* 模拟登录接口,获得用户信息
*/
private void login() {
if (!CommonUtils.isNetConnected(this)) {
CommonUtils.showToast(this, R.string.net_off);
return;
}
if (mSpinnerUser == null) {
CommonUtils.showToast(this, "请选择用户");
return;
}
showLoading();
// 模拟接口请求,耗时2秒
mSpinner.postDelayed(new Runnable() {
@Override
public void run() {
dismissLoading();
ZGLLogUtils.e(TAG, mSpinnerUser.toString());
// 保存登录信息
LoginManager.login(LoginActivity.this, mSpinnerUser);
// 跳转首页
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
}
}, 1000 * 2);
}
}
package com.offcn.imclient.ui;
package com.offcn.im.demo.ui;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
......@@ -16,38 +13,33 @@ import android.widget.TextView;
import com.google.android.material.tabs.TabLayout;
import com.jyall.base.adapter.BaseVPAdapter;
import com.jyall.base.base.BaseActivity;
import com.jyall.base.base.H5Activity;
import com.jyall.base.util.AppManager;
import com.jyall.base.util.CommonUtils;
import com.jyall.base.util.EventBusCenter;
import com.offcn.imclient.R;
import com.offcn.imclient.bean.UserBean;
import com.offcn.imclient.util.Constants;
import com.offcn.imclient.util.LoginManager;
import com.offcn.imclient.util.UserBeanDaoManager;
import com.offcn.im.demo.R;
import com.offcn.im.demo.bean.UserBean;
import com.offcn.im.demo.util.Constants;
import com.offcn.im.demo.util.LoginManager;
import com.offcn.live.im.OIMCallback;
import com.offcn.live.im.OIMSDK;
import com.offcn.live.im.bean.OIMCode;
import com.offcn.live.im.bean.OIMMsg;
import com.offcn.live.im.util.ZGLCommonUtils;
import com.offcn.live.im.util.ZGLLogUtils;
import com.offcn.live.im.util.ZGLNetworkChangeReceiver;
import com.offcn.live.imkit.ui.ChatListFragment;
import com.offcn.live.imkit.util.KitConstants;
import com.offcn.live.imkit.view.ScrollEnabledViewPager;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.w3c.dom.Text;
import java.util.ArrayList;
import java.util.List;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
/**
* tab主页。由最近会话和好友列表组成
* tab主页。业务页面
* <p>
* 会话列表:引用SDK 内部的 ChatListFragment
* 通讯录:业务页面,平台没有通讯录
* 我的:业务页面,模拟登录
*/
public class MainActivity extends BaseActivity {
private static final String TAG = MainActivity.class.getSimpleName();
......@@ -83,6 +75,7 @@ public class MainActivity extends BaseActivity {
return;
}
// 中公IM 连接操作
OIMSDK.getInstance().connect(mUserBean.getUser_id(), mUserBean.getToken(), new OIMCallback.OnConnectListener() {
@Override
public void onStateConnected() {
......@@ -92,26 +85,26 @@ public class MainActivity extends BaseActivity {
@Override
public void onStateDisconnected(int code, String error) {
// ------------连接失败的业务处理----------------
ZGLLogUtils.e(TAG, "IM连接失败 " + code + " " + error);
// ZGLCommonUtils.showToast(MainActivity.this, "IM连接失败 " + code + " " + error);
// 连接失败超时,和部分情况作特殊处理如退出页面:token失效、被踢
// 连接失败。需作特殊处理如退出页面:token失效、被踢等
if (code == OIMCode.Code_IM_Connect_Fail
|| code == OIMCode.Code_IM_Connect_Timeout
|| code == OIMCode.Code_IM_Error_TokenInvalid
|| code == OIMCode.Code_IM_Disconnect_Kick
|| code == OIMCode.Code_IM_Error_NoExist) {
// CommonUtils.showToast(MainActivity.this, "通道连接异常:" + OIMCode.getCodeDesc(MainActivity.this, code));
// 退出登录、清除用户信息
LoginManager.logout(MainActivity.this);
UserBeanDaoManager.getInstance().deleteAll();
// UserBeanDaoManager.getInstance().deleteAll();
if (code == OIMCode.Code_IM_Error_NoExist
|| code == OIMCode.Code_IM_Error_TokenInvalid) {
CommonUtils.showToast(MainActivity.this, "请求失败,请重新登录");
startActivity(new Intent(MainActivity.this, LoginActivity.class));
AppManager.getAppManager().finishAllActivity();
} else if (code == OIMCode.Code_IM_Disconnect_Kick) {
if (code == OIMCode.Code_IM_Disconnect_Kick) {
// 已经连接上中途异常断开:被踢,需弹窗提示重新登录
Activity curActivity = AppManager.getAppManager().getCurrentActivity();
if (curActivity != null) {
AlertDialog dialog = new AlertDialog.Builder(curActivity)
......@@ -135,6 +128,11 @@ public class MainActivity extends BaseActivity {
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
} else {
// 此时错误为:第一次连接时提示 用户不存在、token失效,连接超时,对应操作应该为重新登录
CommonUtils.showToast(MainActivity.this, "请求失败,请重新登录");
startActivity(new Intent(MainActivity.this, LoginActivity.class));
AppManager.getAppManager().finishAllActivity();
}
}
}
......@@ -146,6 +144,7 @@ public class MainActivity extends BaseActivity {
});
// 设置首页fragment
List<Fragment> fragmentList = new ArrayList<>();
fragmentList.add(new ChatListFragmentWrapper());
fragmentList.add(new ContactListFragment());
......@@ -160,10 +159,6 @@ public class MainActivity extends BaseActivity {
for (int i = 0; i < titles.length; i++) {
mTabLayout.getTabAt(i).setCustomView(getTabView(i));
}
/**
* 设置TabLayout的选中监听
*/
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
......@@ -177,7 +172,7 @@ public class MainActivity extends BaseActivity {
@Override
public void onTabUnselected(TabLayout.Tab tab) {
changeTabNormal(tab); //Tab失去焦点
changeTabNormal(tab);
}
@Override
......@@ -203,12 +198,15 @@ public class MainActivity extends BaseActivity {
@Override
public void onBackPressed() {
// super.onBackPressed();
// 退到桌面
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
}
//-----------TabLayout 代码设置 开始-------------------------------------------------
private View getTabView(int index) {
View view = LayoutInflater.from(this).inflate(R.layout.item_tab, null);
TextView title = (TextView) view.findViewById(R.id.tv_title);
......@@ -282,8 +280,10 @@ public class MainActivity extends BaseActivity {
break;
}
}
//-----------TabLayout 代码设置 结束-------------------------------------------------
// 收到新消息,更新UI
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventBus(EventBusCenter eventBusCenter) {
int eventCode = eventBusCenter.getEvenCode();
......
package com.offcn.imclient.ui;
package com.offcn.im.demo.ui;
import android.content.Intent;
import android.os.Bundle;
......@@ -8,9 +8,9 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.offcn.imclient.R;
import com.offcn.imclient.util.LoginManager;
import com.offcn.imclient.util.Utils;
import com.offcn.im.demo.R;
import com.offcn.im.demo.util.LoginManager;
import com.offcn.im.demo.util.Utils;
import com.offcn.live.imkit.view.CircleImageView;
import androidx.annotation.NonNull;
......
package com.offcn.imclient.ui;
package com.offcn.im.demo.ui;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import com.offcn.live.im.OIMSDK;
import com.offcn.live.im.bean.OIMMsg;
import com.offcn.live.im.bean.OIMMsgBody;
import com.offcn.live.im.bean.OIMSendTypeEnum;
import com.offcn.live.im.bean.OIMSessionTypeEnum;
import com.offcn.live.im.util.ZGLLogUtils;
import com.offcn.live.im.util.ZGLParseUtils;
......@@ -28,16 +31,35 @@ public class PushTranslateActivity extends AppCompatActivity {
content = bundle.getString("content");
}
if (!TextUtils.isEmpty(content)) {
// 跳转到页面需要保证 OIMSDK 连接成功,所以建议先跳转到应用首页进行全局初始化操作,若跳转到聊天页需要先连接 OIMSDK 初始化
// 跳转到聊天页面需要保证 OIMSDK 连接成功,所以建议先跳转到应用首页进行全局初始化操作
ZGLLogUtils.e(TAG, "push : " + content);
startActivity(new Intent(this, SplashActivity.class));
// 以下为根据推送类型判断启动页面,如单聊消息、系统通知 等
// OIMMsg oimMsg = ZGLParseUtils.parseObjectByGson(content, OIMMsg.class);
// if(oimMsg != null) {
// if (oimMsg != null) {
// if (oimMsg.getType() == OIMSessionTypeEnum.P2P.getType()) {
// // 会话类型为单聊。跳转到聊天页面需要保证 OIMSDK 连接成功,所以建议先跳转到应用首页进行全局初始化操作
// OIMMsgBody msgBody = oimMsg.getBody();
// if (msgBody != null) {
//// DemoChatActivity.newInstance(this, msgBody.getMsg_to(), msgBody.getMsg_from(), msgBody.getMsg_seq());
// OIMSDK.getInstance().startChat(
// this,
// OIMSendTypeEnum.PRIVATE,
// msgBody.getMsg_from(),
// OIMSDK.getInstance().getUserInfo(msgBody.getMsg_from()).getName(), // 发送者名称。当前未作空判断
// 0);
// }
// } else if (oimMsg.getType() == OIMSessionTypeEnum.GROUP.getType()) {
// // 群聊。2021年1月19日 暂未支持群聊
//
// } else {
// // 其它类型。比如系统通知
//
// }
// } else {
//
// }
}
......
package com.offcn.imclient.ui;
package com.offcn.im.demo.ui;
import android.content.Intent;
import android.os.Build;
......@@ -6,15 +6,10 @@ import android.os.Handler;
import android.view.WindowManager;
import com.jyall.base.base.BaseActivity;
import com.offcn.imclient.R;
import com.offcn.imclient.util.LoginManager;
import com.offcn.live.im.util.ZGLUtils;
import com.offcn.im.demo.util.LoginManager;
/**
* 闪屏页
*
* @author wangwenlong
* @date 2020/12/10
* 闪屏页。三方业务页面
*/
public class SplashActivity extends BaseActivity {
private static final String TAG = SplashActivity.class.getSimpleName();
......@@ -26,7 +21,7 @@ public class SplashActivity extends BaseActivity {
@Override
protected void initViewsAndEvents() {
// 设置全屏效果
if (Build.VERSION.SDK_INT >= 28) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.layoutInDisplayCutoutMode
......@@ -37,6 +32,7 @@ public class SplashActivity extends BaseActivity {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
// 模拟延时
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
......@@ -57,6 +53,9 @@ public class SplashActivity extends BaseActivity {
}
/**
* 判断是否登录
*/
private void exeLogin() {
if (LoginManager.isLogin(this)) {
startActivity(new Intent(this, MainActivity.class));
......
package com.offcn.imclient.util;
package com.offcn.im.demo.util;
public class Constants {
......
package com.offcn.imclient.util;
package com.offcn.im.demo.util;
import android.content.Context;
import android.text.TextUtils;
import com.jyall.base.util.SharedPrefUtils;
import com.offcn.imclient.bean.UserBean;
import com.offcn.im.demo.bean.UserBean;
import com.offcn.live.im.util.ZGLParseUtils;
/**
......
package com.offcn.im.demo.util;
import com.jyall.base.util.ValidateUtils;
import com.offcn.im.demo.bean.UserBean;
import java.util.ArrayList;
import java.util.List;
/**
* 测试数据
*/
public class MockData {
public static List<UserBean> getUsers() {
UserBean friendBean1 = new UserBean("721573asdkjsajdka", "王721573", "", "721573ThXLFM/oGZPTks22QjPNnSvkJxD3aqwtLkmbsTlhm4t5p5G+RXCyx8SwRXv6GO1RVM3WGJzCxmef1N3WZ9euRt5tvKs1XLLYIDGe4PIEBqPrvxEReyZv0jSd+XWxE0EF");
UserBean friendBean2 = new UserBean("555853asdkjsajdka", "王555853", "", "555853ThXLFM/oGZPTks22QjPNnSvkJxD3aqwtLkmbsTlhm4t5p5G+RXCyx8SwRXv6GO1RVM3WGJzCxmef1N3WZ9euRt5tvKs1XLLYIDGe4PIEBqPrvxEReyZv0jSd+XWxE0EF");
UserBean friendBean3 = new UserBean("491503asdkjsajdka", "王491503", "", "491503ThXLFM/oGZPTks22QjPNnSvkJxD3aqwtLkmbsTlhm4t5p5G+RXCyx8SwRXv6GO1RVM3WGJzCxmef1N3WZ9euRt5tvKs1XLLYIDGe4PIEBqPrvxEReyZv0jSd+XWxE0EF");
UserBean friendBean4 = new UserBean("132661asdkjsajdka", "王132661", "", "132661ThXLFM/oGZPTks22QjPNnSvkJxD3aqwtLkmbsTlhm4t5p5G+RXCyx8SwRXv6GO1RVM3WGJzCxmef1N3WZ9euRt5tvKs1XLLYIDGe4PIEBqPrvxEReyZv0jSd+XWxE0EF");
UserBean friendBean5 = new UserBean("753977asdkjsajdka", "王753977", "", "753977ThXLFM/oGZPTks22QjPNnSvkJxD3aqwtLkmbsTlhm4t5p5G+RXCyx8SwRXv6GO1RVM3WGJzCxmef1N3WZ9euRt5tvKs1XLLYIDGe4PIEBqPrvxEReyZv0jSd+XWxE0EF");
List<UserBean> list = new ArrayList<>();
list.add(friendBean1);
list.add(friendBean2);
list.add(friendBean3);
list.add(friendBean4);
list.add(friendBean5);
return list;
}
public static String[] getUserNames() {
return new String[]{"王721573", "王555853", "王491503", "王132661", "王753977"};
}
public static UserBean getUserById(String id) {
List<UserBean> dataList = getUsers();
for (UserBean bean : dataList) {
if (bean.getUser_id().equals(id)) {
return bean;
}
}
return null;
}
public static UserBean getUserByName(String name) {
if (ValidateUtils.isEmpty(name)) {
return null;
}
List<UserBean> dataList = getUsers();
for (UserBean bean : dataList) {
if (bean.getName().equals(name)) {
return bean;
}
}
return null;
}
}
package com.offcn.im.demo.util;
import android.content.Context;
import com.offcn.live.im.OIMSDK;
public class Utils {
/**
* 退出登录,销毁
*
* @param context
*/
public static void logout(Context context) {
OIMSDK.getInstance().destroy(); // 销毁通道
LoginManager.logout(context); // 注销登录信息
// UserBeanDaoManager.getInstance().deleteAll(); // 清除通讯录信息
}
}
package com.offcn.imclient.adapter;
import android.content.Context;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.jyall.base.adapter.BaseRecyclerViewAdapter;
import com.jyall.base.adapter.RecyclerViewHolderUtil;
import com.jyall.base.util.ValidateUtils;
import com.offcn.imclient.R;
import com.offcn.imclient.bean.ServerContactBean;
import com.offcn.imclient.bean.UserBean;
import com.offcn.imclient.view.AnimatedExpandableListView;
import com.offcn.live.imkit.view.CircleImageView;
import java.util.ArrayList;
import java.util.List;
/**
* 最近会话列表适配器
*
* @author wangwenlong
* @date 2020/9/11
*/
public class ContactListExpandableAdapter extends AnimatedExpandableListView.AnimatedExpandableListAdapter {
private Context mContext;
private LayoutInflater inflater;
private List<ServerContactBean> items;
public ContactListExpandableAdapter(Context context, List<ServerContactBean> list) {
mContext = context;
inflater = LayoutInflater.from(context);
items = list;
}
public void setData(List<ServerContactBean> items) {
this.items = items;
notifyDataSetChanged();
}
@Override
public UserBean getChild(int groupPosition, int childPosition) {
return items.get(groupPosition).getList().get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getRealChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder holder;
UserBean item = getChild(groupPosition, childPosition);
if (convertView == null) {
holder = new ChildHolder();
convertView = inflater.inflate(R.layout.item_contact_child, parent, false);
holder.title = (TextView) convertView.findViewById(R.id.tv_name);
holder.avatar = convertView.findViewById(R.id.iv_avatar);
convertView.setTag(holder);
} else {
holder = (ChildHolder) convertView.getTag();
}
if (childPosition == 0) {
holder.title.setText("群发消息");
holder.avatar.setImageResource(R.mipmap.ic_chat_group_mixed);
} else {
holder.title.setText(item.getName());
Glide.with(mContext).load(item.getAvatar()).placeholder(R.mipmap.ic_teacher).into(holder.avatar);
}
return convertView;
}
@Override
public int getRealChildrenCount(int groupPosition) {
return items.get(groupPosition).getList().size();
}
@Override
public ServerContactBean getGroup(int groupPosition) {
return items.get(groupPosition);
}
@Override
public int getGroupCount() {
return items.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupHolder holder;
ServerContactBean item = getGroup(groupPosition);
if (convertView == null) {
holder = new GroupHolder();
convertView = inflater.inflate(R.layout.item_contact_group, parent, false);
holder.title = (TextView) convertView.findViewById(R.id.tv_name);
holder.count = (TextView) convertView.findViewById(R.id.tv_count);
holder.ivChat = convertView.findViewById(R.id.iv_chat);
holder.ivIndicator = convertView.findViewById(R.id.iv_indicator);
convertView.setTag(holder);
} else {
holder = (GroupHolder) convertView.getTag();
}
holder.title.setText(item.getKey());
int itemCount = 1;
if (!ValidateUtils.isEmpty(item.getList())) {
itemCount = item.getList().size();
}
--itemCount;
if (itemCount <= 0) {
holder.count.setVisibility(View.GONE);
} else {
holder.count.setVisibility(View.VISIBLE);
holder.count.setText(String.valueOf(itemCount));
}
holder.ivChat.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnContactItemElementClickListener != null) {
mOnContactItemElementClickListener.onClickChat(groupPosition, 0);
}
}
});
holder.ivIndicator.setImageResource(isExpanded ? R.mipmap.ic_group_indicator_on : R.mipmap.ic_group_indicator_off);
return convertView;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isChildSelectable(int arg0, int arg1) {
return true;
}
private static class ChildHolder {
TextView title;
ImageView avatar;
}
private static class GroupHolder {
TextView title;
TextView count;
ImageView ivChat;
ImageView ivIndicator;
}
public void setOnContactItemElementClickListener(OnContactItemElementClickListener onContactItemElementClickListener) {
mOnContactItemElementClickListener = onContactItemElementClickListener;
}
OnContactItemElementClickListener mOnContactItemElementClickListener;
public interface OnContactItemElementClickListener {
void onClickChat(int groupPosition, int childPosition);
}
}
package com.offcn.imclient.bean;
import java.io.Serializable;
import java.util.List;
public class ServerContactBean implements Serializable {
private String group_id;
private String key;
private List<UserBean> list;
public String getGroup_id() {
return group_id;
}
public void setGroup_id(String group_id) {
this.group_id = group_id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public List<UserBean> getList() {
return list;
}
public void setList(List<UserBean> list) {
this.list = list;
}
}
package com.offcn.imclient.bean;
import java.util.List;
public class ServerContactBeanWrapper {
public List<ServerContactBean> user_list;
}
package com.offcn.imclient.greendao.gen;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;
import org.greenrobot.greendao.AbstractDaoMaster;
import org.greenrobot.greendao.database.StandardDatabase;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.database.DatabaseOpenHelper;
import org.greenrobot.greendao.identityscope.IdentityScopeType;
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/**
* Master of DAO (schema version 1): knows all DAOs.
*/
public class DaoMaster extends AbstractDaoMaster {
public static final int SCHEMA_VERSION = 1;
/** Creates underlying database table using DAOs. */
public static void createAllTables(Database db, boolean ifNotExists) {
UserBeanDao.createTable(db, ifNotExists);
}
/** Drops underlying database table using DAOs. */
public static void dropAllTables(Database db, boolean ifExists) {
UserBeanDao.dropTable(db, ifExists);
}
/**
* WARNING: Drops all table on Upgrade! Use only during development.
* Convenience method using a {@link DevOpenHelper}.
*/
public static DaoSession newDevSession(Context context, String name) {
Database db = new DevOpenHelper(context, name).getWritableDb();
DaoMaster daoMaster = new DaoMaster(db);
return daoMaster.newSession();
}
public DaoMaster(SQLiteDatabase db) {
this(new StandardDatabase(db));
}
public DaoMaster(Database db) {
super(db, SCHEMA_VERSION);
registerDaoClass(UserBeanDao.class);
}
public DaoSession newSession() {
return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
}
public DaoSession newSession(IdentityScopeType type) {
return new DaoSession(db, type, daoConfigMap);
}
/**
* Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} -
*/
public static abstract class OpenHelper extends DatabaseOpenHelper {
public OpenHelper(Context context, String name) {
super(context, name, SCHEMA_VERSION);
}
public OpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory, SCHEMA_VERSION);
}
@Override
public void onCreate(Database db) {
Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
createAllTables(db, false);
}
}
/** WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name) {
super(context, name);
}
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
}
}
package com.offcn.imclient.greendao.gen;
import java.util.Map;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.AbstractDaoSession;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.identityscope.IdentityScopeType;
import org.greenrobot.greendao.internal.DaoConfig;
import com.offcn.imclient.bean.UserBean;
import com.offcn.imclient.greendao.gen.UserBeanDao;
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/**
* {@inheritDoc}
*
* @see org.greenrobot.greendao.AbstractDaoSession
*/
public class DaoSession extends AbstractDaoSession {
private final DaoConfig userBeanDaoConfig;
private final UserBeanDao userBeanDao;
public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
daoConfigMap) {
super(db);
userBeanDaoConfig = daoConfigMap.get(UserBeanDao.class).clone();
userBeanDaoConfig.initIdentityScope(type);
userBeanDao = new UserBeanDao(userBeanDaoConfig, this);
registerDao(UserBean.class, userBeanDao);
}
public void clear() {
userBeanDaoConfig.clearIdentityScope();
}
public UserBeanDao getUserBeanDao() {
return userBeanDao;
}
}
package com.offcn.imclient.greendao.gen;
import android.database.Cursor;
import android.database.sqlite.SQLiteStatement;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.Property;
import org.greenrobot.greendao.internal.DaoConfig;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.database.DatabaseStatement;
import com.offcn.imclient.bean.UserBean;
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/**
* DAO for table "USER_BEAN".
*/
public class UserBeanDao extends AbstractDao<UserBean, Long> {
public static final String TABLENAME = "USER_BEAN";
/**
* Properties of entity UserBean.<br/>
* Can be used for QueryBuilder and for referencing column names.
*/
public static class Properties {
public final static Property Id = new Property(0, Long.class, "id", true, "_id");
public final static Property User_id = new Property(1, String.class, "user_id", false, "USER_ID");
public final static Property Name = new Property(2, String.class, "name", false, "NAME");
public final static Property Username = new Property(3, String.class, "username", false, "USERNAME");
public final static Property Avatar = new Property(4, String.class, "avatar", false, "AVATAR");
public final static Property Avatar_color = new Property(5, String.class, "avatar_color", false, "AVATAR_COLOR");
public final static Property Type = new Property(6, String.class, "type", false, "TYPE");
public final static Property Token = new Property(7, String.class, "token", false, "TOKEN");
public final static Property Remark = new Property(8, String.class, "remark", false, "REMARK");
public final static Property Group_id = new Property(9, String.class, "group_id", false, "GROUP_ID");
public final static Property Group_name = new Property(10, String.class, "group_name", false, "GROUP_NAME");
}
public UserBeanDao(DaoConfig config) {
super(config);
}
public UserBeanDao(DaoConfig config, DaoSession daoSession) {
super(config, daoSession);
}
/** Creates the underlying database table. */
public static void createTable(Database db, boolean ifNotExists) {
String constraint = ifNotExists? "IF NOT EXISTS ": "";
db.execSQL("CREATE TABLE " + constraint + "\"USER_BEAN\" (" + //
"\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
"\"USER_ID\" TEXT," + // 1: user_id
"\"NAME\" TEXT," + // 2: name
"\"USERNAME\" TEXT," + // 3: username
"\"AVATAR\" TEXT," + // 4: avatar
"\"AVATAR_COLOR\" TEXT," + // 5: avatar_color
"\"TYPE\" TEXT," + // 6: type
"\"TOKEN\" TEXT," + // 7: token
"\"REMARK\" TEXT," + // 8: remark
"\"GROUP_ID\" TEXT," + // 9: group_id
"\"GROUP_NAME\" TEXT);"); // 10: group_name
}
/** Drops the underlying database table. */
public static void dropTable(Database db, boolean ifExists) {
String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"USER_BEAN\"";
db.execSQL(sql);
}
@Override
protected final void bindValues(DatabaseStatement stmt, UserBean entity) {
stmt.clearBindings();
Long id = entity.getId();
if (id != null) {
stmt.bindLong(1, id);
}
String user_id = entity.getUser_id();
if (user_id != null) {
stmt.bindString(2, user_id);
}
String name = entity.getName();
if (name != null) {
stmt.bindString(3, name);
}
String username = entity.getUsername();
if (username != null) {
stmt.bindString(4, username);
}
String avatar = entity.getAvatar();
if (avatar != null) {
stmt.bindString(5, avatar);
}
String avatar_color = entity.getAvatar_color();
if (avatar_color != null) {
stmt.bindString(6, avatar_color);
}
String type = entity.getType();
if (type != null) {
stmt.bindString(7, type);
}
String token = entity.getToken();
if (token != null) {
stmt.bindString(8, token);
}
String remark = entity.getRemark();
if (remark != null) {
stmt.bindString(9, remark);
}
String group_id = entity.getGroup_id();
if (group_id != null) {
stmt.bindString(10, group_id);
}
String group_name = entity.getGroup_name();
if (group_name != null) {
stmt.bindString(11, group_name);
}
}
@Override
protected final void bindValues(SQLiteStatement stmt, UserBean entity) {
stmt.clearBindings();
Long id = entity.getId();
if (id != null) {
stmt.bindLong(1, id);
}
String user_id = entity.getUser_id();
if (user_id != null) {
stmt.bindString(2, user_id);
}
String name = entity.getName();
if (name != null) {
stmt.bindString(3, name);
}
String username = entity.getUsername();
if (username != null) {
stmt.bindString(4, username);
}
String avatar = entity.getAvatar();
if (avatar != null) {
stmt.bindString(5, avatar);
}
String avatar_color = entity.getAvatar_color();
if (avatar_color != null) {
stmt.bindString(6, avatar_color);
}
String type = entity.getType();
if (type != null) {
stmt.bindString(7, type);
}
String token = entity.getToken();
if (token != null) {
stmt.bindString(8, token);
}
String remark = entity.getRemark();
if (remark != null) {
stmt.bindString(9, remark);
}
String group_id = entity.getGroup_id();
if (group_id != null) {
stmt.bindString(10, group_id);
}
String group_name = entity.getGroup_name();
if (group_name != null) {
stmt.bindString(11, group_name);
}
}
@Override
public Long readKey(Cursor cursor, int offset) {
return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0);
}
@Override
public UserBean readEntity(Cursor cursor, int offset) {
UserBean entity = new UserBean( //
cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // user_id
cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // name
cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // username
cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // avatar
cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // avatar_color
cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6), // type
cursor.isNull(offset + 7) ? null : cursor.getString(offset + 7), // token
cursor.isNull(offset + 8) ? null : cursor.getString(offset + 8), // remark
cursor.isNull(offset + 9) ? null : cursor.getString(offset + 9), // group_id
cursor.isNull(offset + 10) ? null : cursor.getString(offset + 10) // group_name
);
return entity;
}
@Override
public void readEntity(Cursor cursor, UserBean entity, int offset) {
entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0));
entity.setUser_id(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1));
entity.setName(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2));
entity.setUsername(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3));
entity.setAvatar(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4));
entity.setAvatar_color(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5));
entity.setType(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6));
entity.setToken(cursor.isNull(offset + 7) ? null : cursor.getString(offset + 7));
entity.setRemark(cursor.isNull(offset + 8) ? null : cursor.getString(offset + 8));
entity.setGroup_id(cursor.isNull(offset + 9) ? null : cursor.getString(offset + 9));
entity.setGroup_name(cursor.isNull(offset + 10) ? null : cursor.getString(offset + 10));
}
@Override
protected final Long updateKeyAfterInsert(UserBean entity, long rowId) {
entity.setId(rowId);
return rowId;
}
@Override
public Long getKey(UserBean entity) {
if(entity != null) {
return entity.getId();
} else {
return null;
}
}
@Override
public boolean hasKey(UserBean entity) {
return entity.getId() != null;
}
@Override
protected final boolean isEntityUpdateable() {
return true;
}
}
package com.offcn.imclient.ui;
import android.content.Intent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ExpandableListView;
import android.widget.RelativeLayout;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.jyall.base.base.BaseFragment;
import com.jyall.base.util.CommonUtils;
import com.jyall.base.util.EventBusCenter;
import com.jyall.base.util.ValidateUtils;
import com.offcn.imclient.R;
import com.offcn.imclient.adapter.ContactListExpandableAdapter;
import com.offcn.imclient.bean.ServerContactBean;
import com.offcn.imclient.bean.ServerContactBeanWrapper;
import com.offcn.imclient.bean.UserBean;
import com.offcn.imclient.util.Constants;
import com.offcn.imclient.util.LoginManager;
import com.offcn.imclient.util.UserBeanDaoManager;
import com.offcn.imclient.util.Utils;
import com.offcn.imclient.view.AnimatedExpandableListView;
import com.offcn.live.im.OIMSDK;
import com.offcn.live.im.bean.OIMSendTypeEnum;
import com.offcn.live.im.util.ZGLLogUtils;
import com.offcn.live.im.util.ZGLParseUtils;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONObject;
import java.sql.SQLInvalidAuthorizationSpecException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Handler;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
/**
* 通讯录页
*
* @author wangwenlong
* @date 2020/12/9
*/
public class ContactListFragment extends BaseFragment {
private static final String TAG = ContactListFragment.class.getSimpleName();
private RelativeLayout mContainerContact;
private AnimatedExpandableListView mRecyclerView;
private RelativeLayout mSearch;
private SwipeRefreshLayout mSwipeRefreshLayout;
private List<ServerContactBean> friends = new ArrayList<>();
private ContactListExpandableAdapter mAdapter;
@Override
protected int getContentViewId() {
return R.layout.fragment_contact_list;
}
@Override
protected boolean isRegisterEventBus() {
return true;
}
@Override
protected void init(View view) {
mContainerContact = view.findViewById(R.id.container_list);
mRecyclerView = view.findViewById(R.id.recycler_view);
mSwipeRefreshLayout = view.findViewById(R.id.refresh_layout);
mSearch = view.findViewById(R.id.search);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
getContactList();
}
});
mAdapter = new ContactListExpandableAdapter(getContext(), friends);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
View firstView = view.getChildAt(firstVisibleItem);
if (firstVisibleItem == 0 && (firstView == null || firstView.getTop() == 0)) {
mSwipeRefreshLayout.setEnabled(true);
} else {
mSwipeRefreshLayout.setEnabled(false);
}
}
});
mRecyclerView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
if (childPosition == 0) {
// 说明是自定义的群发条目
ServerContactBean contactBean = friends.get(groupPosition);
if (contactBean != null) {
// 群发消息。收集当前群所有用户id,传给聊天页
String title = contactBean.getKey();
String toId = "";
StringBuilder stringBuilder = new StringBuilder();
List<UserBean> tmpList = contactBean.getList();
if (!ValidateUtils.isEmpty(tmpList)) {
for (int i = 0; i < tmpList.size(); i++) {
UserBean tmp = tmpList.get(i);
if (tmp != null && !ValidateUtils.isEmpty(tmp.getUser_id())) {
stringBuilder.append(tmp.getUser_id());
if (i != tmpList.size() - 1) {
stringBuilder.append(",");
}
}
}
toId = stringBuilder.toString();
OIMSDK.getInstance().startChat(getActivity(), OIMSendTypeEnum.GROUP, toId, title, 0);
} else {
CommonUtils.showToast(getActivity(), "暂无学员");
}
} else {
CommonUtils.showToast(getActivity(), "获取课程信息失败");
}
} else {
UserBean userBean = friends.get(groupPosition).getList().get(childPosition);
if (userBean != null) {
OIMSDK.getInstance().startChat(getActivity(), OIMSendTypeEnum.PRIVATE, userBean.getUser_id(), userBean.getName(), 0);
} else {
CommonUtils.showToast(getActivity(), "获取学生信息失败");
}
}
return true;
}
});
mRecyclerView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
if (mRecyclerView.isGroupExpanded(groupPosition)) {
mRecyclerView.collapseGroupWithAnimation(groupPosition);
} else {
mRecyclerView.expandGroupWithAnimation(groupPosition);
}
return true;
}
});
mAdapter.setOnContactItemElementClickListener(new ContactListExpandableAdapter.OnContactItemElementClickListener() {
@Override
public void onClickChat(int groupPosition, int childPosition) {
ServerContactBean contactBean = friends.get(groupPosition);
if (contactBean != null) {
// 群发消息。收集当前群所有用户id,传给聊天页
String title = contactBean.getKey();
String toId = "";
StringBuilder stringBuilder = new StringBuilder();
List<UserBean> tmpList = contactBean.getList();
if (!ValidateUtils.isEmpty(tmpList)) {
for (int i = 0; i < tmpList.size(); i++) {
UserBean tmp = tmpList.get(i);
if (tmp != null && !ValidateUtils.isEmpty(tmp.getUser_id())) {
stringBuilder.append(tmp.getUser_id());
if (i != tmpList.size() - 1) {
stringBuilder.append(",");
}
}
}
toId = stringBuilder.toString();
OIMSDK.getInstance().startChat(getActivity(), OIMSendTypeEnum.GROUP, toId, title, 0);
} else {
CommonUtils.showToast(getActivity(), "暂无学员");
}
}
}
});
mSearch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!CommonUtils.isFastDoubleClick()) {
startActivity(new Intent(getActivity(), SearchActivity.class));
getActivity().overridePendingTransition(R.anim.push_bottom_in, R.anim.push_bottom_still);
}
}
});
getContactList();
}
@Override
protected boolean setLoadAlways() {
return false;
}
@Override
protected View isNeedEmpty() {
return mContainerContact;
}
@Override
protected void initEmptyResource() {
setEmptyRes("暂无联系人", R.mipmap.ic_empty_contact);
setErrorRes("联系人获取失败", 0);
setErrorClickListner(new View.OnClickListener() {
@Override
public void onClick(View v) {
getContactList();
}
});
}
@Override
public void onResume() {
super.onResume();
if (!ValidateUtils.isEmpty(friends)) {
for (int i = 0; i < friends.size(); i++) {
if (mRecyclerView.isGroupExpanded(i)) {
mRecyclerView.collapseGroup(i);
int finalI = i;
mRecyclerView.postDelayed(new Runnable() {
@Override
public void run() {
mRecyclerView.expandGroup(finalI);
}
}, 100);
}
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventBus(EventBusCenter eventBusCenter) {
// int eventCode = eventBusCenter.getEvenCode();
// if (eventCode == Constants.EventCode.Code_Refresh_Contact) {
//
// }
}
private void getContactList() {
if (!CommonUtils.isNetConnected(getActivity())) {
showNoNetView();
return;
}
// showLoading();
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("im_token", LoginManager.getToken(getActivity()));
RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, Utils.getServerContactUrl(), jsonObject,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
ZGLLogUtils.e(TAG, "contact success " + response.toString());
dismissLoading();
if (mSwipeRefreshLayout != null) {
mSwipeRefreshLayout.setRefreshing(false);
}
UserBeanDaoManager.getInstance().deleteAll();
try {
int rtnCode = response.getInt("code");
if (rtnCode == 0) {
ServerContactBeanWrapper beanWrapper = ZGLParseUtils.parseObjectByGson(response.getJSONObject("data").toString(), ServerContactBeanWrapper.class);
if (beanWrapper != null) {
friends = beanWrapper.user_list;
} else {
// 数据为空
friends.clear();
}
exeContactList();
} else if (rtnCode == 1 || rtnCode == 2) {
// {"code":1,"msg":"登陆过期,请重新登陆","params":{"im_token":"0XR5YOS6dg7x2lirfeX3CbjRLqPWmesaFbdsr\/M4IRZS4mYYyZILI82FT8dgqybCA4W+MxfjJDY=@ip6c.cn.rongnav.com;ip6c.cn.rongcfg.com"}}
Utils.logout(getActivity());
startActivity(new Intent(getActivity(), LoginActivity.class));
getActivity().finish();
String errorMsg = "登录异常";
if (response.has("msg")) {
errorMsg = response.getString("msg");
}
if (response.has("message")) {
errorMsg = response.getString("message");
}
CommonUtils.showToast(getActivity(), errorMsg);
} else {
showErrorView();
String errorMsg = "获取联系人失败";
if (response.has("msg")) {
errorMsg = response.getString("msg");
}
if (response.has("message")) {
errorMsg = response.getString("message");
}
CommonUtils.showToast(getActivity(), errorMsg);
}
} catch (Exception e) {
showErrorView();
CommonUtils.showToast(getActivity(), "获取联系人失败");
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
ZGLLogUtils.e(TAG, "contact error " + error.toString());
dismissLoading();
if (mSwipeRefreshLayout != null) {
mSwipeRefreshLayout.setRefreshing(false);
}
CommonUtils.showToast(getActivity(), error.toString());
}
}
);
requestQueue.add(jsonObjectRequest);
} catch (Exception e) {
dismissLoading();
}
}
private void exeContactList() {
if (!ValidateUtils.isEmpty(friends)) {
showNormalContent();
for (ServerContactBean serverContactBean : friends) {
serverContactBean.getList().add(0, new UserBean());
}
mAdapter.setData(friends);
List<UserBean> userBeanList = new ArrayList<>();
for (ServerContactBean contactBean : friends) {
userBeanList.addAll(contactBean.getList());
}
UserBeanDaoManager.getInstance().insertMulti(userBeanList);
OIMSDK.getInstance().refreshUserData();
} else {
showEmptyView();
UserBeanDaoManager.getInstance().deleteAll();
}
}
}
package com.offcn.imclient.ui;
import android.content.Intent;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.jyall.base.base.BaseActivity;
import com.jyall.base.base.H5Activity;
import com.jyall.base.util.CommonUtils;
import com.jyall.base.util.ValidateUtils;
import com.offcn.imclient.BuildConfig;
import com.offcn.imclient.R;
import com.offcn.imclient.bean.UserBean;
import com.offcn.imclient.util.LoginManager;
import com.offcn.imclient.util.Utils;
import com.offcn.live.im.util.ZGLLogUtils;
import com.offcn.live.im.util.ZGLParseUtils;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
/**
* 登录页
*
* @author wangwenlong
* @date 2020/12/10
*/
public class LoginActivity extends BaseActivity {
private static final String TAG = LoginActivity.class.getSimpleName();
EditText mEtName, mEtPwd;
TextView mTvLogin, mTvVersion, mTvPrivacy;
ImageView mIvClear, mIvEye;
private boolean isShowPassWord = true;
private static final String URL_PRIVACY = "http://xue.eoffcn.com/web/onlineschool_agreement.html";
@Override
protected int getContentViewLayoutId() {
return R.layout.activity_login;
}
@Override
protected void initViewsAndEvents() {
mEtName = findViewById(R.id.et_name);
mEtPwd = findViewById(R.id.et_pwd);
mTvLogin = findViewById(R.id.tv_login);
mTvVersion = findViewById(R.id.tv_version);
mTvPrivacy = findViewById(R.id.tv_privacy);
mIvClear = findViewById(R.id.iv_delete);
mIvEye = findViewById(R.id.iv_eye);
mTvVersion.setText("V" + BuildConfig.VERSION_NAME);
mTvPrivacy.setOnClickListener(v -> {
if (!CommonUtils.isFastDoubleClick()) {
H5Activity.open(LoginActivity.this, H5Activity.class, "隐私协议", URL_PRIVACY);
}
});
mIvClear.setOnClickListener(v -> mEtName.setText(""));
mEtName.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
mIvEye.setOnClickListener(v -> {
if (isShowPassWord) {
mIvEye.setImageDrawable(getResources().getDrawable(R.mipmap.ic_et_eye_on));
mEtPwd.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
mEtPwd.setSelection(mEtPwd.getText().toString().length());
isShowPassWord = !isShowPassWord;
} else {
mIvEye.setImageDrawable(getResources().getDrawable(R.mipmap.ic_et_eye_off));
mEtPwd.setTransformationMethod(PasswordTransformationMethod.getInstance());
mEtPwd.setSelection(mEtPwd.getText().toString().length());
isShowPassWord = !isShowPassWord;
}
});
mTvLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = mEtName.getText().toString().trim();
String pwd = mEtPwd.getText().toString().trim();
login(name, pwd);
}
});
findViewById(R.id.tv_login_test).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
login("lqy62094", "lqy62094");
}
});
}
@Override
protected void loadData() {
}
private void login(String name, String pwd) {
if (!CommonUtils.isNetConnected(this)) {
CommonUtils.showToast(this, R.string.net_off);
return;
}
if (ValidateUtils.isEmpty(name) || ValidateUtils.isEmpty(pwd)) {
CommonUtils.showToast(this, "请输入工号或密码");
return;
}
showLoading();
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("username", name);
jsonObject.put("password", pwd);
RequestQueue requestQueue = Volley.newRequestQueue(this);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, Utils.getServerLoginUrl(), jsonObject,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.e(TAG, "login success " + response.toString());
dismissLoading();
try {
if (response.getInt("code") == 0) {
if (response.getJSONObject("data") == null || response.getJSONObject("data").getJSONObject("user_info") == null) {
CommonUtils.showToast(LoginActivity.this, "用户信息获取失败");
return;
}
UserBean userBean = ZGLParseUtils.parseObjectByGson(response.getJSONObject("data").getJSONObject("user_info").toString(), UserBean.class);
if (userBean != null) {
ZGLLogUtils.e(TAG, userBean.toString());
LoginManager.login(LoginActivity.this, userBean);
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
} else {
CommonUtils.showToast(LoginActivity.this, "用户信息获取失败");
}
} else {
String errorMsg = "登录失败";
if (response.has("msg")) {
errorMsg = response.getString("msg");
}
if (response.has("message")) {
errorMsg = response.getString("message");
}
CommonUtils.showToast(LoginActivity.this, errorMsg);
}
} catch (Exception e) {
CommonUtils.showToast(LoginActivity.this, "用户信息解析失败");
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "login error " + error.toString());
dismissLoading();
CommonUtils.showToast(LoginActivity.this, error.toString());
}
});
requestQueue.add(jsonObjectRequest);
} catch (Exception e) {
}
}
}
package com.offcn.imclient.ui;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.jyall.base.base.BaseActivity;
import com.jyall.base.util.CommonUtils;
import com.jyall.base.util.KeyboardUtils;
import com.jyall.base.util.ValidateUtils;
import com.jyall.base.view.ClearEditText;
import com.offcn.imclient.R;
import com.offcn.imclient.adapter.ContactSearchAdapter;
import com.offcn.imclient.bean.UserBean;
import com.offcn.imclient.util.LoginManager;
import com.offcn.imclient.util.UserBeanDaoManager;
import com.offcn.live.im.OIMSDK;
import com.offcn.live.im.bean.OIMSendTypeEnum;
import com.offcn.live.im.util.ZGLLogUtils;
import java.util.List;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* 搜索页
*
* @author wangwenlong
* @date 2020/12/21
*/
public class SearchActivity extends BaseActivity {
private static final String TAG = SearchActivity.class.getSimpleName();
ClearEditText mEditText;
TextView mTvCancel;
RecyclerView mRecyclerView;
LinearLayout mContainerContent, mContainerNone;
private ContactSearchAdapter mSearchAdapter;
@Override
protected int getContentViewLayoutId() {
return R.layout.activity_search;
}
@Override
protected void initViewsAndEvents() {
mEditText = findViewById(R.id.et_search);
mTvCancel = findViewById(R.id.tv_cancel);
mRecyclerView = findViewById(R.id.recycler_view);
mContainerContent = findViewById(R.id.container_content);
mContainerNone = findViewById(R.id.container_none);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
mRecyclerView.setLayoutManager(linearLayoutManager);
mRecyclerView.setAdapter(mSearchAdapter = new ContactSearchAdapter(this));
mSearchAdapter.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
UserBean userBean = mSearchAdapter.getItem(position);
if (userBean != null) {
OIMSDK.getInstance().startChat(SearchActivity.this, OIMSendTypeEnum.PRIVATE, userBean.getUser_id(), userBean.getName(), 0);
} else {
CommonUtils.showToast(SearchActivity.this, "获取学生信息失败");
}
}
});
mTvCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
overridePendingTransition(R.anim.push_bottom_still, R.anim.push_bottom_out);
}
});
mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (s == null || s.length() == 0 || TextUtils.isEmpty(s.toString().trim())) {
mContainerContent.setVisibility(View.GONE);
mContainerNone.setVisibility(View.GONE);
mSearchAdapter.clear();
return;
}
String content = s.toString().trim();
searchStudentByContent(content);
}
});
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
KeyboardUtils.showSoftInput(SearchActivity.this, mEditText);
}
}, 300);
}
@Override
protected void loadData() {
}
@Override
public void onBackPressed() {
finish();
overridePendingTransition(R.anim.push_bottom_still, R.anim.push_bottom_out);
}
/**
* 查询学生
*
* @param content
*/
private void searchStudentByContent(String content) {
ZGLLogUtils.e(TAG, "searchStudentByContent " + content);
List<UserBean> list = UserBeanDaoManager.getInstance().queryByNameOrMobile(content);
if (ValidateUtils.isEmpty(list)) {
mContainerContent.setVisibility(View.GONE);
mContainerNone.setVisibility(View.VISIBLE);
mSearchAdapter.clear();
} else {
mContainerNone.setVisibility(View.GONE);
mContainerContent.setVisibility(View.VISIBLE);
mSearchAdapter.clear();
mSearchAdapter.addAll(list);
}
}
}
package com.offcn.imclient.util;
import android.content.Context;
import com.offcn.imclient.greendao.gen.DaoMaster;
import com.offcn.imclient.greendao.gen.DaoSession;
import com.offcn.live.im.util.ZGLDaoManager;
import com.offcn.live.im.util.ZGLGreenDaoUpgradeHelper;
import org.greenrobot.greendao.query.QueryBuilder;
public class DaoManager {
private static final String DB_NAME = "im-client.db";//数据库名称
private volatile static DaoManager mDaoManager;//多线程访问
private static DaoUpgradeHelper mHelper;
private static DaoMaster mDaoMaster;
private static DaoSession mDaoSession;
private Context context;
public Context getContext() {
return context;
}
private DaoManager(){
}
/**
* 使用单例模式获得操作数据库的对象
*/
public static DaoManager getInstance() {
if (mDaoManager == null) {
synchronized (ZGLDaoManager.class) {
if (mDaoManager == null) {
mDaoManager = new DaoManager();
}
}
}
return mDaoManager;
}
/**
* 初始化Context对象
*/
public void init(Context context) {
this.context = context;
}
/**
* 判断数据库是否存在,如果不存在则创建
*/
public DaoMaster getDaoMaster() {
if (null == mDaoMaster) {
mHelper = new DaoUpgradeHelper(context, DB_NAME, null);
mDaoMaster = new DaoMaster(mHelper.getWritableDatabase());
}
return mDaoMaster;
}
/**
* 完成对数据库的增删查找
*/
public DaoSession getDaoSession() {
if (null == mDaoSession) {
if (null == mDaoMaster) {
mDaoMaster = getDaoMaster();
}
mDaoSession = mDaoMaster.newSession();
}
return mDaoSession;
}
/**
* 设置debug模式开启或关闭,默认关闭
*/
public void setDebug(boolean flag) {
QueryBuilder.LOG_SQL = flag;
QueryBuilder.LOG_VALUES = flag;
}
/**
* 关闭数据库
*/
public void closeDataBase() {
closeHelper();
closeDaoSession();
}
public void closeDaoSession() {
if (null != mDaoSession) {
mDaoSession.clear();
mDaoSession = null;
}
}
public void closeHelper() {
if (mHelper != null) {
mHelper.close();
mHelper = null;
}
}
}
package com.offcn.imclient.util;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.offcn.imclient.greendao.gen.UserBeanDao;
import com.offcn.live.im.greendao.gen.DaoMaster;
import com.offcn.live.im.greendao.gen.MsgTableDao;
import com.offcn.live.im.greendao.gen.OIMMsgContentDao;
import com.offcn.live.im.greendao.gen.OIMUserBeanDao;
import com.offcn.live.im.util.ZGLMigrationHelper;
public class DaoUpgradeHelper extends DaoMaster.DevOpenHelper {
public DaoUpgradeHelper(Context context, String name) {
super(context, name);
}
public DaoUpgradeHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
ZGLMigrationHelper.migrate(db, UserBeanDao.class);
}
}
package com.offcn.imclient.util;
import android.content.Context;
import com.jyall.base.util.ValidateUtils;
import com.offcn.imclient.bean.UserBean;
import com.offcn.imclient.greendao.gen.DaoSession;
import com.offcn.imclient.greendao.gen.UserBeanDao;
import org.greenrobot.greendao.query.QueryBuilder;
import java.util.ArrayList;
import java.util.List;
public class UserBeanDaoManager {
private static final boolean DUBUG = true;
private DaoManager manager;
private UserBeanDao studentDao;
private DaoSession daoSession;
private Context mContext;
private UserBeanDaoManager() {
}
private static UserBeanDaoManager INSTANCE = new UserBeanDaoManager();
public static UserBeanDaoManager getInstance() {
return INSTANCE;
}
public void init(Context context) {
mContext = context;
manager = DaoManager.getInstance();
manager.init(context);
daoSession = manager.getDaoSession();
manager.setDebug(DUBUG);
UserBeanDao.createTable(daoSession.getDatabase(), true);
}
/**
* 添加数据,如果有重复则覆盖
*/
public void insert(UserBean student) {
manager.getDaoSession().insertOrReplace(student);
}
/**
* 添加多条数据,需要开辟新的线程
*/
public void insertMulti(final List<UserBean> students) {
manager.getDaoSession().runInTx(new Runnable() {
@Override
public void run() {
for (UserBean student : students) {
manager.getDaoSession().insertOrReplace(student);
}
}
});
}
/**
* 删除数据
*/
public void deleteStudent(UserBean student) {
manager.getDaoSession().delete(student);
}
/**
* 删除全部数据
*/
public void deleteAll() {
manager.getDaoSession().deleteAll(UserBean.class);
}
/**
* 更新数据
*/
public void updateStudent(UserBean student) {
manager.getDaoSession().update(student);
}
/**
* 按照主键返回单条数据
*/
public UserBean listOneStudent(long key) {
return manager.getDaoSession().load(UserBean.class, key);
}
/**
* 根据指定条件查询数据
*/
public List<UserBean> queryStudent() {
//查询构建器
QueryBuilder<UserBean> builder = manager.getDaoSession().queryBuilder(UserBean.class);
List<UserBean> list = builder.where(UserBeanDao.Properties.User_id.ge(1)).list();
return list;
}
/**
* 根据指定条件查询数据
*/
public UserBean queryStudentByUserId(String userId) {
//查询构建器
try {
QueryBuilder<UserBean> builder = manager.getDaoSession().queryBuilder(UserBean.class);
UserBean userBean = builder.where(UserBeanDao.Properties.User_id.eq(userId)).limit(1).unique();
return userBean;
} catch (Exception e) {
return null;
}
}
public List<UserBean> queryByNameOrMobile(String content) {
List<UserBean> result = new ArrayList<>();
try {
QueryBuilder<UserBean> builder = manager.getDaoSession().queryBuilder(UserBean.class);
List<UserBean> list = builder.where(
builder.or(
UserBeanDao.Properties.Name.like("%" + content + "%"),
UserBeanDao.Properties.Username.like("%" + content + "%")
)
)
.list();
if (!ValidateUtils.isEmpty(list)) {
for (UserBean userBean : list) {
if (!result.contains(userBean)) {
result.add(userBean);
}
}
}
} catch (Exception e) {
}
return result;
}
/**
* 查询全部数据
*/
public List<UserBean> queryAll() {
return manager.getDaoSession().loadAll(UserBean.class);
}
}
package com.offcn.imclient.util;
import android.content.Context;
import com.offcn.imclient.bean.UserBean;
import com.offcn.live.im.OIMSDK;
public class Utils {
/**
* 退出登录,销毁
*
* @param context
*/
public static void logout(Context context) {
OIMSDK.getInstance().destroy();
LoginManager.logout(context);
UserBeanDaoManager.getInstance().deleteAll();
}
public static String getServerLoginUrl() {
if (Constants.ENV_IS_TEST) {
return "http://api.study.t.eoffcn.com/web/v2/im/login";
} else {
return "http://api.study.eoffcn.com/web/v2/im/login";
}
}
public static String getServerContactUrl() {
if (Constants.ENV_IS_TEST) {
return "http://api.study.t.eoffcn.com/web/v2/im/userlist";
} else {
return "http://api.study.eoffcn.com/web/v2/im/userlist";
}
}
}
/*
* Copyright (C) 2014 Gary Guo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.offcn.imclient.view;
import java.util.ArrayList;
import java.util.List;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.Transformation;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
/**
* This class defines an ExpandableListView which supports animations for
* collapsing and expanding groups.
*/
public class AnimatedExpandableListView extends ExpandableListView {
/*
* A detailed explanation for how this class works:
*
* Animating the ExpandableListView was no easy task. The way that this
* class does it is by exploiting how an ExpandableListView works.
*
* Normally when {@link ExpandableListView#collapseGroup(int)} or
* {@link ExpandableListView#expandGroup(int)} is called, the view toggles
* the flag for a group and calls notifyDataSetChanged to cause the ListView
* to refresh all of it's view. This time however, depending on whether a
* group is expanded or collapsed, certain childViews will either be ignored
* or added to the list.
*
* Knowing this, we can come up with a way to animate our views. For
* instance for group expansion, we tell the adapter to animate the
* children of a certain group. We then expand the group which causes the
* ExpandableListView to refresh all views on screen. The way that
* ExpandableListView does this is by calling getView() in the adapter.
* However since the adapter knows that we are animating a certain group,
* instead of returning the real views for the children of the group being
* animated, it will return a fake dummy view. This dummy view will then
* draw the real child views within it's dispatchDraw function. The reason
* we do this is so that we can animate all of it's children by simply
* animating the dummy view. After we complete the animation, we tell the
* adapter to stop animating the group and call notifyDataSetChanged. Now
* the ExpandableListView is forced to refresh it's views again, except this
* time, it will get the real views for the expanded group.
*
* So, to list it all out, when {@link #expandGroupWithAnimation(int)} is
* called the following happens:
*
* 1. The ExpandableListView tells the adapter to animate a certain group.
* 2. The ExpandableListView calls expandGroup.
* 3. ExpandGroup calls notifyDataSetChanged.
* 4. As an result, getChildView is called for expanding group.
* 5. Since the adapter is in "animating mode", it will return a dummy view.
* 6. This dummy view draws the actual children of the expanding group.
* 7. This dummy view's height is animated from 0 to it's expanded height.
* 8. Once the animation completes, the adapter is notified to stop
* animating the group and notifyDataSetChanged is called again.
* 9. This forces the ExpandableListView to refresh all of it's views again.
* 10.This time when getChildView is called, it will return the actual
* child views.
*
* For animating the collapse of a group is a bit more difficult since we
* can't call collapseGroup from the start as it would just ignore the
* child items, giving up no chance to do any sort of animation. Instead
* what we have to do is play the animation first and call collapseGroup
* after the animation is done.
*
* So, to list it all out, when {@link #collapseGroupWithAnimation(int)} is
* called the following happens:
*
* 1. The ExpandableListView tells the adapter to animate a certain group.
* 2. The ExpandableListView calls notifyDataSetChanged.
* 3. As an result, getChildView is called for expanding group.
* 4. Since the adapter is in "animating mode", it will return a dummy view.
* 5. This dummy view draws the actual children of the expanding group.
* 6. This dummy view's height is animated from it's current height to 0.
* 7. Once the animation completes, the adapter is notified to stop
* animating the group and notifyDataSetChanged is called again.
* 8. collapseGroup is finally called.
* 9. This forces the ExpandableListView to refresh all of it's views again.
* 10.This time when the ListView will not get any of the child views for
* the collapsed group.
*/
@SuppressWarnings("unused")
private static final String TAG = AnimatedExpandableListAdapter.class.getSimpleName();
/**
* The duration of the expand/collapse animations
*/
private static final int ANIMATION_DURATION = 300;
private AnimatedExpandableListAdapter adapter;
public AnimatedExpandableListView(Context context) {
super(context);
}
public AnimatedExpandableListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AnimatedExpandableListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* @see ExpandableListView#setAdapter(ExpandableListAdapter)
*/
public void setAdapter(ExpandableListAdapter adapter) {
super.setAdapter(adapter);
// Make sure that the adapter extends AnimatedExpandableListAdapter
if(adapter instanceof AnimatedExpandableListAdapter) {
this.adapter = (AnimatedExpandableListAdapter) adapter;
this.adapter.setParent(this);
} else {
throw new ClassCastException(adapter.toString() + " must implement AnimatedExpandableListAdapter");
}
}
/**
* Expands the given group with an animation.
* @param groupPos The position of the group to expand
* @return Returns true if the group was expanded. False if the group was
* already expanded.
*/
@SuppressLint("NewApi")
public boolean expandGroupWithAnimation(int groupPos) {
boolean lastGroup = groupPos == adapter.getGroupCount() - 1;
if (lastGroup && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return expandGroup(groupPos, true);
}
int groupFlatPos = getFlatListPosition(getPackedPositionForGroup(groupPos));
if (groupFlatPos != -1) {
int childIndex = groupFlatPos - getFirstVisiblePosition();
if (childIndex < getChildCount()) {
// Get the view for the group is it is on screen...
View v = getChildAt(childIndex);
if (v.getBottom() >= getBottom()) {
// If the user is not going to be able to see the animation
// we just expand the group without an animation.
// This resolves the case where getChildView will not be
// called if the children of the group is not on screen
// We need to notify the adapter that the group was expanded
// without it's knowledge
adapter.notifyGroupExpanded(groupPos);
return expandGroup(groupPos);
}
}
}
// Let the adapter know that we are starting the animation...
adapter.startExpandAnimation(groupPos, 0);
// Finally call expandGroup (note that expandGroup will call
// notifyDataSetChanged so we don't need to)
return expandGroup(groupPos);
}
/**
* Collapses the given group with an animation.
* @param groupPos The position of the group to collapse
* @return Returns true if the group was collapsed. False if the group was
* already collapsed.
*/
public boolean collapseGroupWithAnimation(int groupPos) {
int groupFlatPos = getFlatListPosition(getPackedPositionForGroup(groupPos));
if (groupFlatPos != -1) {
int childIndex = groupFlatPos - getFirstVisiblePosition();
if (childIndex >= 0 && childIndex < getChildCount()) {
// Get the view for the group is it is on screen...
View v = getChildAt(childIndex);
if (v.getBottom() >= getBottom()) {
// If the user is not going to be able to see the animation
// we just collapse the group without an animation.
// This resolves the case where getChildView will not be
// called if the children of the group is not on screen
return collapseGroup(groupPos);
}
} else {
// If the group is offscreen, we can just collapse it without an
// animation...
return collapseGroup(groupPos);
}
}
// Get the position of the firstChild visible from the top of the screen
long packedPos = getExpandableListPosition(getFirstVisiblePosition());
int firstChildPos = getPackedPositionChild(packedPos);
int firstGroupPos = getPackedPositionGroup(packedPos);
// If the first visible view on the screen is a child view AND it's a
// child of the group we are trying to collapse, then set that
// as the first child position of the group... see
// {@link #startCollapseAnimation(int, int)} for why this is necessary
firstChildPos = firstChildPos == -1 || firstGroupPos != groupPos ? 0 : firstChildPos;
// Let the adapter know that we are going to start animating the
// collapse animation.
adapter.startCollapseAnimation(groupPos, firstChildPos);
// Force the listview to refresh it's views
adapter.notifyDataSetChanged();
return isGroupExpanded(groupPos);
}
private int getAnimationDuration() {
return ANIMATION_DURATION;
}
/**
* Used for holding information regarding the group.
*/
private static class GroupInfo {
boolean animating = false;
boolean expanding = false;
int firstChildPosition;
/**
* This variable contains the last known height value of the dummy view.
* We save this information so that if the user collapses a group
* before it fully expands, the collapse animation will start from the
* CURRENT height of the dummy view and not from the full expanded
* height.
*/
int dummyHeight = -1;
}
/**
* A specialized adapter for use with the AnimatedExpandableListView. All
* adapters used with AnimatedExpandableListView MUST extend this class.
*/
public static abstract class AnimatedExpandableListAdapter extends BaseExpandableListAdapter {
private SparseArray<GroupInfo> groupInfo = new SparseArray<GroupInfo>();
private AnimatedExpandableListView parent;
private static final int STATE_IDLE = 0;
private static final int STATE_EXPANDING = 1;
private static final int STATE_COLLAPSING = 2;
private void setParent(AnimatedExpandableListView parent) {
this.parent = parent;
}
public int getRealChildType(int groupPosition, int childPosition) {
return 0;
}
public int getRealChildTypeCount() {
return 1;
}
public abstract View getRealChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent);
public abstract int getRealChildrenCount(int groupPosition);
private GroupInfo getGroupInfo(int groupPosition) {
GroupInfo info = groupInfo.get(groupPosition);
if (info == null) {
info = new GroupInfo();
groupInfo.put(groupPosition, info);
}
return info;
}
public void notifyGroupExpanded(int groupPosition) {
GroupInfo info = getGroupInfo(groupPosition);
info.dummyHeight = -1;
}
private void startExpandAnimation(int groupPosition, int firstChildPosition) {
GroupInfo info = getGroupInfo(groupPosition);
info.animating = true;
info.firstChildPosition = firstChildPosition;
info.expanding = true;
}
private void startCollapseAnimation(int groupPosition, int firstChildPosition) {
GroupInfo info = getGroupInfo(groupPosition);
info.animating = true;
info.firstChildPosition = firstChildPosition;
info.expanding = false;
}
private void stopAnimation(int groupPosition) {
GroupInfo info = getGroupInfo(groupPosition);
info.animating = false;
}
/**
* Override {@link #getRealChildType(int, int)} instead.
*/
@Override
public final int getChildType(int groupPosition, int childPosition) {
GroupInfo info = getGroupInfo(groupPosition);
if (info.animating) {
// If we are animating this group, then all of it's children
// are going to be dummy views which we will say is type 0.
return 0;
} else {
// If we are not animating this group, then we will add 1 to
// the type it has so that no type id conflicts will occur
// unless getRealChildType() returns MAX_INT
return getRealChildType(groupPosition, childPosition) + 1;
}
}
/**
* Override {@link #getRealChildTypeCount()} instead.
*/
@Override
public final int getChildTypeCount() {
// Return 1 more than the childTypeCount to account for DummyView
return getRealChildTypeCount() + 1;
}
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 0);
}
/**
* Override {@link #getChildView(int, int, boolean, View, ViewGroup)} instead.
*/
@Override
public final View getChildView(final int groupPosition, int childPosition, boolean isLastChild, View convertView, final ViewGroup parent) {
final GroupInfo info = getGroupInfo(groupPosition);
if (info.animating) {
// If this group is animating, return the a DummyView...
if (convertView instanceof DummyView == false) {
convertView = new DummyView(parent.getContext());
convertView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 0));
}
if (childPosition < info.firstChildPosition) {
// The reason why we do this is to support the collapse
// this group when the group view is not visible but the
// children of this group are. When notifyDataSetChanged
// is called, the ExpandableListView tries to keep the
// list position the same by saving the first visible item
// and jumping back to that item after the views have been
// refreshed. Now the problem is, if a group has 2 items
// and the first visible item is the 2nd child of the group
// and this group is collapsed, then the dummy view will be
// used for the group. But now the group only has 1 item
// which is the dummy view, thus when the ListView is trying
// to restore the scroll position, it will try to jump to
// the second item of the group. But this group no longer
// has a second item, so it is forced to jump to the next
// group. This will cause a very ugly visual glitch. So
// the way that we counteract this is by creating as many
// dummy views as we need to maintain the scroll position
// of the ListView after notifyDataSetChanged has been
// called.
convertView.getLayoutParams().height = 0;
return convertView;
}
final ExpandableListView listView = (ExpandableListView) parent;
final DummyView dummyView = (DummyView) convertView;
// Clear the views that the dummy view draws.
dummyView.clearViews();
// Set the style of the divider
dummyView.setDivider(listView.getDivider(), parent.getMeasuredWidth(), listView.getDividerHeight());
// Make measure specs to measure child views
final int measureSpecW = MeasureSpec.makeMeasureSpec(parent.getWidth(), MeasureSpec.EXACTLY);
final int measureSpecH = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
int totalHeight = 0;
int clipHeight = parent.getHeight();
final int len = getRealChildrenCount(groupPosition);
for (int i = info.firstChildPosition; i < len; i++) {
View childView = getRealChildView(groupPosition, i, (i == len - 1), null, parent);
LayoutParams p = (LayoutParams) childView.getLayoutParams();
if (p == null) {
p = (LayoutParams) generateDefaultLayoutParams();
childView.setLayoutParams(p);
}
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
childHeightSpec = measureSpecH;
}
childView.measure(measureSpecW, childHeightSpec);
totalHeight += childView.getMeasuredHeight();
if (totalHeight < clipHeight) {
// we only need to draw enough views to fool the user...
dummyView.addFakeView(childView);
} else {
dummyView.addFakeView(childView);
// if this group has too many views, we don't want to
// calculate the height of everything... just do a light
// approximation and break
int averageHeight = totalHeight / (i + 1);
totalHeight += (len - i - 1) * averageHeight;
break;
}
}
Object o;
int state = (o = dummyView.getTag()) == null ? STATE_IDLE : (Integer) o;
if (info.expanding && state != STATE_EXPANDING) {
ExpandAnimation ani = new ExpandAnimation(dummyView, 0, totalHeight, info);
ani.setDuration(this.parent.getAnimationDuration());
ani.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
stopAnimation(groupPosition);
notifyDataSetChanged();
dummyView.setTag(STATE_IDLE);
}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationStart(Animation animation) {}
});
dummyView.startAnimation(ani);
dummyView.setTag(STATE_EXPANDING);
} else if (!info.expanding && state != STATE_COLLAPSING) {
if (info.dummyHeight == -1) {
info.dummyHeight = totalHeight;
}
ExpandAnimation ani = new ExpandAnimation(dummyView, info.dummyHeight, 0, info);
ani.setDuration(this.parent.getAnimationDuration());
ani.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
stopAnimation(groupPosition);
listView.collapseGroup(groupPosition);
notifyDataSetChanged();
info.dummyHeight = -1;
dummyView.setTag(STATE_IDLE);
}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationStart(Animation animation) {}
});
dummyView.startAnimation(ani);
dummyView.setTag(STATE_COLLAPSING);
}
return convertView;
} else {
return getRealChildView(groupPosition, childPosition, isLastChild, convertView, parent);
}
}
@Override
public final int getChildrenCount(int groupPosition) {
GroupInfo info = getGroupInfo(groupPosition);
if (info.animating) {
return info.firstChildPosition + 1;
} else {
return getRealChildrenCount(groupPosition);
}
}
}
private static class DummyView extends View {
private List<View> views = new ArrayList<View>();
private Drawable divider;
private int dividerWidth;
private int dividerHeight;
public DummyView(Context context) {
super(context);
}
public void setDivider(Drawable divider, int dividerWidth, int dividerHeight) {
if(divider != null) {
this.divider = divider;
this.dividerWidth = dividerWidth;
this.dividerHeight = dividerHeight;
divider.setBounds(0, 0, dividerWidth, dividerHeight);
}
}
/**
* Add a view for the DummyView to draw.
* @param childView View to draw
*/
public void addFakeView(View childView) {
childView.layout(0, 0, getWidth(), childView.getMeasuredHeight());
views.add(childView);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
final int len = views.size();
for(int i = 0; i < len; i++) {
View v = views.get(i);
v.layout(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
}
}
public void clearViews() {
views.clear();
}
@Override
public void dispatchDraw(Canvas canvas) {
canvas.save();
if(divider != null) {
divider.setBounds(0, 0, dividerWidth, dividerHeight);
}
final int len = views.size();
for(int i = 0; i < len; i++) {
View v = views.get(i);
canvas.save();
canvas.clipRect(0, 0, getWidth(), v.getMeasuredHeight());
v.draw(canvas);
canvas.restore();
if(divider != null) {
divider.draw(canvas);
canvas.translate(0, dividerHeight);
}
canvas.translate(0, v.getMeasuredHeight());
}
canvas.restore();
}
}
private static class ExpandAnimation extends Animation {
private int baseHeight;
private int delta;
private View view;
private GroupInfo groupInfo;
private ExpandAnimation(View v, int startHeight, int endHeight, GroupInfo info) {
baseHeight = startHeight;
delta = endHeight - startHeight;
view = v;
groupInfo = info;
view.getLayoutParams().height = startHeight;
view.requestLayout();
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
int val = baseHeight + (int) (delta * interpolatedTime);
view.getLayoutParams().height = val;
groupInfo.dummyHeight = val;
view.requestLayout();
} else {
int val = baseHeight + delta;
view.getLayoutParams().height = val;
groupInfo.dummyHeight = val;
view.requestLayout();
}
}
}
}
......@@ -14,74 +14,25 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="60dp"
android:drawableTop="@mipmap/ic_logo"
android:drawableTop="@mipmap/ic_launcher"
android:drawablePadding="20dp"
android:text="在线课堂教师版"
android:text="@string/app_name"
android:textColor="@color/color_333333"
android:textSize="20sp"
android:textStyle="bold" />
<RelativeLayout
android:id="@+id/rl_username"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="40dp">
<EditText
android:id="@+id/et_name"
style="@style/loginEditText"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/iv_delete"
android:hint="请输入工号"
android:inputType="textPassword" />
<ImageView
android:id="@+id/iv_delete"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:padding="5dp"
android:src="@mipmap/ic_et_clear" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:background="@drawable/login_edit_line" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_password"
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="10dp">
<EditText
android:id="@+id/et_pwd"
style="@style/loginEditText"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/iv_eye"
android:hint="请输入密码"
android:inputType="textPassword" />
<ImageView
android:id="@+id/iv_eye"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:padding="5dp"
android:src="@mipmap/ic_et_eye_off" />
android:layout_marginTop="20dp"
android:text="点击选择登录用户" />
<View
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:background="@drawable/login_edit_line" />
</RelativeLayout>
android:layout_height="40dp"
android:background="@color/color_999999"
android:prompt="@string/spinner_default" />
<TextView
android:id="@+id/tv_login"
......@@ -94,60 +45,5 @@
android:textColor="@android:color/white"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_login_test"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:background="@color/colorPrimary"
android:gravity="center"
android:text="测试一键登录(lqy62094)"
android:textColor="@android:color/white"
android:textSize="16sp"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom|center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/tv_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="V1.0.0"
android:textColor="@color/color_999999"
tools:text="V1.0.0" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登录即代表你同意《"
android:textColor="@color/color_999999"
android:textSize="10sp" />
<TextView
android:id="@+id/tv_privacy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="隐私协议"
android:textColor="#1890ff"
android:textSize="10sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="》"
android:textColor="@color/color_999999"
android:textSize="10sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:paddingTop="@dimen/toolbar_padding_top"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_margin="15dp"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="0dp"
android:layout_height="38dp"
android:layout_weight="1"
android:background="@drawable/bg_search"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_search" />
<com.jyall.base.view.ClearEditText
android:id="@+id/et_search"
android:layout_width="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:singleLine="true"
android:background="@null"
android:textSize="13sp"
android:hint="@string/search"
android:textColor="@color/color_333333"
android:textColorHint="#CECECE" />
</LinearLayout>
<TextView
android:id="@+id/tv_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="取消"
android:textColor="@color/color_333333"
android:textSize="16sp" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/container_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/color_cecece" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="15dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/container_none"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@android:color/white"
android:gravity="center"
android:text="找不到对应用户" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_f5f5f5" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
\ No newline at end of file
......@@ -9,30 +9,9 @@
android:orientation="vertical"
android:paddingTop="@dimen/main_padding_top">
<RelativeLayout
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:background="@drawable/bg_search">
<TextView
android:layout_width="wrap_content"
android:layout_height="38dp"
android:layout_centerInParent="true"
android:drawableLeft="@mipmap/ic_search"
android:drawablePadding="5dp"
android:gravity="center"
android:text="@string/search"
android:textColor="@color/color_cecece"
android:textSize="15sp" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="15dp"
android:orientation="vertical">
<LinearLayout
......@@ -62,6 +41,7 @@
</LinearLayout>
<!-- 集成SDK内部页面-->
<fragment
android:id="@+id/chat_list_fragment"
android:name="com.offcn.live.imkit.ui.ChatListFragment"
......
......@@ -8,48 +8,9 @@
android:orientation="vertical"
android:paddingTop="@dimen/main_padding_top">
<RelativeLayout
android:id="@+id/search"
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:background="@drawable/bg_search">
<TextView
android:layout_width="wrap_content"
android:layout_height="38dp"
android:layout_centerInParent="true"
android:drawableLeft="@mipmap/ic_search"
android:drawablePadding="5dp"
android:gravity="center"
android:text="@string/search"
android:textColor="@color/color_cecece"
android:textSize="15sp" />
</RelativeLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/container_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="15dp">
<com.offcn.imclient.view.AnimatedExpandableListView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:childDivider="@null"
android:divider="@null"
android:groupIndicator="@null" />
</RelativeLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
android:layout_height="match_parent"/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_height="60dp"
android:gravity="center_vertical"
android:paddingLeft="30dp">
android:paddingLeft="15dp">
<ImageView
android:id="@+id/iv_avatar"
......@@ -17,6 +17,6 @@
android:singleLine="true"
android:ellipsize="end"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp" />
android:layout_marginLeft="10dp" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center_vertical">
<ImageView
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginLeft="10dp"
tools:src="@mipmap/ic_group_indicator_off"
android:id="@+id/iv_indicator"
android:layout_marginRight="10dp" />
<TextView
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:singleLine="true"
tools:text="我是课程标题我是课程标题我是课程标题我是课程标题我是课程标题我是课程标题我是课程标题" />
<TextView
android:id="@+id/tv_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
tools:text="25人" />
<ImageView
android:id="@+id/iv_chat"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:src="@mipmap/ic_chat_group" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.offcn.live.imkit.view.CircleImageView
android:id="@+id/rc_img"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_alignParentStart="true"
android:layout_marginLeft="16dp"
android:layout_marginTop="9dp"
android:layout_marginBottom="9dp"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="13dp"
android:layout_marginRight="16dp"
android:ellipsize="end"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="@color/color_333333"
android:textSize="15dp" />
</LinearLayout>
<View
android:id="@+id/view_line"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginStart="65dp"
android:background="@color/color_e5e5e5" />
</LinearLayout>
</RelativeLayout>
\ No newline at end of file
<resources>
<string name="app_name">在线课堂教师版</string>
<string name="app_name">中公IMDemo</string>
<string name="spinner_default">请选择用户</string>
<string name="push_mi_appid">2882303761518931116</string>
<string name="push_mi_appkey">5231893188116</string>
<string name="push_vivo_appid">105430534</string>
<string name="push_vivo_appkey">d2b91a4841e49704211a25bde2dc9e11</string>
<string name="push_oppo_appkey">1115a09757a147d3a25433e0404b9055</string>
<string name="push_oppo_appsecret">239dd9255c5349bab1bd526301e07bae</string>
<string name="search">搜索姓名或者手机号</string>
<string name="push_mi_appid">2882303761518588294</string>
<string name="push_mi_appkey">5761858881294</string>
<string name="push_vivo_appid">104300660</string>
<string name="push_vivo_appkey">5920cbae23f22a915ecabf26554b644e</string>
<string name="push_oppo_appkey">aa5d4f8306b04b7c820019b906e2ce92</string>
<string name="push_oppo_appsecret">365b1426c0a14519b3f96092f0a729a9</string>
</resources>
\ No newline at end of file
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
maven {
url 'http://maven.base.eoffcn.com/repository/zglive/'
credentials {
......@@ -11,15 +8,17 @@ buildscript {
password = "zglive"
}
}
maven {url 'https://developer.huawei.com/repo/'}
maven {
url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
}
jcenter()
google()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
mavenCentral()
maven {
url "https://jitpack.io"
}
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.1"
......@@ -33,9 +32,6 @@ buildscript {
allprojects {
repositories {
google()
jcenter()
maven {
url 'http://maven.base.eoffcn.com/repository/zglive/'
credentials {
......@@ -43,14 +39,17 @@ allprojects {
password = "zglive"
}
}
maven {url 'https://developer.huawei.com/repo/'}
maven {
url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
}
jcenter()
google()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
mavenCentral()
maven {
url "https://jitpack.io"
}
maven {url 'https://developer.huawei.com/repo/'}
}
}
......
该项目为 IM 客户端
集成IMKIT
\ No newline at end of file
该项目为中公IMSDK 的 Android客户端Demo示例
\ No newline at end of file
include ':app'
rootProject.name = "IMTeacher"
\ No newline at end of file
rootProject.name = "IMSDK_Demo"
\ No newline at end of file
++ /dev/null
------------华为------------
包名:
com.offcn.imteacher
APP ID:
103563811
API key:
CgB6e3x9dUrnhfW7QTy8zKNAopJZKlP2p33BRXsZV1ZQ6QJZkrxI0Ozaz/pjIfNSOVO9cl04nzTBthSirmV5AcFO
APP SECRET:
ccb23fec2495a197a98435b04de07c8608bd4d934f8c8068b53a833dffc8be28
SHA256:
6D:B6:2B:2A:27:2E:BD:BB:A5:91:56:E2:EB:91:DF:81:D6:34:F1:72:48:63:41:B7:98:C9:B0:BC:88:88:E7:D7
------------小米----------
包名:
com.offcn.imteacher
AppID:
2882303761518931116
AppKey:
5231893188116
AppSecret:
YxfHTk1OHPmctQzgRDZ+Yg==
----------VIVO----------------
应用包名:com.offcn.imteacher
AppID:105430534
AppKey:d2b91a4841e49704211a25bde2dc9e11
AppSecret:9ae21754-7e4a-42e2-8546-20b249d60743
----------OPPO---------------
appid: 30441883
appkey:1115a09757a147d3a25433e0404b9055(勿外泄)
appsecret:239dd9255c5349bab1bd526301e07bae(勿外泄)
appserversecret:b36e458a2e7a46188058a61bdbb9a633(勿外泄)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment