私聊改造:输入体验优化

This commit is contained in:
huangjian
2023-01-11 19:09:36 +08:00
parent 42aea570b3
commit 69f0d76330
34 changed files with 1455 additions and 1021 deletions

View File

@@ -676,7 +676,6 @@
android:label="单聊界面" android:label="单聊界面"
android:launchMode="singleTop" android:launchMode="singleTop"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar"
android:windowSoftInputMode="stateHidden|adjustResize" /> android:windowSoftInputMode="stateHidden|adjustResize" />
<activity <activity
android:name=".ui.im.avtivity.AddBlackListActivity" android:name=".ui.im.avtivity.AddBlackListActivity"
@@ -952,10 +951,12 @@
<!-- 房间内私聊 --> <!-- 房间内私聊 -->
<activity <activity
android:name=".room_chat.activity.NimRoomP2PMessageActivity" android:name=".room_chat.activity.NimRoomP2PMessageActivity"
android:theme="@style/room_message_activity" /> android:theme="@style/room_message_activity"
android:windowSoftInputMode="stateHidden|adjustResize" />
<activity <activity
android:name=".room_chat.activity.RoomMsgActivity" android:name=".room_chat.activity.RoomMsgActivity"
android:theme="@style/room_message_activity" /> android:theme="@style/room_message_activity"
android:windowSoftInputMode="stateHidden|adjustNothing" />
<activity <activity
android:name=".room_chat.activity.RoomNewbieActivity" android:name=".room_chat.activity.RoomNewbieActivity"
android:theme="@style/room_message_activity" /> android:theme="@style/room_message_activity" />

View File

@@ -0,0 +1,44 @@
package com.mango.moshen.ui.im;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.effective.android.panel.PanelSwitchHelper;
public class AutoHidePanelRecyclerView extends RecyclerView {
PanelSwitchHelper panelSwitchHelper;
public void setPanelSwitchHelper(PanelSwitchHelper panelSwitchHelper) {
this.panelSwitchHelper = panelSwitchHelper;
}
public AutoHidePanelRecyclerView(Context context) {
this(context, null);
}
public AutoHidePanelRecyclerView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoHidePanelRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setLayoutManager(new LinearLayoutManager(context));
}
@Override
public boolean onTouchEvent(MotionEvent e) {
if (e != null && e.getAction() != MotionEvent.ACTION_CANCEL) {
if (panelSwitchHelper != null) {
panelSwitchHelper.hookSystemBackByPanelSwitcher();
}
}
return super.onTouchEvent(e);
}
}

View File

@@ -7,7 +7,9 @@ import com.netease.nim.uikit.api.model.contact.ContactEventListener;
import com.netease.nim.uikit.api.model.session.SessionCustomization; import com.netease.nim.uikit.api.model.session.SessionCustomization;
import com.netease.nim.uikit.api.model.session.SessionEventListener; import com.netease.nim.uikit.api.model.session.SessionEventListener;
import com.netease.nim.uikit.business.session.actions.BaseAction; import com.netease.nim.uikit.business.session.actions.BaseAction;
import com.netease.nim.uikit.business.session.actions.CameraAction;
import com.netease.nim.uikit.business.session.actions.ImageAction; import com.netease.nim.uikit.business.session.actions.ImageAction;
import com.netease.nim.uikit.business.session.actions.PhotoAction;
import com.netease.nimlib.sdk.msg.model.IMMessage; import com.netease.nimlib.sdk.msg.model.IMMessage;
import com.mango.moshen.community.holder.DynamicSysHolder; import com.mango.moshen.community.holder.DynamicSysHolder;
import com.mango.moshen.community.im.WorldDynamicShareViewHolder; import com.mango.moshen.community.im.WorldDynamicShareViewHolder;
@@ -116,10 +118,11 @@ public class ImInitHelper {
private void initP2PSessionCustomization() { private void initP2PSessionCustomization() {
SessionCustomization sessionCustomization = new SessionCustomization(); SessionCustomization sessionCustomization = new SessionCustomization();
ArrayList<BaseAction> actions = new ArrayList<>(); ArrayList<BaseAction> actions = new ArrayList<>();
actions.add(new ImageAction()); actions.add(new PhotoAction());
actions.add(new CameraAction());
actions.add(new GiftAction()); actions.add(new GiftAction());
sessionCustomization.actions = actions; sessionCustomization.actions = actions;
sessionCustomization.withSticker = true; sessionCustomization.withSticker = false;
NimUIKit.setCommonP2PSessionCustomization(sessionCustomization); NimUIKit.setCommonP2PSessionCustomization(sessionCustomization);
// 语音派对 // 语音派对

View File

@@ -0,0 +1,878 @@
package com.mango.moshen.ui.im;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Handler;
import android.os.SystemClock;
import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.alibaba.fastjson.JSONObject;
import com.effective.android.panel.PanelSwitchHelper;
import com.effective.android.panel.interfaces.PanelHeightMeasurer;
import com.effective.android.panel.interfaces.listener.OnPanelChangeListener;
import com.effective.android.panel.view.panel.IPanelView;
import com.effective.android.panel.view.panel.PanelView;
import com.mango.moshen.R;
import com.mango.moshen.ui.im.actions.GiftAction;
import com.mango.xchat_android_library.utils.SingleToastUtil;
import com.mango.xchat_android_library.utils.SizeUtils;
import com.netease.nim.uikit.api.NimUIKit;
import com.netease.nim.uikit.api.UIKitOptions;
import com.netease.nim.uikit.api.model.session.SessionCustomization;
import com.netease.nim.uikit.business.ait.AitTextChangeListener;
import com.netease.nim.uikit.business.session.actions.BaseAction;
import com.netease.nim.uikit.business.session.actions.CameraAction;
import com.netease.nim.uikit.business.session.actions.PhotoAction;
import com.netease.nim.uikit.business.session.emoji.EmoticonPickerView;
import com.netease.nim.uikit.business.session.emoji.IEmoticonSelectedListener;
import com.netease.nim.uikit.business.session.emoji.MoonUtil;
import com.netease.nim.uikit.business.session.event.ActiveEvent;
import com.netease.nim.uikit.business.session.module.Container;
import com.netease.nim.uikit.business.session.module.input.ActionsPanel;
import com.netease.nim.uikit.business.session.module.input.NimAudioChatEvent;
import com.netease.nim.uikit.common.antispam.AntiSpamEvent;
import com.netease.nim.uikit.common.ui.dialog.EasyAlertDialogHelper;
import com.netease.nim.uikit.common.util.AntiSpamUtil;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.netease.nim.uikit.common.util.string.StringUtil;
import com.netease.nim.uikit.common.util.sys.ScreenUtil;
import com.netease.nim.uikit.impl.NimUIKitImpl;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.media.record.AudioRecorder;
import com.netease.nimlib.sdk.media.record.IAudioRecordCallback;
import com.netease.nimlib.sdk.media.record.RecordType;
import com.netease.nimlib.sdk.msg.MessageBuilder;
import com.netease.nimlib.sdk.msg.MsgService;
import com.netease.nimlib.sdk.msg.attachment.MsgAttachment;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.CustomNotification;
import com.netease.nimlib.sdk.msg.model.CustomNotificationConfig;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.util.List;
/**
* 底部文本编辑,语音等模块
* Created by hzxuwen on 2015/6/16.
*/
public class InputPanel implements IEmoticonSelectedListener, IAudioRecordCallback, AitTextChangeListener {
private static final String TAG = "MsgSendLayout";
private static final int SHOW_LAYOUT_DELAY = 0;
protected Container container;
protected View view;
protected Handler uiHandler;
protected EditText messageEditText;// 文本消息编辑框
protected Button audioRecordBtn; // 录音按钮
protected View audioAnimLayout; // 录音动画布局
protected FrameLayout textAudioSwitchLayout; // 切换文本,语音按钮布局
protected View switchToTextButtonInInputBar;// 文本消息选择按钮
protected View switchToAudioButtonInInputBar;// 语音消息选择按钮
protected View sendMessageButtonInInputBar;// 发送消息按钮
protected View emojiButtonInInputBar;// 发送消息按钮
protected View messageInputBar;
// 表情
protected EmoticonPickerView emoticonPickerView; // 贴图表情控件
// 语音
protected AudioRecorder audioMessageHelper;
private AutoHidePanelRecyclerView messageListView;
private SessionCustomization customization;
private Chronometer time;
private TextView timerTip;
private LinearLayout timerTipContainer;
private boolean started = false;
private boolean cancelled = false;
private boolean touched = false; // 是否按着
private boolean isKeyboardShowed = true; // 是否显示键盘
private boolean isTextAudioSwitchShow; // 是否展示左侧语音按钮
// adapter
private List<BaseAction> actions;
// data
private long typingTime = 0;
private TextWatcher aitTextWatcher;
private volatile boolean disable;
private boolean isChat;
private PanelSwitchHelper mHelper;
private final Runnable showTextRunnable = new Runnable() {
@Override
public void run() {
showInputMethod(messageEditText);
}
};
private ImageView ivImage;
private ImageView ivCamera;
private ImageView ivGift;
/**
* ************************* 键盘布局切换 *******************************
*/
private final View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (v == switchToTextButtonInInputBar) {
switchToTextLayout(true);// 显示文本发送的布局
} else if (v == sendMessageButtonInInputBar) {
onTextMessageSendButtonPressed();
} else if (v == switchToAudioButtonInInputBar) {
switchToAudioLayout();
} else if (v == ivCamera) {
for (BaseAction action : actions) {
if (action instanceof CameraAction) {
action.onClick();
break;
}
}
mHelper.resetState();
} else if (v == ivGift) {
ivGift.postDelayed(() -> {
for (BaseAction action : actions) {
if (action instanceof GiftAction) {
action.onClick();
break;
}
}
}, !mHelper.isResetState() ? 300 : 0);
mHelper.resetState();
} else if (v == ivImage) {
for (BaseAction action : actions) {
if (action instanceof PhotoAction) {
action.onClick();
break;
}
}
mHelper.resetState();
}
}
};
public InputPanel(Container container, View view, List<BaseAction> actions, boolean isTextAudioSwitchShow) {
this.container = container;
this.view = view;
this.actions = actions;
this.uiHandler = new Handler();
this.isTextAudioSwitchShow = isTextAudioSwitchShow;
init();
}
public InputPanel(Container container, View view, List<BaseAction> actions) {
this(container, view, actions, true);
}
// 上滑取消录音判断
private static boolean isCancelled(View view, MotionEvent event) {
int[] location = new int[2];
view.getLocationOnScreen(location);
return event.getRawX() < location[0] || event.getRawX() > location[0] + view.getWidth()
|| event.getRawY() < location[1] - 40;
}
public void onPause() {
// 停止录音
if (audioMessageHelper != null) {
onEndAudioRecord(true);
}
}
public void onDestroy() {
// release
if (audioMessageHelper != null) {
audioMessageHelper.destroyAudioRecorder();
}
}
public boolean collapse(boolean immediately) {
boolean respond = !mHelper.isResetState();
mHelper.resetState();
return respond;
}
public void addAitTextWatcher(TextWatcher watcher) {
aitTextWatcher = watcher;
}
private void init() {
initViews();
initInputBarListener();
initTextEdit();
initAudioRecordButton();
restoreText(false);
for (int i = 0; i < actions.size(); ++i) {
actions.get(i).setIndex(i);
actions.get(i).setContainer(container);
}
if (disable) {
disableButtons();
}
if (mHelper == null) {
mHelper = new PanelSwitchHelper.Builder(container.activity)
//可选
.addKeyboardStateListener((visible, height) -> {
Log.d(TAG, "系统键盘是否可见 : " + visible + " 高度为:" + height);
})
//可选
.addEditTextFocusChangeListener((view, hasFocus) -> {
Log.d(TAG, "输入框是否获得焦点 : " + hasFocus);
})
//可选
.addViewClickListener(view -> {
if (view == null) return;
if (view.getId() == R.id.emoji_button) {
switchToTextLayout(false);
}
Log.d(TAG, "点击了View : " + view);
})
//可选
.addPanelChangeListener(new OnPanelChangeListener() {
@Override
public void onKeyboard() {
Log.d(TAG, "唤起系统输入法");
container.proxy.onInputPanelExpand();
}
@Override
public void onNone() {
Log.d(TAG, "隐藏所有面板");
}
@Override
public void onPanel(IPanelView view) {
Log.d(TAG, "唤起面板 : " + view);
container.proxy.onInputPanelExpand();
}
@Override
public void onPanelSizeChange(IPanelView panelView, boolean portrait, int oldWidth, int oldHeight, int width, int height) {
}
})
.addPanelHeightMeasurer(new PanelHeightMeasurer() {
@Override
public boolean synchronizeKeyboardHeight() {
return false;
}
@Override
public int getTargetPanelDefaultHeight() {
return ScreenUtil.dip2px(200);
}
@Override
public int getPanelTriggerId() {
return R.id.iv_image;
}
})
.addPanelHeightMeasurer(new PanelHeightMeasurer() {
@Override
public boolean synchronizeKeyboardHeight() {
return false;
}
@Override
public int getTargetPanelDefaultHeight() {
return ScreenUtil.dip2px(200);
}
@Override
public int getPanelTriggerId() {
return R.id.emoji_button;
}
})
.logTrack(true)//output log
.build();
messageListView.setPanelSwitchHelper(mHelper);
}
}
public void setCustomization(SessionCustomization customization) {
this.customization = customization;
if (customization != null) {
emoticonPickerView.setWithSticker(customization.withSticker);
}
}
public void reload(Container container, SessionCustomization customization) {
this.container = container;
setCustomization(customization);
}
private void initViews() {
messageInputBar = view.findViewById(R.id.textMessageLayout);
switchToTextButtonInInputBar = view.findViewById(R.id.buttonTextMessage);
switchToAudioButtonInInputBar = view.findViewById(R.id.buttonAudioMessage);
emojiButtonInInputBar = view.findViewById(R.id.emoji_button);
sendMessageButtonInInputBar = view.findViewById(R.id.buttonSendMessage);
messageEditText = view.findViewById(R.id.editTextMessage);
// 语音
audioRecordBtn = view.findViewById(R.id.audioRecord);
audioAnimLayout = view.findViewById(R.id.layoutPlayAudio);
time = view.findViewById(R.id.timer);
timerTip = view.findViewById(R.id.timer_tip);
timerTipContainer = view.findViewById(R.id.timer_tip_container);
// 表情
emoticonPickerView = view.findViewById(R.id.emoticon_picker_view);
emoticonPickerView.show(this);
// 显示录音按钮
switchToTextButtonInInputBar.setVisibility(View.GONE);
switchToAudioButtonInInputBar.setVisibility(View.VISIBLE);
// 文本录音按钮切换布局
textAudioSwitchLayout = view.findViewById(R.id.switchLayout);
if (isTextAudioSwitchShow) {
textAudioSwitchLayout.setVisibility(View.VISIBLE);
} else {
textAudioSwitchLayout.setVisibility(View.GONE);
}
messageListView = view.findViewById(R.id.messageListView);
ivImage = view.findViewById(R.id.iv_image);
ivCamera = view.findViewById(R.id.iv_camera);
ivGift = view.findViewById(R.id.iv_gift);
ivCamera.setOnClickListener(clickListener);
ivGift.setOnClickListener(clickListener);
}
public void disableButtons() {
if (messageEditText != null && audioRecordBtn != null &&
switchToTextButtonInInputBar != null &&
switchToAudioButtonInInputBar != null &&
emojiButtonInInputBar != null) {
messageEditText.setEnabled(false);
messageEditText.setHint("禁言中,快找管理员解除禁言吧!");
messageEditText.setHintTextColor(Color.parseColor("#999999"));
audioRecordBtn.setEnabled(false);
switchToTextButtonInInputBar.setEnabled(false);
switchToAudioButtonInInputBar.setEnabled(false);
emojiButtonInInputBar.setEnabled(false);
} else {
setDisable(true);
}
}
public void setDisable(boolean disable) {
this.disable = disable;
}
private void initInputBarListener() {
switchToTextButtonInInputBar.setOnClickListener(clickListener);
switchToAudioButtonInInputBar.setOnClickListener(clickListener);
sendMessageButtonInInputBar.setOnClickListener(clickListener);
}
private void initTextEdit() {
messageEditText.setInputType(InputType.TYPE_CLASS_TEXT);
messageEditText.setImeOptions(EditorInfo.IME_ACTION_SEND);
messageEditText.setOnEditorActionListener((v, actionId, event) -> {
//当actionId == XX_SEND 或者 XX_DONE时都触发
//或者event.getKeyCode == ENTER 且 event.getAction == ACTION_DOWN时也触发
//注意这是一定要判断event != null。因为在某些输入法上会返回null。
if (actionId == EditorInfo.IME_ACTION_SEND
|| actionId == EditorInfo.IME_ACTION_DONE
|| (event != null && KeyEvent.KEYCODE_ENTER == event.getKeyCode() && KeyEvent.ACTION_DOWN == event.getAction())) {
//处理事件
onTextMessageSendButtonPressed();
return true;
}
return false;
});
messageEditText.setOnFocusChangeListener((v, hasFocus) -> {
messageEditText.setHint("");
checkSendButtonEnable(messageEditText);
});
messageEditText.addTextChangedListener(new TextWatcher() {
private int start;
private int count;
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
this.start = start;
this.count = count;
if (aitTextWatcher != null) {
aitTextWatcher.onTextChanged(s, start, before, count);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (aitTextWatcher != null) {
aitTextWatcher.beforeTextChanged(s, start, count, after);
}
}
@Override
public void afterTextChanged(Editable s) {
checkSendButtonEnable(messageEditText);
MoonUtil.replaceEmoticons(container.activity, s, start, count);
int editEnd = messageEditText.getSelectionEnd();
messageEditText.removeTextChangedListener(this);
while (StringUtil.counterChars(s.toString()) > NimUIKitImpl.getOptions().maxInputTextLength && editEnd > 0) {
s.delete(editEnd - 1, editEnd);
editEnd--;
}
messageEditText.setSelection(Math.min(s.length(), editEnd));
messageEditText.addTextChangedListener(this);
if (aitTextWatcher != null) {
aitTextWatcher.afterTextChanged(s);
}
sendTypingCommand();
}
});
// 不展示右侧按钮时需要添加edit间距
if (!isTextAudioSwitchShow) {
try {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) messageEditText.getLayoutParams();
layoutParams.setMarginStart(SizeUtils.dp2px(view.getContext(), 12));
messageEditText.requestLayout();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/**
* 发送“正在输入”通知
*/
private void sendTypingCommand() {
if (container.account.equals(NimUIKit.getAccount())) {
return;
}
if (container.sessionType == SessionTypeEnum.Team || container.sessionType == SessionTypeEnum.ChatRoom) {
return;
}
if (System.currentTimeMillis() - typingTime > 5000L) {
typingTime = System.currentTimeMillis();
CustomNotification command = new CustomNotification();
command.setSessionId(container.account);
command.setSessionType(container.sessionType);
CustomNotificationConfig config = new CustomNotificationConfig();
config.enablePush = false;
config.enableUnreadCount = false;
command.setConfig(config);
JSONObject json = new JSONObject();
json.put("id", "1");
command.setContent(json.toString());
NIMClient.getService(MsgService.class).sendCustomNotification(command);
}
}
// 点击edittext切换键盘和更多布局
private void switchToTextLayout(boolean needShowInput) {
audioRecordBtn.setVisibility(View.GONE);
messageEditText.setVisibility(View.VISIBLE);
switchToTextButtonInInputBar.setVisibility(View.GONE);
switchToAudioButtonInInputBar.setVisibility(View.VISIBLE);
messageInputBar.setVisibility(View.VISIBLE);
if (needShowInput) {
uiHandler.postDelayed(showTextRunnable, SHOW_LAYOUT_DELAY);
}
}
// 发送文本消息
private void onTextMessageSendButtonPressed() {
String text = messageEditText.getText().toString();
if (TextUtils.isEmpty(text.trim())) return;
EventBus.getDefault().post(new ActiveEvent());
IMMessage textMessage = createTextMessage(text);
if (AntiSpamUtil.checkLocalAntiSpam(textMessage)) {
EventBus.getDefault().post(new AntiSpamEvent());
} else {
if (container.proxy.sendMessage(textMessage)) {
restoreText(true);
}
}
}
protected IMMessage createTextMessage(String text) {
return MessageBuilder.createTextMessage(container.account, container.sessionType, text);
}
// 切换成音频,收起键盘,按钮切换成键盘
private void switchToAudioLayout() {
if (!isChat) {
SingleToastUtil.showToast("等级不够");
return;
}
Log.e(TAG, "switchToAudioLayout: ");
NimAudioChatEvent event = new NimAudioChatEvent();
event.setSuccess(o -> {
messageEditText.setVisibility(View.GONE);
audioRecordBtn.setVisibility(View.VISIBLE);
hideInputMethod();
switchToAudioButtonInInputBar.setVisibility(View.GONE);
switchToTextButtonInInputBar.setVisibility(View.VISIBLE);
mHelper.resetState();
});
Log.e(TAG, "switchToAudioLayout: post event");
EventBus.getDefault().post(event);
}
// 隐藏键盘布局
public void hideInputMethod() {
isKeyboardShowed = false;
uiHandler.removeCallbacks(showTextRunnable);
InputMethodManager imm = (InputMethodManager) container.activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(messageEditText.getWindowToken(), 0);
messageEditText.clearFocus();
}
// 显示键盘布局
private void showInputMethod(EditText editTextMessage) {
editTextMessage.requestFocus();
//如果已经显示,则继续操作时不需要把光标定位到最后
if (!isKeyboardShowed) {
editTextMessage.setSelection(editTextMessage.getText().length());
isKeyboardShowed = true;
}
mHelper.toKeyboardState();
container.proxy.onInputPanelExpand();
}
private void restoreText(boolean clearText) {
if (clearText) {
messageEditText.setText("");
}
checkSendButtonEnable(messageEditText);
}
/**
* 显示发送或更多
*
* @param editText
*/
private void checkSendButtonEnable(EditText editText) {
String textMessage = editText.getText().toString();
setEditTextState();
if (!TextUtils.isEmpty(StringUtil.removeBlanks(textMessage)) && editText.hasFocus()) {
sendMessageButtonInInputBar.setVisibility(View.VISIBLE);
} else {
sendMessageButtonInInputBar.setVisibility(View.GONE);
}
}
/**
* *************** IEmojiSelectedListener ***************
*/
@Override
public void onEmojiSelected(String key) {
Editable mEditable = messageEditText.getText();
if (key.equals("/DEL")) {
messageEditText.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
} else {
int start = messageEditText.getSelectionStart();
int end = messageEditText.getSelectionEnd();
start = (start < 0 ? 0 : start);
end = (start < 0 ? 0 : end);
mEditable.replace(start, end, key);
}
}
@Override
public void onStickerSelected(String category, String item) {
Log.i("InputPanel", "onStickerSelected, category =" + category + ", sticker =" + item);
if (customization != null) {
MsgAttachment attachment = customization.createStickerAttachment(category, item);
IMMessage stickerMessage = MessageBuilder.createCustomMessage(container.account, container.sessionType, "贴图消息", attachment);
container.proxy.sendMessage(stickerMessage);
}
}
@Override
public void onTextAdd(String content, int start, int length) {
if (messageEditText.getVisibility() != View.VISIBLE ||
(emoticonPickerView != null && emoticonPickerView.getVisibility() == View.VISIBLE)) {
switchToTextLayout(true);
} else {
uiHandler.postDelayed(showTextRunnable, SHOW_LAYOUT_DELAY);
}
messageEditText.getEditableText().insert(start, content);
}
@Override
public void onTextDelete(int start, int length) {
if (messageEditText.getVisibility() != View.VISIBLE) {
switchToTextLayout(true);
} else {
uiHandler.postDelayed(showTextRunnable, SHOW_LAYOUT_DELAY);
}
int end = start + length - 1;
messageEditText.getEditableText().replace(start, end, "");
}
public int getEditSelectionStart() {
return messageEditText.getSelectionStart();
}
/**
* ****************************** 语音 ***********************************
*/
@SuppressLint("ClickableViewAccessibility")
private void initAudioRecordButton() {
audioRecordBtn.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
touched = true;
initAudioRecord();
onStartAudioRecord();
} else if (event.getAction() == MotionEvent.ACTION_CANCEL
|| event.getAction() == MotionEvent.ACTION_UP) {
touched = false;
onEndAudioRecord(isCancelled(v, event));
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
touched = true;
cancelAudioRecord(isCancelled(v, event));
}
return false;
});
}
/**
* 初始化AudioRecord
*/
private void initAudioRecord() {
if (audioMessageHelper == null) {
UIKitOptions options = NimUIKitImpl.getOptions();
audioMessageHelper = new AudioRecorder(container.activity, options.audioRecordType, options.audioRecordMaxTime, this);
}
}
/**
* 开始语音录制
*/
private void onStartAudioRecord() {
container.activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
audioMessageHelper.startRecord();
cancelled = false;
}
/**
* 结束语音录制
*
* @param cancel
*/
private void onEndAudioRecord(boolean cancel) {
started = false;
container.activity.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
audioMessageHelper.completeRecord(cancel);
audioRecordBtn.setText(R.string.record_audio);
audioRecordBtn.setBackgroundResource(R.drawable.bg_message_voice);
stopAudioRecordAnim();
if (!cancel) {
EventBus.getDefault().post(new ActiveEvent());
}
}
/**
* 取消语音录制
*
* @param cancel
*/
private void cancelAudioRecord(boolean cancel) {
// reject
if (!started) {
return;
}
// no change
if (cancelled == cancel) {
return;
}
cancelled = cancel;
updateTimerTip(cancel);
}
/**
* 正在进行语音录制和取消语音录制,界面展示
*
* @param cancel
*/
private void updateTimerTip(boolean cancel) {
if (cancel) {
timerTip.setText(R.string.recording_cancel_tip);
timerTipContainer.setBackgroundResource(R.drawable.nim_cancel_record_red_bg);
} else {
timerTip.setText(R.string.recording_cancel);
timerTipContainer.setBackgroundResource(0);
}
}
/**
* 开始语音录制动画
*/
private void playAudioRecordAnim() {
audioAnimLayout.setVisibility(View.VISIBLE);
time.setBase(SystemClock.elapsedRealtime());
time.start();
}
/**
* 结束语音录制动画
*/
private void stopAudioRecordAnim() {
audioAnimLayout.setVisibility(View.GONE);
time.stop();
time.setBase(SystemClock.elapsedRealtime());
}
// 录音状态回调
@Override
public void onRecordReady() {
}
@Override
public void onRecordStart(File audioFile, RecordType recordType) {
started = true;
if (!touched) {
return;
}
audioRecordBtn.setText(R.string.record_audio_end);
audioRecordBtn.setBackgroundResource(R.drawable.bg_message_voice_pressed);
updateTimerTip(false); // 初始化语音动画状态
playAudioRecordAnim();
}
@Override
public void onRecordSuccess(File audioFile, long audioLength, RecordType recordType) {
IMMessage audioMessage = MessageBuilder.createAudioMessage(container.account, container.sessionType, audioFile, audioLength);
container.proxy.sendMessage(audioMessage);
}
@Override
public void onRecordFail() {
if (started) {
SingleToastUtil.showToast(R.string.recording_error);
}
}
@Override
public void onRecordCancel() {
}
@Override
public void onRecordReachedMaxTime(final int maxTime) {
stopAudioRecordAnim();
EasyAlertDialogHelper.createOkCancelDiolag(container.activity, "", container.activity.getString(R.string.recording_max_time), false, new EasyAlertDialogHelper.OnDialogActionListener() {
@Override
public void doCancelAction() {
}
@Override
public void doOkAction() {
audioMessageHelper.handleEndRecord(true, maxTime);
}
}).show();
}
public boolean isRecording() {
return audioMessageHelper != null && audioMessageHelper.isRecording();
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return;
}
int index = (requestCode << 16) >> 24;
if (index != 0) {
index--;
if (index < 0 | index >= actions.size()) {
LogUtil.d(TAG, "request code out of actions' range");
return;
}
BaseAction action = actions.get(index);
if (action != null) {
action.onActivityResult(requestCode & 0xff, resultCode, data);
}
}
}
public void reloadActions(List<BaseAction> actions) {
this.actions = actions;
for (int i = 0; i < this.actions.size(); ++i) {
this.actions.get(i).setIndex(i);
this.actions.get(i).setContainer(container);
}
ActionsPanel.init(view, actions);
}
public void setLimitLevel(boolean isChat, String msg) {
this.isChat = isChat;
setEditTextState();
}
private void setEditTextState() {
if (!isChat) {
messageEditText.setHint("暂未达到可发起私聊等级");
messageEditText.setFocusable(false);
messageEditText.setFocusableInTouchMode(false);
messageEditText.setEnabled(false);
sendMessageButtonInInputBar.setEnabled(false);
} else {
messageEditText.setHint("请输入消息");
messageEditText.setFocusable(true);
messageEditText.setFocusableInTouchMode(true);
messageEditText.setEnabled(true);
sendMessageButtonInInputBar.setEnabled(true);
}
}
}

View File

@@ -17,6 +17,8 @@ import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.mango.core.room.event.MessageSizeEvent;
import com.mango.xchat_android_library.utils.SingleToastUtil;
import com.netease.nim.uikit.R; import com.netease.nim.uikit.R;
import com.netease.nim.uikit.api.NimUIKit; import com.netease.nim.uikit.api.NimUIKit;
import com.netease.nim.uikit.api.model.user.UserInfoObserver; import com.netease.nim.uikit.api.model.user.UserInfoObserver;
@@ -65,8 +67,6 @@ import com.netease.nimlib.sdk.robot.model.RobotAttachment;
import com.netease.nimlib.sdk.robot.model.RobotMsgType; import com.netease.nimlib.sdk.robot.model.RobotMsgType;
import com.netease.nimlib.sdk.team.constant.TeamMemberType; import com.netease.nimlib.sdk.team.constant.TeamMemberType;
import com.netease.nimlib.sdk.team.model.TeamMember; import com.netease.nimlib.sdk.team.model.TeamMember;
import com.mango.core.room.event.MessageSizeEvent;
import com.mango.xchat_android_library.utils.SingleToastUtil;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
@@ -87,7 +87,7 @@ public class MessageListPanelEx {
private static final int REQUEST_CODE_FORWARD_TEAM = 0x02; private static final int REQUEST_CODE_FORWARD_TEAM = 0x02;
// 背景图片缓存 // 背景图片缓存
private static Pair<String, Bitmap> background; private static Pair<String, Bitmap> background;
private static Comparator<IMMessage> comp = new Comparator<IMMessage>() { private static final Comparator<IMMessage> comp = new Comparator<IMMessage>() {
@Override @Override
public int compare(IMMessage o1, IMMessage o2) { public int compare(IMMessage o1, IMMessage o2) {
@@ -97,7 +97,7 @@ public class MessageListPanelEx {
}; };
// container // container
private Container container; private Container container;
private View rootView; private final View rootView;
// message list view // message list view
private RecyclerView messageListView; private RecyclerView messageListView;
private List<IMMessage> items; private List<IMMessage> items;
@@ -107,15 +107,15 @@ public class MessageListPanelEx {
private IncomingMsgPrompt incomingMsgPrompt; private IncomingMsgPrompt incomingMsgPrompt;
private Handler uiHandler; private Handler uiHandler;
// 仅显示消息记录,不接收和发送消息 // 仅显示消息记录,不接收和发送消息
private boolean recordOnly; private final boolean recordOnly;
// 从服务器拉取消息记录 // 从服务器拉取消息记录
private boolean remote; private final boolean remote;
// 语音转文字 // 语音转文字
private VoiceTrans voiceTrans; private VoiceTrans voiceTrans;
// 待转发消息 // 待转发消息
private IMMessage forwardMessage; private IMMessage forwardMessage;
private CountDownTimer countDownTimer; private CountDownTimer countDownTimer;
private OnItemClickListener listener = new OnItemClickListener() { private final OnItemClickListener listener = new OnItemClickListener() {
@Override @Override
public void onItemClick(IRecyclerView adapter, View view, int position) { public void onItemClick(IRecyclerView adapter, View view, int position) {
@@ -142,7 +142,7 @@ public class MessageListPanelEx {
container.activity.startActivity(intent); container.activity.startActivity(intent);
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
// Toast.makeText(container.activity, "路径错误", Toast.LENGTH_SHORT).show(); // Toast.makeText(container.activity, "路径错误", Toast.LENGTH_SHORT).show();
SingleToastUtil.showToastShort("路径错误"); SingleToastUtil.showToast("路径错误");
} }
} else if (LinkElement.TYPE_BLOCK.equals(element.getType())) { } else if (LinkElement.TYPE_BLOCK.equals(element.getType())) {
@@ -162,7 +162,7 @@ public class MessageListPanelEx {
/** /**
* 消息状态变化观察者 * 消息状态变化观察者
*/ */
private Observer<IMMessage> messageStatusObserver = new Observer<IMMessage>() { private final Observer<IMMessage> messageStatusObserver = new Observer<IMMessage>() {
@Override @Override
public void onEvent(IMMessage message) { public void onEvent(IMMessage message) {
if (isMyMessage(message)) { if (isMyMessage(message)) {
@@ -173,7 +173,7 @@ public class MessageListPanelEx {
/** /**
* 消息附件上传/下载进度观察者 * 消息附件上传/下载进度观察者
*/ */
private Observer<AttachmentProgress> attachmentProgressObserver = new Observer<AttachmentProgress>() { private final Observer<AttachmentProgress> attachmentProgressObserver = new Observer<AttachmentProgress>() {
@Override @Override
public void onEvent(AttachmentProgress progress) { public void onEvent(AttachmentProgress progress) {
onAttachmentProgressChange(progress); onAttachmentProgressChange(progress);
@@ -182,7 +182,7 @@ public class MessageListPanelEx {
/** /**
* 本地消息接收观察者 * 本地消息接收观察者
*/ */
private MessageListPanelHelper.LocalMessageObserver incomingLocalMessageObserver = new MessageListPanelHelper.LocalMessageObserver() { private final MessageListPanelHelper.LocalMessageObserver incomingLocalMessageObserver = new MessageListPanelHelper.LocalMessageObserver() {
@Override @Override
public void onAddMessage(IMMessage message) { public void onAddMessage(IMMessage message) {
if (message == null || !container.account.equals(message.getSessionId())) { if (message == null || !container.account.equals(message.getSessionId())) {
@@ -202,7 +202,7 @@ public class MessageListPanelEx {
/** /**
* 消息撤回观察者 * 消息撤回观察者
*/ */
private Observer<RevokeMsgNotification> revokeMessageObserver = new Observer<RevokeMsgNotification>() { private final Observer<RevokeMsgNotification> revokeMessageObserver = new Observer<RevokeMsgNotification>() {
@Override @Override
public void onEvent(RevokeMsgNotification notification) { public void onEvent(RevokeMsgNotification notification) {
if (notification == null || notification.getMessage() == null) { if (notification == null || notification.getMessage() == null) {
@@ -282,10 +282,10 @@ public class MessageListPanelEx {
} }
private void initListView(IMMessage anchor) { private void initListView(IMMessage anchor) {
listviewBk = (ImageView) rootView.findViewById(R.id.message_activity_background); listviewBk = rootView.findViewById(R.id.message_activity_background);
// RecyclerView // RecyclerView
messageListView = (RecyclerView) rootView.findViewById(R.id.messageListView); messageListView = rootView.findViewById(R.id.messageListView);
messageListView.setLayoutManager(new LinearLayoutManager(container.activity)); messageListView.setLayoutManager(new LinearLayoutManager(container.activity));
messageListView.requestDisallowInterceptTouchEvent(true); messageListView.requestDisallowInterceptTouchEvent(true);
messageListView.addOnScrollListener(new RecyclerView.OnScrollListener() { messageListView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -339,12 +339,7 @@ public class MessageListPanelEx {
} }
public void scrollToBottom() { public void scrollToBottom() {
uiHandler.postDelayed(new Runnable() { doScrollToBottom();
@Override
public void run() {
doScrollToBottom();
}
}, 200);
} }
private void doScrollToBottom() { private void doScrollToBottom() {
@@ -603,15 +598,11 @@ public class MessageListPanelEx {
} }
private boolean receiveReceiptCheck(final IMMessage msg) { private boolean receiveReceiptCheck(final IMMessage msg) {
if (msg != null && msg.getSessionType() == SessionTypeEnum.P2P return msg != null && msg.getSessionType() == SessionTypeEnum.P2P
&& msg.getDirect() == MsgDirectionEnum.Out && msg.getDirect() == MsgDirectionEnum.Out
&& msg.getMsgType() != MsgTypeEnum.tip && msg.getMsgType() != MsgTypeEnum.tip
&& msg.getMsgType() != MsgTypeEnum.notification && msg.getMsgType() != MsgTypeEnum.notification
&& msg.isRemoteRead()) { && msg.isRemoteRead();
return true;
}
return false;
} }
/** /**
@@ -649,12 +640,8 @@ public class MessageListPanelEx {
} }
private boolean sendReceiptCheck(final IMMessage msg) { private boolean sendReceiptCheck(final IMMessage msg) {
if (msg == null || msg.getDirect() != MsgDirectionEnum.In || return msg != null && msg.getDirect() == MsgDirectionEnum.In &&
msg.getMsgType() == MsgTypeEnum.tip || msg.getMsgType() == MsgTypeEnum.notification) { msg.getMsgType() != MsgTypeEnum.tip && msg.getMsgType() != MsgTypeEnum.notification; // 非收到的消息Tip消息和通知类消息不要发已读回执
return false; // 非收到的消息Tip消息和通知类消息不要发已读回执
}
return true;
} }
// 删除消息 // 删除消息
@@ -699,7 +686,7 @@ public class MessageListPanelEx {
if (message == null) { if (message == null) {
// Toast.makeText(container.activity, "该类型不支持转发", Toast.LENGTH_SHORT).show(); // Toast.makeText(container.activity, "该类型不支持转发", Toast.LENGTH_SHORT).show();
SingleToastUtil.showToastShort("该类型不支持转发"); SingleToastUtil.showToast("该类型不支持转发");
return; return;
} }
@@ -742,15 +729,15 @@ public class MessageListPanelEx {
private class MessageLoader implements BaseFetchLoadAdapter.RequestLoadMoreListener, BaseFetchLoadAdapter.RequestFetchMoreListener { private class MessageLoader implements BaseFetchLoadAdapter.RequestLoadMoreListener, BaseFetchLoadAdapter.RequestFetchMoreListener {
private int loadMsgCount = NimUIKitImpl.getOptions().messageCountLoadOnce; private final int loadMsgCount = NimUIKitImpl.getOptions().messageCountLoadOnce;
private QueryDirectionEnum direction = null; private QueryDirectionEnum direction = null;
private IMMessage anchor; private final IMMessage anchor;
private boolean remote; private final boolean remote;
private boolean firstLoad = true; private boolean firstLoad = true;
private RequestCallback<List<IMMessage>> callback = new RequestCallbackWrapper<List<IMMessage>>() { private final RequestCallback<List<IMMessage>> callback = new RequestCallbackWrapper<List<IMMessage>>() {
@Override @Override
public void onResult(int code, List<IMMessage> messages, Throwable exception) { public void onResult(int code, List<IMMessage> messages, Throwable exception) {
if (code != ResponseCode.RES_SUCCESS || exception != null) { if (code != ResponseCode.RES_SUCCESS || exception != null) {
@@ -1209,8 +1196,7 @@ public class MessageListPanelEx {
@Override @Override
public void onClick() { public void onClick() {
// Toast.makeText(container.activity, finalContent, Toast.LENGTH_SHORT).show(); SingleToastUtil.showToast(finalContent);
SingleToastUtil.showToastShort(finalContent);
setEarPhoneMode(!UserPreferences.isEarPhoneModeEnable(), true); setEarPhoneMode(!UserPreferences.isEarPhoneModeEnable(), true);
} }
}); });
@@ -1257,8 +1243,7 @@ public class MessageListPanelEx {
@Override @Override
public void onClick() { public void onClick() {
if (!NetworkUtil.isNetAvailable(container.activity)) { if (!NetworkUtil.isNetAvailable(container.activity)) {
// Toast.makeText(container.activity, R.string.network_is_not_available, Toast.LENGTH_SHORT).show(); SingleToastUtil.showToast(R.string.network_is_not_available);
SingleToastUtil.showToastShort(R.string.network_is_not_available);
return; return;
} }
NIMClient.getService(MsgService.class).revokeMessage(item).setCallback(new RequestCallback<Void>() { NIMClient.getService(MsgService.class).revokeMessage(item).setCallback(new RequestCallback<Void>() {
@@ -1271,11 +1256,9 @@ public class MessageListPanelEx {
@Override @Override
public void onFailed(int code) { public void onFailed(int code) {
if (code == ResponseCode.RES_OVERDUE) { if (code == ResponseCode.RES_OVERDUE) {
// Toast.makeText(container.activity, R.string.revoke_failed, Toast.LENGTH_SHORT).show(); SingleToastUtil.showToast(R.string.revoke_failed);
SingleToastUtil.showToastShort(R.string.revoke_failed);
} else { } else {
// Toast.makeText(container.activity, "revoke msg failed, code:" + code, Toast.LENGTH_SHORT).show(); SingleToastUtil.showToast("revoke msg failed, code:" + code);
SingleToastUtil.showToastShort("revoke msg failed, code:" + code);
} }
} }

View File

@@ -17,6 +17,31 @@ import androidx.annotation.Nullable;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.mango.core.audio.event.VoiceShakeHeartEvent;
import com.mango.core.auth.AuthModel;
import com.mango.core.im.friend.IMFriendModel;
import com.mango.core.mentoring_relationship.event.MentoringSuccessEvent;
import com.mango.core.noble.NobleUtil;
import com.mango.core.praise.PraiseModel;
import com.mango.core.praise.event.IsLikedEvent;
import com.mango.core.praise.event.PraiseEvent;
import com.mango.core.user.UserModel;
import com.mango.core.user.bean.UserDetailInfo;
import com.mango.core.user.bean.UserInfo;
import com.mango.core.utils.StringExtensionKt;
import com.mango.core.utils.SystemUidUtil;
import com.mango.core.utils.net.BeanObserver;
import com.mango.moshen.R;
import com.mango.moshen.avroom.activity.AVRoomActivity;
import com.mango.moshen.common.widget.CustomImageSpan;
import com.mango.moshen.mentoring_relationship.dialog.BuildMentoringRelationshipSuccessDialog;
import com.mango.moshen.ui.im.audio.ShakeHeartDialogFragment;
import com.mango.moshen.ui.im.fragment.MessageFragment;
import com.mango.moshen.ui.user.UserInfoActivity;
import com.mango.moshen.ui.utils.ImageLoadUtils;
import com.mango.xchat_android_library.utils.ListUtils;
import com.mango.xchat_android_library.utils.SingleToastUtil;
import com.netease.nim.uikit.StatusBarUtil;
import com.netease.nim.uikit.api.NimUIKit; import com.netease.nim.uikit.api.NimUIKit;
import com.netease.nim.uikit.api.model.contact.ContactChangedObserver; import com.netease.nim.uikit.api.model.contact.ContactChangedObserver;
import com.netease.nim.uikit.api.model.main.OnlineStateChangeObserver; import com.netease.nim.uikit.api.model.main.OnlineStateChangeObserver;
@@ -31,33 +56,6 @@ import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.msg.MsgServiceObserve; import com.netease.nimlib.sdk.msg.MsgServiceObserve;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.CustomNotification; import com.netease.nimlib.sdk.msg.model.CustomNotification;
import com.mango.moshen.R;
import com.mango.moshen.avroom.activity.AVRoomActivity;
import com.mango.moshen.common.widget.CustomImageSpan;
import com.mango.moshen.ui.im.audio.ShakeHeartDialogFragment;
import com.mango.moshen.ui.im.fragment.MessageFragment;
import com.mango.moshen.ui.user.UserInfoActivity;
import com.mango.moshen.ui.utils.ImageLoadUtils;
import com.mango.moshen.mentoring_relationship.dialog.BuildMentoringRelationshipSuccessDialog;
import com.mango.core.audio.event.VoiceShakeHeartEvent;
import com.mango.core.auth.AuthModel;
import com.mango.core.im.friend.IMFriendModel;
import com.mango.core.initial.InitialModel;
import com.mango.core.initial.bean.InitInfo;
import com.mango.core.level.UserLevelVo;
import com.mango.core.mentoring_relationship.event.MentoringSuccessEvent;
import com.mango.core.noble.NobleUtil;
import com.mango.core.praise.PraiseModel;
import com.mango.core.praise.event.IsLikedEvent;
import com.mango.core.praise.event.PraiseEvent;
import com.mango.core.user.UserModel;
import com.mango.core.user.bean.UserDetailInfo;
import com.mango.core.user.bean.UserInfo;
import com.mango.core.utils.StringExtensionKt;
import com.mango.core.utils.SystemUidUtil;
import com.mango.core.utils.net.BeanObserver;
import com.mango.xchat_android_library.utils.ListUtils;
import com.mango.xchat_android_library.utils.SingleToastUtil;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
@@ -414,21 +412,6 @@ public class NimP2PMessageActivity extends NewBaseMessageActivity {
MessageFragment fragment = new MessageFragment(); MessageFragment fragment = new MessageFragment();
fragment.setArguments(arguments); fragment.setArguments(arguments);
fragment.setContainerId(R.id.message_fragment_container); fragment.setContainerId(R.id.message_fragment_container);
// 等级限制:官方小秘书 和 系统消息,不设置等级限制
if (!SystemUidUtil.isSystemUid(sessionId)) {
UserInfo userInfo = UserModel.get().getCacheLoginUserInfo();
if (userInfo != null) {
UserLevelVo userLevelVo = userInfo.getUserLevelVo();
if (userLevelVo != null) {
fragment.setCurrentLevel(userLevelVo.experLevelSeq);
}
}
InitInfo initInfo = InitialModel.get().getCacheInitInfo();
if (initInfo != null) {
fragment.setLimitLevel(initInfo.getPrivateChatLevelNo());
}
}
return fragment; return fragment;
} }
@@ -486,4 +469,16 @@ public class NimP2PMessageActivity extends NewBaseMessageActivity {
ShakeHeartDialogFragment shakeHeartDialogFragment = ShakeHeartDialogFragment.newInstance(event.showTextHint); ShakeHeartDialogFragment shakeHeartDialogFragment = ShakeHeartDialogFragment.newInstance(event.showTextHint);
shakeHeartDialogFragment.show(getSupportFragmentManager(), "shake_heart"); shakeHeartDialogFragment.show(getSupportFragmentManager(), "shake_heart");
} }
@Override
protected boolean needSteepStateBar() {
return true;
}
@Override
protected void setStatusBar() {
super.setStatusBar();
StatusBarUtil.transparencyBar(this);
StatusBarUtil.StatusBarLightMode(this);
}
} }

View File

@@ -20,6 +20,24 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.mango.core.UriProvider;
import com.mango.core.auth.AuthModel;
import com.mango.core.im.chatterbox.ChatterBoxHelper;
import com.mango.core.im.chatterbox.HideInputEvent;
import com.mango.core.room.event.MessageSizeEvent;
import com.mango.core.statistic.StatisticManager;
import com.mango.core.statistic.protocol.StatisticsProtocol;
import com.mango.moshen.R;
import com.mango.moshen.common.widget.OriginalDrawStatusClickSpan;
import com.mango.moshen.ui.im.GreetPresenter;
import com.mango.moshen.ui.im.InputPanel;
import com.mango.moshen.ui.im.MessageListPanelEx;
import com.mango.moshen.ui.im.chat.MVHChatterBoxStart;
import com.mango.moshen.ui.im.model.IMCustomModel;
import com.mango.moshen.ui.webview.CommonWebViewActivity;
import com.mango.moshen.utils.PushMessageHandler;
import com.mango.xchat_android_library.utils.SingleToastUtil;
import com.mango.xchat_android_library.utils.config.BasicConfig;
import com.netease.nim.uikit.api.UIKitOptions; import com.netease.nim.uikit.api.UIKitOptions;
import com.netease.nim.uikit.api.model.main.CustomPushContentProvider; import com.netease.nim.uikit.api.model.main.CustomPushContentProvider;
import com.netease.nim.uikit.api.model.session.SessionCustomization; import com.netease.nim.uikit.api.model.session.SessionCustomization;
@@ -28,7 +46,6 @@ import com.netease.nim.uikit.business.session.actions.BaseAction;
import com.netease.nim.uikit.business.session.constant.Extras; import com.netease.nim.uikit.business.session.constant.Extras;
import com.netease.nim.uikit.business.session.module.Container; import com.netease.nim.uikit.business.session.module.Container;
import com.netease.nim.uikit.business.session.module.ModuleProxy; import com.netease.nim.uikit.business.session.module.ModuleProxy;
import com.netease.nim.uikit.business.session.module.input.InputPanel;
import com.netease.nim.uikit.business.session.module.input.NimAudioChatEvent; import com.netease.nim.uikit.business.session.module.input.NimAudioChatEvent;
import com.netease.nim.uikit.business.session.module.input.NimImageActionEvent; import com.netease.nim.uikit.business.session.module.input.NimImageActionEvent;
import com.netease.nim.uikit.common.fragment.TFragment; import com.netease.nim.uikit.common.fragment.TFragment;
@@ -51,25 +68,6 @@ import com.netease.nimlib.sdk.robot.model.NimRobotInfo;
import com.netease.nimlib.sdk.robot.model.RobotAttachment; import com.netease.nimlib.sdk.robot.model.RobotAttachment;
import com.netease.nimlib.sdk.robot.model.RobotMsgType; import com.netease.nimlib.sdk.robot.model.RobotMsgType;
import com.tbruyelle.rxpermissions2.RxPermissions; import com.tbruyelle.rxpermissions2.RxPermissions;
import com.mango.moshen.R;
import com.mango.moshen.common.widget.OriginalDrawStatusClickSpan;
import com.mango.moshen.ui.im.GreetPresenter;
import com.mango.moshen.ui.im.MessageListPanelEx;
import com.mango.moshen.ui.im.chat.MVHChatterBoxStart;
import com.mango.moshen.ui.im.model.IMCustomModel;
import com.mango.moshen.ui.webview.CommonWebViewActivity;
import com.mango.moshen.utils.PushMessageHandler;
import com.mango.core.UriProvider;
import com.mango.core.auth.AuthModel;
import com.mango.core.im.chatterbox.ChatterBoxHelper;
import com.mango.core.im.chatterbox.HideInputEvent;
import com.mango.core.im.custom.bean.CustomAttachment;
import com.mango.core.im.custom.bean.ImTipAttachment;
import com.mango.core.room.event.MessageSizeEvent;
import com.mango.core.statistic.StatisticManager;
import com.mango.core.statistic.protocol.StatisticsProtocol;
import com.mango.xchat_android_library.utils.SingleToastUtil;
import com.mango.xchat_android_library.utils.config.BasicConfig;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
@@ -103,6 +101,7 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
protected InputPanel inputPanel; protected InputPanel inputPanel;
protected MessageListPanelEx messageListPanel; protected MessageListPanelEx messageListPanel;
protected AitManager aitManager; protected AitManager aitManager;
private boolean inRoom;
/** /**
* 消息接收观察者 * 消息接收观察者
*/ */
@@ -190,27 +189,12 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
} }
} }
/**
* 发送提示信息
*
* @param msg
*/
public void sendTipMessage(String msg, int second) {
ImTipAttachment attachment = new ImTipAttachment(CustomAttachment.CUSTOM_MSG_IM_TIP, second);
attachment.setMsg(msg);
IMMessage message = MessageBuilder.createCustomMessage(sessionId, SessionTypeEnum.P2P, attachment);
sendMessage(message);
}
public boolean onBackPressed() { public boolean onBackPressed() {
if (inputPanel.collapse(true)) { if (inputPanel.collapse(true)) {
return true; return true;
} }
if (messageListPanel.onBackPressed()) { return messageListPanel.onBackPressed();
return true;
}
return false;
} }
public void refreshMessageList() { public void refreshMessageList() {
@@ -243,8 +227,6 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
initAitManager(); initAitManager();
inputPanel.switchRobotMode(NimUIKitImpl.getRobotInfoProvider().getRobotByAccount(sessionId) != null);
registerObservers(true); registerObservers(true);
if (customization != null) { if (customization != null) {
@@ -302,7 +284,7 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
*/ */
// 是否允许发送消息 // 是否允许发送消息
protected boolean isAllowSendMessage(final IMMessage message) { protected boolean isAllowSendMessage(final IMMessage message) {
return true; return isChat;
} }
/** /**
@@ -324,7 +306,9 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
*/ */
@Override @Override
public boolean sendMessage(IMMessage message) { public boolean sendMessage(IMMessage message) {
if (!isAllowSendMessage(message)) { if (!isAllowSendMessage(message)) {
SingleToastUtil.showToast("未到达私聊等级!");
return false; return false;
} }
@@ -346,8 +330,6 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
final IMMessage msg = message; final IMMessage msg = message;
appendPushConfig(message); appendPushConfig(message);
// send message to server and save to db
IMMessage finalMessage = message;
NIMClient.getService(MsgService.class).sendMessage(message, false).setCallback(new RequestCallback<Void>() { NIMClient.getService(MsgService.class).sendMessage(message, false).setCallback(new RequestCallback<Void>() {
@Override @Override
public void onSuccess(Void param) { public void onSuccess(Void param) {
@@ -542,10 +524,6 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
// 操作面板集合 // 操作面板集合
protected List<BaseAction> getActionList() { protected List<BaseAction> getActionList() {
List<BaseAction> actions = new ArrayList<>(); List<BaseAction> actions = new ArrayList<>();
// actions.add(new ImageAction());
// actions.add(new VideoAction());
// actions.add(new LocationAction());
if (customization != null && customization.actions != null) { if (customization != null && customization.actions != null) {
actions.addAll(customization.actions); actions.addAll(customization.actions);
} }
@@ -566,18 +544,6 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
messageListPanel.receiveReceipt(); messageListPanel.receiveReceipt();
} }
/**
* 重新加载 输入面板
*
* @param sessionCustomization
*/
public void reloadInputPanel(SessionCustomization sessionCustomization) {
this.customization = sessionCustomization;
Container container = new Container(getActivity(), sessionId, sessionType, this);
inputPanel.reload(container, customization);
inputPanel.reloadActions(sessionCustomization.actions);
}
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
public void onHideInput(HideInputEvent event) { public void onHideInput(HideInputEvent event) {
if (inputPanel != null) { if (inputPanel != null) {
@@ -592,51 +558,54 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
if (inputPanel != null) { if (inputPanel != null) {
if (event.getSize() > 0) { if (event.getSize() > 0) {
tvChatLimit.setVisibility(View.GONE); tvChatLimit.setVisibility(View.GONE);
isChat = true;
inputPanel.setLimitLevel(true, ""); inputPanel.setLimitLevel(true, "");
} else { } else {
IMCustomModel.get().getPrivateChatLimit(sessionId).subscribe(((privateChatLimitInfo, throwable) -> { IMCustomModel.get()
if (throwable != null) { .getPrivateChatLimit(sessionId)
throwable.printStackTrace(); .subscribe(((privateChatLimitInfo, throwable) -> {
} else { if (throwable != null) {
isChat = privateChatLimitInfo.isChat(); throwable.printStackTrace();
hintText = "暂未达到可发起私聊等级"; } else {
inputPanel.setLimitLevel(privateChatLimitInfo.isChat(), privateChatLimitInfo.getMessage()); isChat = privateChatLimitInfo.isChat();
hintText = "暂未达到可发起私聊等级";
inputPanel.setLimitLevel(privateChatLimitInfo.isChat(), privateChatLimitInfo.getMessage());
String experLevel = "财富等级≥" + privateChatLimitInfo.getWealthLevel(); String experLevel = "财富等级≥" + privateChatLimitInfo.getWealthLevel();
String charmLevel = "魅力等级≥" + privateChatLimitInfo.getCharmLevel(); String charmLevel = "魅力等级≥" + privateChatLimitInfo.getCharmLevel();
String privacyAgreementDescTip = getContext().getString(R.string.text_chat_limit, experLevel, charmLevel); String privacyAgreementDescTip = getContext().getString(R.string.text_chat_limit, experLevel, charmLevel);
SpannableString ss = new SpannableString(privacyAgreementDescTip); SpannableString ss = new SpannableString(privacyAgreementDescTip);
int experLevelIndex = privacyAgreementDescTip.indexOf(experLevel); int experLevelIndex = privacyAgreementDescTip.indexOf(experLevel);
int charmLevelIndex = privacyAgreementDescTip.indexOf(charmLevel); int charmLevelIndex = privacyAgreementDescTip.indexOf(charmLevel);
ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.appColor)), experLevelIndex, experLevelIndex + experLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.appColor)), experLevelIndex, experLevelIndex + experLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ss.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(getContext(), R.color.appColor)) { ss.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(getContext(), R.color.appColor)) {
@Override @Override
public void onClick(@NonNull View widget) { public void onClick(@NonNull View widget) {
if (widget instanceof TextView) if (widget instanceof TextView)
((TextView) widget).setHighlightColor(getResources().getColor(android.R.color.transparent)); ((TextView) widget).setHighlightColor(getResources().getColor(android.R.color.transparent));
CommonWebViewActivity.start(getContext(), UriProvider.getUserLevelUrl()); CommonWebViewActivity.start(getContext(), UriProvider.getUserLevelUrl());
}
}, experLevelIndex, experLevelIndex + experLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.appColor)), charmLevelIndex, charmLevelIndex + charmLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ss.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(getContext(), R.color.appColor)) {
@Override
public void onClick(@NonNull View widget) {
if (widget instanceof TextView)
((TextView) widget).setHighlightColor(getResources().getColor(android.R.color.transparent));
CommonWebViewActivity.start(getContext(), UriProvider.getUserLevelUrl());
}
}, charmLevelIndex, charmLevelIndex + experLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
tvChatLimit.setText(ss);
tvChatLimit.setHighlightColor(Color.TRANSPARENT);
tvChatLimit.setMovementMethod(new LinkMovementMethod());
tvChatLimit.setVisibility(isChat ? View.GONE : View.VISIBLE);
} }
}, experLevelIndex, experLevelIndex + experLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); }));
ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.appColor)), charmLevelIndex, charmLevelIndex + charmLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
ss.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(getContext(), R.color.appColor)) {
@Override
public void onClick(@NonNull View widget) {
if (widget instanceof TextView)
((TextView) widget).setHighlightColor(getResources().getColor(android.R.color.transparent));
CommonWebViewActivity.start(getContext(), UriProvider.getUserLevelUrl());
}
}, charmLevelIndex, charmLevelIndex + experLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
tvChatLimit.setText(ss);
tvChatLimit.setHighlightColor(Color.TRANSPARENT);
tvChatLimit.setMovementMethod(new LinkMovementMethod());
tvChatLimit.setVisibility(isChat ? View.GONE : View.VISIBLE);
}
}));
} }
} }
} }
@@ -672,12 +641,4 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
}); });
} }
public void setLimitLevel(int limitLevel) {
}
//
//
public void setCurrentLevel(int currentLevel) {
}
} }

View File

@@ -4,7 +4,8 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/bg_normal_1c1b22"> android:background="@color/bg_normal_1c1b22"
android:paddingTop="30dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<com.netease.nim.uikit.business.session.emoji.EmoticonPickerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/emoticon_picker_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center">
<TextView
android:id="@+id/nim_message_item_text_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="phone|email|web"
android:gravity="center_vertical|left"
android:includeFontPadding="false"
android:lineSpacingExtra="3dip"
android:maxWidth="222dp"
android:text="这是选择图片的玩意"
android:textColor="@color/text_title_white"
android:textSize="@dimen/dp_13" />
</LinearLayout>

View File

@@ -1,58 +1,24 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <com.effective.android.panel.view.PanelSwitchLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/messageActivityLayout" android:id="@+id/messageActivityLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/bg_normal_1c1b22" android:background="@color/bg_normal_1c1b22"
android:orientation="vertical"> android:orientation="vertical"
app:animationSpeed="standard">
<RelativeLayout <com.effective.android.panel.view.content.LinearContentContainer
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dip" android:layout_height="match_parent"
android:layout_weight="1"> android:orientation="vertical"
app:edit_view="@id/editTextMessage">
<FrameLayout
android:id="@+id/fl_game"
android:layout_width="299dp"
android:layout_height="163dp"
android:layout_centerHorizontal="true"
android:layout_marginBottom="-10dp"
android:background="@drawable/chat_popup_game_bg"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="25dp"
android:text="Ta爱玩的游戏"
android:textColor="#ff666666"
android:textSize="18sp" />
<ImageView
android:id="@+id/iv_close"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="right"
android:layout_marginRight="10dp"
android:scaleType="center"
android:src="@drawable/chat_popup_game_close" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="55dp" />
</FrameLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/message_activity_list_view_container" android:id="@+id/message_activity_list_view_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="0dp"
android:layout_below="@id/fl_game"
android:layout_weight="1"> android:layout_weight="1">
<com.netease.nim.uikit.business.session.helper.MsgBkImageView <com.netease.nim.uikit.business.session.helper.MsgBkImageView
@@ -72,7 +38,7 @@
</FrameLayout> </FrameLayout>
<androidx.recyclerview.widget.RecyclerView <com.mango.moshen.ui.im.AutoHidePanelRecyclerView
android:id="@+id/messageListView" android:id="@+id/messageListView"
style="@style/recycler_view" style="@style/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -120,18 +86,173 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_10" android:layout_marginTop="@dimen/dp_10"
android:text="哈哈哈哈哈"
android:paddingStart="@dimen/dp_10"
android:paddingEnd="@dimen/dp_10"
android:paddingTop="@dimen/dp_2"
android:paddingBottom="@dimen/dp_2"
android:background="@drawable/bg_chat_limit" android:background="@drawable/bg_chat_limit"
android:visibility="gone" android:paddingStart="@dimen/dp_10"
/> android:paddingTop="@dimen/dp_2"
android:paddingEnd="@dimen/dp_10"
android:paddingBottom="@dimen/dp_2"
android:text="哈哈哈哈哈"
android:visibility="gone" />
</RelativeLayout> </RelativeLayout>
</RelativeLayout> <LinearLayout
android:id="@+id/textMessageLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingTop="@dimen/bottom_component_margin_vertical"
android:paddingBottom="@dimen/bottom_component_margin_vertical">
<include layout="@layout/nim_message_activity_bottom_layout" /> <LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center_vertical"
android:orientation="horizontal">
</LinearLayout> <FrameLayout
android:id="@+id/switchLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/bottom_component_margin_horizontal"
android:layout_marginRight="@dimen/bottom_component_margin_horizontal">
<ImageView
android:id="@+id/buttonAudioMessage"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/nim_message_button_bottom_audio_selector"
android:contentDescription="@string/empty"
android:scaleType="center" />
<ImageView
android:id="@+id/buttonTextMessage"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/nim_message_button_bottom_text_selector"
android:contentDescription="@string/empty"
android:scaleType="center"
android:visibility="gone" />
</FrameLayout>
<Button
android:id="@+id/audioRecord"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:layout_marginEnd="@dimen/bottom_component_margin_horizontal"
android:layout_weight="1"
android:background="@drawable/bg_message_voice"
android:text="@string/record_audio"
android:textColor="@color/white"
android:textSize="16sp"
android:visibility="gone" />
<EditText
android:id="@+id/editTextMessage"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginEnd="@dimen/bottom_component_margin_horizontal"
android:layout_weight="1"
android:autoLink="web|email|phone"
android:background="@drawable/bg_message_input"
android:hint="@string/message_hint"
android:imeOptions="actionSend"
android:inputType="text"
android:maxLength="120"
android:maxLines="4"
android:paddingStart="@dimen/dp_10"
android:paddingEnd="10dp"
android:textColor="@color/color_C6C6E9"
android:textColorHint="@color/text_hint_555574"
android:textCursorDrawable="@null"
android:textSize="13sp" />
<ImageView
android:id="@+id/emoji_button"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginEnd="@dimen/bottom_component_margin_horizontal"
android:background="@drawable/nim_message_button_bottom_emoji_selector"
android:contentDescription="@string/empty"
android:scaleType="center" />
<TextView
android:id="@+id/buttonSendMessage"
android:layout_width="56dp"
android:layout_height="30dp"
android:layout_marginEnd="6dp"
android:background="@drawable/common_btn_bg"
android:contentDescription="@string/empty"
android:gravity="center"
android:text="@string/send"
android:textColor="@color/white"
android:textSize="@dimen/sp_12"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_image"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/message_input_ic_image" />
<ImageView
android:id="@+id/iv_camera"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="88dp"
android:src="@drawable/message_input_ic_camera" />
<ImageView
android:id="@+id/iv_gift"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="88dp"
android:src="@drawable/message_input_ic_gift" />
</LinearLayout>
</LinearLayout>
</com.effective.android.panel.view.content.LinearContentContainer>
<!-- 面板区域仅能包含PanelView-->
<com.effective.android.panel.view.panel.PanelContainer
android:id="@+id/panel_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 每一项面板 -->
<!-- panel_layout 用于指定面板该 ID 对应的布局 ,必须项-->
<!-- panel_trigger 用于用户点击该 ID 对应的 View 时切换到该面板 -->
<!-- panel_toggle 用于当该面板显示时 ,用户再次点击 panel_trigger 对应的 View 时是否回切输入法-->
<com.effective.android.panel.view.panel.PanelView
android:id="@+id/panel_emotion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:panel_layout="@layout/nim_message_emoji_layout"
app:panel_trigger="@id/emoji_button" />
<com.effective.android.panel.view.panel.PanelView
android:id="@+id/panel_photo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:panel_layout="@layout/nim_message_photo_layout"
app:panel_trigger="@id/iv_image" />
</com.effective.android.panel.view.panel.PanelContainer>
</com.effective.android.panel.view.PanelSwitchLayout>

View File

@@ -13,6 +13,15 @@ import android.widget.TextView;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.mango.core.im.friend.IMFriendModel;
import com.mango.core.manager.IMNetEaseManager;
import com.mango.core.manager.RoomEvent;
import com.mango.core.utils.SystemUidUtil;
import com.mango.moshen.R;
import com.mango.moshen.room_chat.event.ClickRootViewEvent;
import com.mango.moshen.ui.im.avtivity.NewBaseMessageActivity;
import com.mango.moshen.ui.im.fragment.MessageFragment;
import com.mango.xchat_android_library.utils.SingleToastUtil;
import com.netease.nim.uikit.api.NimUIKit; import com.netease.nim.uikit.api.NimUIKit;
import com.netease.nim.uikit.api.model.contact.ContactChangedObserver; import com.netease.nim.uikit.api.model.contact.ContactChangedObserver;
import com.netease.nim.uikit.api.model.main.OnlineStateChangeObserver; import com.netease.nim.uikit.api.model.main.OnlineStateChangeObserver;
@@ -25,20 +34,6 @@ import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.msg.MsgServiceObserve; import com.netease.nimlib.sdk.msg.MsgServiceObserve;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.CustomNotification; import com.netease.nimlib.sdk.msg.model.CustomNotification;
import com.mango.moshen.R;
import com.mango.moshen.ui.im.avtivity.NewBaseMessageActivity;
import com.mango.moshen.ui.im.fragment.MessageFragment;
import com.mango.moshen.room_chat.event.ClickRootViewEvent;
import com.mango.core.im.friend.IMFriendModel;
import com.mango.core.initial.InitialModel;
import com.mango.core.initial.bean.InitInfo;
import com.mango.core.level.UserLevelVo;
import com.mango.core.manager.IMNetEaseManager;
import com.mango.core.manager.RoomEvent;
import com.mango.core.user.UserModel;
import com.mango.core.user.bean.UserInfo;
import com.mango.core.utils.SystemUidUtil;
import com.mango.xchat_android_library.utils.SingleToastUtil;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
@@ -259,14 +254,11 @@ public class NimRoomP2PMessageActivity extends NewBaseMessageActivity {
int id = json.getIntValue("id"); int id = json.getIntValue("id");
if (id == 1) { if (id == 1) {
// 正在输入 // 正在输入
// Toast.makeText(NimRoomP2PMessageActivity.this, "对方正在输入...", Toast.LENGTH_LONG).show(); SingleToastUtil.showToast("对方正在输入...");
SingleToastUtil.showToastShort("对方正在输入...");
} else {
// Toast.makeText(NimP2PMessageActivity.this, "command: " + content, Toast.LENGTH_SHORT).show();
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
} }
} }
@@ -281,29 +273,12 @@ public class NimRoomP2PMessageActivity extends NewBaseMessageActivity {
MessageFragment fragment = new MessageFragment(); MessageFragment fragment = new MessageFragment();
fragment.setArguments(arguments); fragment.setArguments(arguments);
fragment.setContainerId(R.id.message_fragment_container); fragment.setContainerId(R.id.message_fragment_container);
// 等级限制:官方小秘书 和 系统消息,不设置等级限制
if (!SystemUidUtil.isSystemUid(sessionId)) {
UserInfo userInfo = UserModel.get().getCacheLoginUserInfo();
if (userInfo != null) {
UserLevelVo userLevelVo = userInfo.getUserLevelVo();
if (userLevelVo != null) {
fragment.setCurrentLevel(userLevelVo.experLevelSeq);
}
}
InitInfo initInfo = InitialModel.get().getCacheInitInfo();
if (initInfo != null) {
fragment.setLimitLevel(initInfo.getPrivateChatLevelNo());
fragment.setLimitLevel(initInfo.getPrivateChatRegisterDay());
}
}
return fragment; return fragment;
} }
@Override @Override
protected void initToolBar() { protected void initToolBar() {
//ToolBarOptions options = new NimToolBarOptions();
// setToolBar(R.id.toolbar, options);
} }
@Override @Override

View File

@@ -95,6 +95,9 @@ dependencies {
api 'com.github.getActivity:ToastUtils:10.3' api 'com.github.getActivity:ToastUtils:10.3'
api 'com.github.DSAppTeam:PanelSwitchHelper:v1.5.2'
} }
repositories { repositories {
mavenCentral() mavenCentral()

View File

@@ -69,8 +69,6 @@ dependencies {
annotationProcessor "com.github.bumptech.glide:compiler:${glideVersion}" annotationProcessor "com.github.bumptech.glide:compiler:${glideVersion}"
implementation project(':library') implementation project(':library')
} }
repositories { repositories {
mavenCentral() mavenCentral()

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F4F4FA" /> <solid android:color="#F2F2F7" />
<corners android:radius="15dp" /> <corners android:radius="25dp" />
</shape> </shape>

View File

@@ -6,13 +6,6 @@
android:orientation="vertical" android:orientation="vertical"
android:visibility="visible"> android:visibility="visible">
<View
android:id="@+id/top_divider_line"
android:layout_height="1px"
android:layout_width="match_parent"
android:background="#353548"
android:visibility="gone"/>
<androidx.viewpager.widget.ViewPager <androidx.viewpager.widget.ViewPager
android:id="@+id/scrPlugin" android:id="@+id/scrPlugin"
android:layout_width="fill_parent" android:layout_width="fill_parent"
@@ -30,8 +23,6 @@
android:gravity="center" android:gravity="center"
android:orientation="horizontal"/> android:orientation="horizontal"/>
<View style="@style/horizontal_light_thin_divider"/>
<LinearLayout <LinearLayout
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -50,6 +41,7 @@
android:layout_height="44dp" android:layout_height="44dp"
android:orientation="horizontal"> android:orientation="horizontal">
</LinearLayout> </LinearLayout>
</HorizontalScrollView> </HorizontalScrollView>
</LinearLayout> </LinearLayout>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<resources> <resources>
<color name="nim_app_color">#FFBC52</color> <color name="nim_app_color">#5BC8F8</color>
<color name="nim_app_color_press">#FFBC52</color> <color name="nim_app_color_press">#5BC8F8</color>
<color name="transparent">#00000000</color> <color name="transparent">#00000000</color>
<color name="white">#FFFFFF</color> <color name="white">#FFFFFF</color>

View File

@@ -1,61 +0,0 @@
package com.netease.nim.uikit;
import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
/**
* Created by huangmeng1 on 2018/3/9.
*/
public class AndroidBug5497Workaround {
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
public static void assistActivity (Activity activity) {
new AndroidBug5497Workaround(activity);
}
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497Workaround(final Activity activity) {
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
possiblyResizeChildOfContent(activity);
}
});
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent(Activity activity) {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
int usableHeightSansKeyboard = activity.getWindowManager().getDefaultDisplay().getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
if (heightDifference > (usableHeightSansKeyboard/4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom - r.top);// 全屏模式下: return r.bottom
}
}

View File

@@ -307,16 +307,6 @@ public class NimUIKit {
NimUIKitImpl.startP2PSession(context, account); NimUIKitImpl.startP2PSession(context, account);
} }
/**
* 同 {@link NimUIKitImpl#startP2PSession(Context, String)},同时聊天界面打开后列表跳转至anchor位置
*
* @param context 上下文
* @param account 目标账号
* @param anchor 跳转到指定消息的位置不需要跳转填null
*/
public static void startP2PSession(Context context, String account, IMMessage anchor) {
NimUIKitImpl.startP2PSession(context, account, anchor);
}
/** /**
* 打开群聊界面,若开发者未设置 {@link NimUIKitImpl#setCommonTeamSessionCustomization(SessionCustomization)}, * 打开群聊界面,若开发者未设置 {@link NimUIKitImpl#setCommonTeamSessionCustomization(SessionCustomization)},

View File

@@ -1,82 +0,0 @@
package com.netease.nim.uikit.api.wrapper;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import com.netease.nim.uikit.R;
import com.netease.nim.uikit.api.NimUIKit;
import com.netease.nim.uikit.business.team.helper.TeamHelper;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.team.model.Team;
import com.netease.nimlib.sdk.uinfo.UserInfoProvider;
import com.netease.nimlib.sdk.uinfo.model.UserInfo;
/**
* 初始化sdk 需要的用户信息提供者,现主要用于内置通知提醒获取昵称和头像
* <p>
* 注意不要与 IUserInfoProvider 混淆,后者是 UIKit 与 demo 之间的数据共享接口
* <p>
*/
public class NimUserInfoProvider implements UserInfoProvider {
private Context context;
public NimUserInfoProvider(Context context) {
this.context = context;
}
@Override
public UserInfo getUserInfo(String account) {
return NimUIKit.getUserInfoProvider().getUserInfo(account);
}
@Override
public Bitmap getAvatarForMessageNotifier(SessionTypeEnum sessionType, String sessionId) {
/*
* 注意:这里最好从缓存里拿,如果加载时间过长会导致通知栏延迟弹出!该函数在后台线程执行!
*/
Bitmap bm = null;
int defResId = R.drawable.nim_avatar_default;
if (SessionTypeEnum.P2P == sessionType) {
UserInfo user = getUserInfo(sessionId);
bm = (user != null) ? NimUIKit.getImageLoaderKit().getNotificationBitmapFromCache(user.getAvatar()) : null;
} else if (SessionTypeEnum.Team == sessionType) {
Team team = NimUIKit.getTeamProvider().getTeamById(sessionId);
bm = (team != null) ? NimUIKit.getImageLoaderKit().getNotificationBitmapFromCache(team.getIcon()) : null;
defResId = R.drawable.nim_avatar_group;
}
if (bm == null) {
Drawable drawable = context.getResources().getDrawable(defResId);
if (drawable instanceof BitmapDrawable) {
bm = ((BitmapDrawable) drawable).getBitmap();
}
}
return bm;
}
@Override
public String getDisplayNameForMessageNotifier(String account, String sessionId, SessionTypeEnum sessionType) {
String nick = null;
if (sessionType == SessionTypeEnum.P2P) {
nick = NimUIKit.getContactProvider().getAlias(account);
} else if (sessionType == SessionTypeEnum.Team) {
nick = NimUIKit.getContactProvider().getAlias(account);
if (TextUtils.isEmpty(nick)) {
nick = TeamHelper.getTeamNick(sessionId, account);
}
}
if (TextUtils.isEmpty(nick)) {
return null; // 返回null交给sdk处理。如果对方有设置nicksdk会显示nick
}
return nick;
}
}

View File

@@ -0,0 +1,44 @@
package com.netease.nim.uikit.business.session.actions;
import com.netease.nim.uikit.R;
import com.netease.nim.uikit.business.session.constant.RequestCode;
import com.netease.nim.uikit.business.session.event.ActiveEvent;
import com.netease.nim.uikit.common.media.picker.PickImageHelper;
import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder;
import com.netease.nimlib.sdk.msg.MessageBuilder;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
/**
* Created by hzxuwen on 2015/6/12.
*/
public class CameraAction extends PickImageAction {
public CameraAction() {
super(R.drawable.chat_icon_photo, R.string.input_panel_photo, true);
}
@Override
public void onClick() {
PickImageHelper.pickCamera(getActivity(), makeRequestCode(RequestCode.PICK_IMAGE), buildOption());
}
@Override
protected void onPicked(File file) {
IMMessage message;
if (getContainer() != null && getContainer().sessionType == SessionTypeEnum.ChatRoom) {
message = ChatRoomMessageBuilder.createChatRoomImageMessage(getAccount(), file, file.getName());
} else {
message = MessageBuilder.createImageMessage(getAccount(), getSessionType(), file, file.getName());
}
sendMessage(message);
EventBus.getDefault().post(new ActiveEvent());
}
}

View File

@@ -0,0 +1,43 @@
package com.netease.nim.uikit.business.session.actions;
import com.netease.nim.uikit.R;
import com.netease.nim.uikit.business.session.constant.RequestCode;
import com.netease.nim.uikit.business.session.event.ActiveEvent;
import com.netease.nim.uikit.common.media.picker.PickImageHelper;
import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder;
import com.netease.nimlib.sdk.msg.MessageBuilder;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
/**
* Created by hzxuwen on 2015/6/12.
*/
public class PhotoAction extends PickImageAction {
public PhotoAction() {
super(R.drawable.chat_icon_photo, R.string.input_panel_photo, true);
}
@Override
public void onClick() {
PickImageHelper.pickPhoto(getActivity(), makeRequestCode(RequestCode.PICK_IMAGE), buildOption());
}
@Override
protected void onPicked(File file) {
IMMessage message;
if (getContainer() != null && getContainer().sessionType == SessionTypeEnum.ChatRoom) {
message = ChatRoomMessageBuilder.createChatRoomImageMessage(getAccount(), file, file.getName());
} else {
message = MessageBuilder.createImageMessage(getAccount(), getSessionType(), file, file.getName());
}
sendMessage(message);
EventBus.getDefault().post(new ActiveEvent());
}
}

View File

@@ -25,26 +25,23 @@ import java.io.File;
*/ */
public abstract class PickImageAction extends BaseAction { public abstract class PickImageAction extends BaseAction {
private static final int PICK_IMAGE_COUNT = 9;
private static final int PORTRAIT_IMAGE_WIDTH = 720;
public static final String MIME_JPEG = "image/jpeg"; public static final String MIME_JPEG = "image/jpeg";
public static final String JPG = ".jpg"; public static final String JPG = ".jpg";
private static final int PICK_IMAGE_COUNT = 9;
private static final int PORTRAIT_IMAGE_WIDTH = 720;
private boolean multiSelect; private boolean multiSelect;
private boolean crop = false; private boolean crop = false;
protected abstract void onPicked(File file);
protected PickImageAction(int iconResId, int titleId, boolean multiSelect) { protected PickImageAction(int iconResId, int titleId, boolean multiSelect) {
super(iconResId, titleId); super(iconResId, titleId);
this.multiSelect = multiSelect; this.multiSelect = multiSelect;
} }
protected abstract void onPicked(File file);
@Override @Override
public void onClick() { public void onClick() {
int requestCode = makeRequestCode(RequestCode.PICK_IMAGE); PickImageHelper.pickImage(getActivity(), makeRequestCode(RequestCode.PICK_IMAGE), buildOption());
showSelector(getTitleId(), requestCode, multiSelect, tempFile());
} }
private String tempFile() { private String tempFile() {
@@ -52,20 +49,16 @@ public abstract class PickImageAction extends BaseAction {
return StorageUtil.getWritePath(filename, StorageType.TYPE_TEMP); return StorageUtil.getWritePath(filename, StorageType.TYPE_TEMP);
} }
/** public PickImageHelper.PickImageOption buildOption() {
* 打开图片选择器
*/
private void showSelector(int titleId, final int requestCode, final boolean multiSelect, final String outPath) {
PickImageHelper.PickImageOption option = new PickImageHelper.PickImageOption(); PickImageHelper.PickImageOption option = new PickImageHelper.PickImageOption();
option.titleResId = titleId; option.titleResId = getTitleId();
option.multiSelect = multiSelect; option.multiSelect = multiSelect;
option.multiSelectMaxCount = PICK_IMAGE_COUNT; option.multiSelectMaxCount = PICK_IMAGE_COUNT;
option.crop = crop; option.crop = crop;
option.cropOutputImageWidth = PORTRAIT_IMAGE_WIDTH; option.cropOutputImageWidth = PORTRAIT_IMAGE_WIDTH;
option.cropOutputImageHeight = PORTRAIT_IMAGE_WIDTH; option.cropOutputImageHeight = PORTRAIT_IMAGE_WIDTH;
option.outputPath = outPath; option.outputPath = tempFile();
return option;
PickImageHelper.pickImage(getActivity(), requestCode, option);
} }
@Override @Override

View File

@@ -1,11 +1,8 @@
package com.netease.nim.uikit.business.session.emoji; package com.netease.nim.uikit.business.session.emoji;
import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.os.Build;
import android.os.Handler; import android.os.Handler;
import androidx.viewpager.widget.ViewPager;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -15,6 +12,8 @@ import android.widget.HorizontalScrollView;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import androidx.viewpager.widget.ViewPager;
import com.netease.nim.uikit.R; import com.netease.nim.uikit.R;
import com.netease.nim.uikit.common.ui.imageview.CheckedImageButton; import com.netease.nim.uikit.common.ui.imageview.CheckedImageButton;
import com.netease.nim.uikit.common.util.log.LogUtil; import com.netease.nim.uikit.common.util.log.LogUtil;
@@ -47,9 +46,14 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
private HorizontalScrollView scrollView; private HorizontalScrollView scrollView;
private LinearLayout tabView; private LinearLayout tabView;
// 添加各个tab按钮
OnClickListener tabCheckListener = new OnClickListener() {
@Override
public void onClick(View v) {
onEmoticonBtnChecked(v.getId());
}
};
private int categoryIndex; private int categoryIndex;
private Handler uiHandler; private Handler uiHandler;
public EmoticonPickerView(Context context) { public EmoticonPickerView(Context context) {
@@ -64,17 +68,14 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
init(context); init(context);
} }
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public EmoticonPickerView(Context context, AttributeSet attrs, int defStyle) { public EmoticonPickerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
init(context); init(context);
} }
private void init(Context context) { private void init(Context context) {
this.context = context; this.context = context;
this.uiHandler = new Handler(context.getMainLooper()); this.uiHandler = new Handler(context.getMainLooper());
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.nim_emoji_layout, this); inflater.inflate(R.layout.nim_emoji_layout, this);
} }
@@ -91,41 +92,26 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
} }
public void show(IEmoticonSelectedListener listener) { public void show(IEmoticonSelectedListener listener) {
setListener(listener); this.listener = listener;
if (loaded) if (loaded)
return; return;
loadStickers(); loadStickers();
loaded = true; loaded = true;
if (!withSticker) {
show(); showEmojiView();
}
public void setListener(IEmoticonSelectedListener listener) {
if (listener != null) {
this.listener = listener;
} else { } else {
LogUtil.i("sticker", "listener is null"); onEmoticonBtnChecked(0);
setSelectedVisible(0);
} }
} }
protected void setupEmojView() { protected void setupEmojView() {
currentEmojiPage = (ViewPager) findViewById(R.id.scrPlugin); currentEmojiPage = findViewById(R.id.scrPlugin);
pageNumberLayout = (LinearLayout) findViewById(R.id.layout_scr_bottom); pageNumberLayout = findViewById(R.id.layout_scr_bottom);
tabView = (LinearLayout) findViewById(R.id.emoj_tab_view); tabView = findViewById(R.id.emoj_tab_view);
scrollView = (HorizontalScrollView) findViewById(R.id.emoj_tab_view_container); scrollView = findViewById(R.id.emoj_tab_view_container);
findViewById(R.id.top_divider_line).setVisibility(View.VISIBLE);
} }
// 添加各个tab按钮
OnClickListener tabCheckListener = new OnClickListener() {
@Override
public void onClick(View v) {
onEmoticonBtnChecked(v.getId());
}
};
private void loadStickers() { private void loadStickers() {
if (!withSticker) { if (!withSticker) {
scrollView.setVisibility(View.GONE); scrollView.setVisibility(View.GONE);
@@ -151,7 +137,6 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
} }
} }
private CheckedImageButton addEmoticonTabBtn(int index, OnClickListener listener) { private CheckedImageButton addEmoticonTabBtn(int index, OnClickListener listener) {
CheckedImageButton emotBtn = new CheckedImageButton(context); CheckedImageButton emotBtn = new CheckedImageButton(context);
emotBtn.setNormalBkResId(R.drawable.nim_sticker_button_background_normal_layer_list); emotBtn.setNormalBkResId(R.drawable.nim_sticker_button_background_normal_layer_list);
@@ -232,19 +217,6 @@ public class EmoticonPickerView extends LinearLayout implements IEmoticonCategor
gifView.showEmojis(); gifView.showEmojis();
} }
private void show() {
if (listener == null) {
LogUtil.i("sticker", "show picker view when listener is null");
}
if (!withSticker) {
showEmojiView();
} else {
onEmoticonBtnChecked(0);
setSelectedVisible(0);
}
}
private void setSelectedVisible(final int index) { private void setSelectedVisible(final int index) {
final Runnable runnable = new Runnable() { final Runnable runnable = new Runnable() {
@Override @Override

View File

@@ -18,6 +18,60 @@ import org.greenrobot.eventbus.EventBus;
*/ */
public class PickImageHelper { public class PickImageHelper {
/**
* 打开图片选择器
*/
public static void pickImage(final Context context, final int requestCode, final PickImageOption option) {
if (context == null) {
return;
}
CustomAlertDialog dialog = new CustomAlertDialog(context);
dialog.setTitle(option.titleResId);
dialog.addItem(context.getString(R.string.input_panel_take), () -> pickCamera(context, requestCode, option));
dialog.addItem(context.getString(R.string.choose_from_photo_album), () -> pickPhoto(context, requestCode, option));
dialog.show();
}
/**
* 打开图片选择器
*/
public static void pickPhoto(final Context context, final int requestCode, final PickImageOption option) {
NimImageActionEvent event = new NimImageActionEvent();
event.setSuccess(o -> {
int from = PickImageActivity.FROM_LOCAL;
if (!option.crop) {
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, option.multiSelect,
option.multiSelectMaxCount, true, false, 0, 0);
} else {
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, false, 1,
false, true, option.cropOutputImageWidth, option.cropOutputImageHeight);
}
});
EventBus.getDefault().post(event);
}
/**
* 打开相机发送图片
*/
public static void pickCamera(final Context context, final int requestCode, final PickImageOption option) {
NimImageActionEvent event = new NimImageActionEvent();
event.setSuccess(o -> {
int from = PickImageActivity.FROM_CAMERA;
if (!option.crop) {
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, option.multiSelect, 1,
true, false, 0, 0);
} else {
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, false, 1,
false, true, option.cropOutputImageWidth, option.cropOutputImageHeight);
}
});
EventBus.getDefault().post(event);
}
public static class PickImageOption { public static class PickImageOption {
/** /**
* 图片选择器标题 * 图片选择器标题
@@ -55,53 +109,5 @@ public class PickImageHelper {
public String outputPath = StorageUtil.getWritePath(StringUtil.get32UUID() + ".jpg", StorageType.TYPE_TEMP); public String outputPath = StorageUtil.getWritePath(StringUtil.get32UUID() + ".jpg", StorageType.TYPE_TEMP);
} }
/**
* 打开图片选择器
*/
public static void pickImage(final Context context, final int requestCode, final PickImageOption option) {
if (context == null) {
return;
}
CustomAlertDialog dialog = new CustomAlertDialog(context);
dialog.setTitle(option.titleResId);
dialog.addItem(context.getString(R.string.input_panel_take), new CustomAlertDialog.onSeparateItemClickListener() {
@Override
public void onClick() {
NimImageActionEvent event = new NimImageActionEvent();
event.setSuccess(o -> {
int from = PickImageActivity.FROM_CAMERA;
if (!option.crop) {
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, option.multiSelect, 1,
true, false, 0, 0);
} else {
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, false, 1,
false, true, option.cropOutputImageWidth, option.cropOutputImageHeight);
}
});
EventBus.getDefault().post(event);
}
});
dialog.addItem(context.getString(R.string.choose_from_photo_album), new CustomAlertDialog.onSeparateItemClickListener() {
@Override
public void onClick() {
NimImageActionEvent event = new NimImageActionEvent();
event.setSuccess(o -> {
int from = PickImageActivity.FROM_LOCAL;
if (!option.crop) {
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, option.multiSelect,
option.multiSelectMaxCount, true, false, 0, 0);
} else {
PickImageActivity.start((Activity) context, requestCode, from, option.outputPath, false, 1,
false, true, option.cropOutputImageWidth, option.cropOutputImageHeight);
}
});
EventBus.getDefault().post(event);
}
});
dialog.show();
}
} }

View File

@@ -1,36 +0,0 @@
package com.netease.nim.uikit.impl.preference;
import android.content.Context;
import android.content.SharedPreferences;
import com.netease.nim.uikit.api.NimUIKit;
/**
* Created by hzxuwen on 2015/10/21.
*/
public class UserPreferences {
private final static String KEY_EARPHONE_MODE = "KEY_EARPHONE_MODE";
public static void setEarPhoneModeEnable(boolean on) {
saveBoolean(KEY_EARPHONE_MODE, on);
}
public static boolean isEarPhoneModeEnable() {
return getBoolean(KEY_EARPHONE_MODE, true);
}
private static boolean getBoolean(String key, boolean value) {
return getSharedPreferences().getBoolean(key, value);
}
private static void saveBoolean(String key, boolean value) {
SharedPreferences.Editor editor = getSharedPreferences().edit();
editor.putBoolean(key, value);
editor.apply();
}
private static SharedPreferences getSharedPreferences() {
return NimUIKit.getContext().getSharedPreferences("UIKit." + NimUIKit.getAccount(), Context.MODE_PRIVATE);
}
}

View File

@@ -1,204 +0,0 @@
package com.netease.nim.uikit.support.permission;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.fragment.app.Fragment;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class BaseMPermission {
private static final String TAG = "MPermission";
public enum MPermissionResultEnum {
GRANTED, DENIED, DENIED_NEVER_ASK_AGAIN
}
static boolean isOverMarshmallow() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
static Activity getActivity(Object object) {
if (object instanceof Fragment) {
return ((Fragment) object).getActivity();
} else if (object instanceof Activity) {
return (Activity) object;
}
return null;
}
/**
* 获取权限请求结果
*/
public static List<MPermissionResultEnum> getPermissionResult(Activity activity, String[] permissions) {
return findPermissionResult(activity, permissions);
}
public static List<MPermissionResultEnum> getPermissionResult(Fragment fragment, String[] permissions) {
return findPermissionResult(fragment.getActivity(), permissions);
}
@TargetApi(value = Build.VERSION_CODES.M)
private static List<MPermissionResultEnum> findPermissionResult(Activity activity, String... permissions) {
boolean overM = isOverMarshmallow();
List<MPermissionResultEnum> result = new ArrayList<>();
for (String p : permissions) {
if (overM) {
if (activity.checkSelfPermission(p) == PackageManager.PERMISSION_GRANTED) {
result.add(MPermissionResultEnum.GRANTED);
} else {
if (!activity.shouldShowRequestPermissionRationale(p)) {
result.add(MPermissionResultEnum.DENIED_NEVER_ASK_AGAIN);
} else {
result.add(MPermissionResultEnum.DENIED);
}
}
} else {
result.add(MPermissionResultEnum.GRANTED);
}
}
return result;
}
/**
* 获取所有被未被授权的权限
*/
public static List<String> getDeniedPermissions(Activity activity, String[] permissions) {
return findDeniedPermissions(activity, permissions);
}
public static List<String> getDeniedPermissions(Fragment fragment, String[] permissions) {
return findDeniedPermissions(fragment.getActivity(), permissions);
}
@TargetApi(value = Build.VERSION_CODES.M)
static List<String> findDeniedPermissions(Activity activity, String... permissions) {
if (!isOverMarshmallow()) {
return null;
}
List<String> denyPermissions = new ArrayList<>();
for (String value : permissions) {
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED) {
denyPermissions.add(value);
}
}
return denyPermissions;
}
/**
* 获取被拒绝且勾选不再询问的权限
* 请在请求权限结果回调中使用,因为从未请求过的权限也会被认为是该结果集
*/
public static List<String> getNeverAskAgainPermissions(Activity activity, String[] permissions) {
return findNeverAskAgainPermissions(activity, permissions);
}
public static List<String> getNeverAskAgainPermissions(Fragment fragment, String[] permissions) {
return findNeverAskAgainPermissions(fragment.getActivity(), permissions);
}
@TargetApi(value = Build.VERSION_CODES.M)
private static List<String> findNeverAskAgainPermissions(Activity activity, String... permissions) {
if (!isOverMarshmallow()) {
return null;
}
List<String> neverAskAgainPermission = new ArrayList<>();
for (String value : permissions) {
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED &&
!activity.shouldShowRequestPermissionRationale(value)) {
// 拒绝&不要需要解释了(用户勾选了不再询问)
// 坑爹第一次不做任何设置返回值也是false。建议在权限授权结果里判断
neverAskAgainPermission.add(value);
}
}
return neverAskAgainPermission;
}
@TargetApi(value = Build.VERSION_CODES.M)
static boolean hasNeverAskAgainPermission(Activity activity, List<String> permission) {
if (!isOverMarshmallow()) {
return false;
}
for (String value : permission) {
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED &&
!activity.shouldShowRequestPermissionRationale(value)) {
return true;
}
}
return false;
}
/**
* 获取被拒绝但没有勾选不再询问的权限(可以继续申请,会继续弹框)
*/
public static List<String> getDeniedPermissionsWithoutNeverAskAgain(Activity activity, String[] permissions) {
return findDeniedPermissionWithoutNeverAskAgain(activity, permissions);
}
public static List<String> getDeniedPermissionsWithoutNeverAskAgain(Fragment fragment, String[] permissions) {
return findDeniedPermissionWithoutNeverAskAgain(fragment.getActivity(), permissions);
}
@TargetApi(value = Build.VERSION_CODES.M)
private static List<String> findDeniedPermissionWithoutNeverAskAgain(Activity activity, String... permission) {
if (!isOverMarshmallow()) {
return null;
}
List<String> denyPermissions = new ArrayList<>();
for (String value : permission) {
if (activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED &&
activity.shouldShowRequestPermissionRationale(value)) {
denyPermissions.add(value); // 上次申请被用户拒绝了
}
}
return denyPermissions;
}
/**
* Log专用
*/
public static void printMPermissionResult(boolean preRequest, Activity activity, String[] permissions) {
Log.i(TAG, "----- MPermission result " + (preRequest ? "before" : "after") + " request");
List<BaseMPermission.MPermissionResultEnum> result = getPermissionResult(activity, permissions);
int i = 0;
for (BaseMPermission.MPermissionResultEnum p : result) {
Log.i(TAG, "* MPermission=" + permissions[i++] + ", result=" + p);
}
}
static String toString(List<String> permission) {
if (permission == null || permission.isEmpty()) {
return "";
}
return toString(permission.toArray(new String[permission.size()]));
}
private static String toString(String[] permission) {
if (permission == null || permission.length <= 0) {
return "";
}
StringBuilder sb = new StringBuilder();
for (String p : permission) {
sb.append(p.replaceFirst("android.permission.", ""));
sb.append(",");
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
}

View File

@@ -1,170 +0,0 @@
package com.netease.nim.uikit.support.permission;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.netease.nim.uikit.support.permission.annotation.OnMPermissionDenied;
import com.netease.nim.uikit.support.permission.annotation.OnMPermissionGranted;
import com.netease.nim.uikit.support.permission.annotation.OnMPermissionNeverAskAgain;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class MPermission extends BaseMPermission {
private int requestCode;
private String[] permissions;
private Object object; // activity or fragment
private MPermission(Object object) {
this.object = object;
}
public static MPermission with(Activity activity) {
return new MPermission(activity);
}
public static MPermission with(Fragment fragment) {
return new MPermission(fragment);
}
public MPermission setRequestCode(int requestCode) {
this.requestCode = requestCode;
return this;
}
public MPermission permissions(String... permissions) {
this.permissions = permissions;
return this;
}
/**
* ********************* request *********************
*/
@TargetApi(value = Build.VERSION_CODES.M)
public void request() {
doRequestPermissions(object, requestCode, permissions);
}
@TargetApi(value = Build.VERSION_CODES.M)
private static void doRequestPermissions(Object object, int requestCode, String[] permissions) {
if (!isOverMarshmallow()) {
doExecuteSuccess(object, requestCode);
return;
}
List<String> deniedPermissions = findDeniedPermissions(getActivity(object), permissions);
if (deniedPermissions != null && deniedPermissions.size() > 0) {
if (object instanceof Activity) {
((Activity) object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
} else if (object instanceof Fragment) {
((Fragment) object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
} else {
throw new IllegalArgumentException(object.getClass().getName() + " is not supported");
}
} else {
doExecuteSuccess(object, requestCode);
}
}
/**
* ********************* on result *********************
*/
public static void onRequestPermissionsResult(Activity activity, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
dispatchResult(activity, requestCode, permissions, grantResults);
}
public static void onRequestPermissionsResult(Fragment fragment, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
dispatchResult(fragment, requestCode, permissions, grantResults);
}
private static void dispatchResult(Object obj, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
List<String> deniedPermissions = new ArrayList<>();
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
deniedPermissions.add(permissions[i]);
}
}
if (deniedPermissions.size() > 0) {
if (hasNeverAskAgainPermission(getActivity(obj), deniedPermissions)) {
doExecuteFailAsNeverAskAgain(obj, requestCode);
} else {
doExecuteFail(obj, requestCode);
}
} else {
doExecuteSuccess(obj, requestCode);
}
}
/**
* ********************* reflect execute result *********************
*/
private static void doExecuteSuccess(Object activity, int requestCode) {
executeMethod(activity, findMethodWithRequestCode(activity.getClass(), OnMPermissionGranted.class, requestCode));
}
private static void doExecuteFail(Object activity, int requestCode) {
executeMethod(activity, findMethodWithRequestCode(activity.getClass(), OnMPermissionDenied.class, requestCode));
}
private static void doExecuteFailAsNeverAskAgain(Object activity, int requestCode) {
executeMethod(activity, findMethodWithRequestCode(activity.getClass(), OnMPermissionNeverAskAgain.class, requestCode));
}
private static <A extends Annotation> Method findMethodWithRequestCode(Class clazz, Class<A> annotation, int
requestCode) {
for (Method method : clazz.getDeclaredMethods()) {
if (method.getAnnotation(annotation) != null &&
isEqualRequestCodeFromAnnotation(method, annotation, requestCode)) {
return method;
}
}
return null;
}
private static boolean isEqualRequestCodeFromAnnotation(Method m, Class clazz, int requestCode) {
if (clazz.equals(OnMPermissionDenied.class)) {
return requestCode == m.getAnnotation(OnMPermissionDenied.class).value();
} else if (clazz.equals(OnMPermissionGranted.class)) {
return requestCode == m.getAnnotation(OnMPermissionGranted.class).value();
} else if (clazz.equals(OnMPermissionNeverAskAgain.class)) {
return requestCode == m.getAnnotation(OnMPermissionNeverAskAgain.class).value();
} else {
return false;
}
}
/**
* ********************* reflect execute method *********************
*/
private static void executeMethod(Object activity, Method executeMethod) {
executeMethodWithParam(activity, executeMethod, new Object[]{});
}
private static void executeMethodWithParam(Object activity, Method executeMethod, Object... args) {
if (executeMethod != null) {
try {
if (!executeMethod.isAccessible()) {
executeMethod.setAccessible(true);
}
executeMethod.invoke(activity, args);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}

View File

@@ -1,15 +0,0 @@
package com.netease.nim.uikit.support.permission.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* register a method invoked when permission requests are denied without check never ask again.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OnMPermissionDenied {
int value();
}

View File

@@ -1,15 +0,0 @@
package com.netease.nim.uikit.support.permission.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* register a method invoked when permission requests are succeeded.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OnMPermissionGranted {
int value();
}

View File

@@ -1,15 +0,0 @@
package com.netease.nim.uikit.support.permission.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* register some methods handling the user's choice to permanently deny permissions checking never ask again.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OnMPermissionNeverAskAgain {
int value();
}