diff options
Diffstat (limited to 'src/main/java/eu/siacs/conversations/ui/ConversationFragment.java')
-rw-r--r-- | src/main/java/eu/siacs/conversations/ui/ConversationFragment.java | 342 |
1 files changed, 155 insertions, 187 deletions
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 1665090c..3c45792f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -8,6 +8,7 @@ import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.os.Bundle; import android.support.annotation.Nullable; @@ -28,19 +29,27 @@ import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.ListView; +import android.widget.PopupWindow; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; +import com.orangegangsters.github.swipyrefreshlayout.library.SwipyRefreshLayout; + import net.java.otr4j.session.SessionStatus; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.UUID; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.ui.dialogs.MessageDetailsDialog; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -51,9 +60,11 @@ import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presence; +import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.TransferablePlaceholder; import eu.siacs.conversations.http.HttpDownloadConnection; +import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected; @@ -61,11 +72,15 @@ import eu.siacs.conversations.ui.XmppActivity.OnValueEdited; import eu.siacs.conversations.ui.adapter.MessageAdapter; import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked; import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked; +import eu.siacs.conversations.ui.listeners.ConversationSwipeRefreshListener; import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.jid.Jid; +import github.ankushsachdeva.emojicon.EmojiconGridView; +import github.ankushsachdeva.emojicon.EmojiconsPopup; +import github.ankushsachdeva.emojicon.emoji.Emojicon; public class ConversationFragment extends Fragment implements EditMessage.KeyboardListener { @@ -104,113 +119,19 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } }; protected ListView messagesView; + protected SwipyRefreshLayout swipeLayout; final protected List<Message> messageList = new ArrayList<>(); protected MessageAdapter messageListAdapter; private EditMessage mEditMessage; private ImageButton mSendButton; + private ImageView mEmojButton; + private View mRootView; + private EmojiconsPopup mEmojPopup; private RelativeLayout snackbar; private TextView snackbarMessage; private TextView snackbarAction; private boolean messagesLoaded = true; private Toast messageLoaderToast; - - private OnScrollListener mOnScrollListener = new OnScrollListener() { - - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - // TODO Auto-generated method stub - - } - - private int getIndexOf(String uuid, List<Message> messages) { - if (uuid == null) { - return messages.size() - 1; - } - for(int i = 0; i < messages.size(); ++i) { - if (uuid.equals(messages.get(i).getUuid())) { - return i; - } else { - Message next = messages.get(i); - while(next != null && next.wasMergedIntoPrevious()) { - if (uuid.equals(next.getUuid())) { - return i; - } - next = next.next(); - } - - } - } - return 0; - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, - int visibleItemCount, int totalItemCount) { - synchronized (ConversationFragment.this.messageList) { - if (firstVisibleItem < 5 && messagesLoaded && messageList.size() > 0) { - long timestamp; - if (messageList.get(0).getType() == Message.TYPE_STATUS && messageList.size() >= 2) { - timestamp = messageList.get(1).getTimeSent(); - } else { - timestamp = messageList.get(0).getTimeSent(); - } - messagesLoaded = false; - activity.xmppConnectionService.loadMoreMessages(conversation, timestamp, new XmppConnectionService.OnMoreMessagesLoaded() { - @Override - public void onMoreMessagesLoaded(final int c, Conversation conversation) { - if (ConversationFragment.this.conversation != conversation) { - return; - } - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - final int oldPosition = messagesView.getFirstVisiblePosition(); - final Message message; - if (oldPosition < messageList.size()) { - message = messageList.get(oldPosition); - } else { - message = null; - } - String uuid = message != null ? message.getUuid() : null; - View v = messagesView.getChildAt(0); - final int pxOffset = (v == null) ? 0 : v.getTop(); - ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList); - updateStatusMessages(); - messageListAdapter.notifyDataSetChanged(); - int pos = getIndexOf(uuid,messageList); - messagesView.setSelectionFromTop(pos, pxOffset); - messagesLoaded = true; - if (messageLoaderToast != null) { - messageLoaderToast.cancel(); - } - } - }); - } - - @Override - public void informUser(final int resId) { - - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - if (messageLoaderToast != null) { - messageLoaderToast.cancel(); - } - if (ConversationFragment.this.conversation != conversation) { - return; - } - messageLoaderToast = Toast.makeText(activity, resId, Toast.LENGTH_LONG); - messageLoaderToast.show(); - } - }); - - } - }); - - } - } - } - }; private final int KEYCHAIN_UNLOCK_NOT_REQUIRED = 0; private final int KEYCHAIN_UNLOCK_REQUIRED = 1; private final int KEYCHAIN_UNLOCK_PENDING = 2; @@ -300,14 +221,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa activity.attachFile(ConversationActivity.ATTACHMENT_CHOICE_CHOOSE_IMAGE); break; case CANCEL: - if (conversation != null) { - if (conversation.getCorrectingMessage() != null) { - conversation.setCorrectingMessage(null); - mEditMessage.getEditableText().clear(); - } - if (conversation.getMode() == Conversation.MODE_MULTI) { - conversation.setNextCounterpart(null); - } + if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) { + conversation.setNextCounterpart(null); updateChatMsgHint(); updateSendButton(); } @@ -342,21 +257,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (body.length() == 0 || this.conversation == null) { return; } - final Message message; - if (conversation.getCorrectingMessage() == null) { - message = new Message(conversation, body, conversation.getNextEncryption()); - if (conversation.getMode() == Conversation.MODE_MULTI) { - if (conversation.getNextCounterpart() != null) { - message.setCounterpart(conversation.getNextCounterpart()); - message.setType(Message.TYPE_PRIVATE); - } + Message message = new Message(conversation, body, conversation.getNextEncryption()); + if (conversation.getMode() == Conversation.MODE_MULTI) { + if (conversation.getNextCounterpart() != null) { + message.setCounterpart(conversation.getNextCounterpart()); + message.setType(Message.TYPE_PRIVATE); } - } else { - message = conversation.getCorrectingMessage(); - message.setBody(body); - message.setEdited(message.getUuid()); - message.setUuid(UUID.randomUUID().toString()); - conversation.setCorrectingMessage(null); } switch (conversation.getNextEncryption()) { case Message.ENCRYPTION_OTR: @@ -377,9 +283,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa public void updateChatMsgHint() { final boolean multi = conversation.getMode() == Conversation.MODE_MULTI; - if (conversation.getCorrectingMessage() != null) { - this.mEditMessage.setHint(R.string.send_corrected_message); - } else if (multi && conversation.getNextCounterpart() != null) { + if (multi && conversation.getNextCounterpart() != null) { this.mEditMessage.setHint(getString( R.string.send_private_message_to, conversation.getNextCounterpart().getResourcepart())); @@ -415,7 +319,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa public void setupIme() { if (activity == null) { return; - } else if (activity.usingEnterKey() && activity.enterIsSend()) { + } else if (activity.usingEnterKey() && ConversationsPlusPreferences.enterIsSend()) { mEditMessage.setInputType(mEditMessage.getInputType() & (~InputType.TYPE_TEXT_FLAG_MULTI_LINE)); mEditMessage.setInputType(mEditMessage.getInputType() & (~InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE)); } else if (activity.usingEnterKey()) { @@ -443,6 +347,107 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa }); mEditMessage.setOnEditorActionListener(mEditorActionListener); + // Start of emojicon + mEmojButton = (ImageView) view.findViewById(R.id.emoji_btn); + mRootView = view.findViewById(R.id.textsend); + + // Give the topmost view of your activity layout hierarchy. This will be used to measure soft keyboard height + mEmojPopup = new EmojiconsPopup(mRootView, this.getActivity()); + + //Will automatically set size according to the soft keyboard size + mEmojPopup.setSizeForSoftKeyboard(); + + //If the emoji popup is dismissed, change emojiButton to smiley icon + mEmojPopup.setOnDismissListener(new PopupWindow.OnDismissListener() { + + @Override + public void onDismiss() { + changeEmojiKeyboardIcon(mEmojButton, R.drawable.smiley); + } + }); + + //If the text keyboard closes, also dismiss the emoji popup + mEmojPopup.setOnSoftKeyboardOpenCloseListener(new EmojiconsPopup.OnSoftKeyboardOpenCloseListener() { + + @Override + public void onKeyboardOpen(int keyBoardHeight) { + + } + + @Override + public void onKeyboardClose() { + if (mEmojPopup.isShowing()) + mEmojPopup.dismiss(); + } + }); + + //On emoji clicked, add it to edittext + mEmojPopup.setOnEmojiconClickedListener(new EmojiconGridView.OnEmojiconClickedListener() { + + @Override + public void onEmojiconClicked(Emojicon emojicon) { + if (mEditMessage == null || emojicon == null) { + return; + } + + int start = mEditMessage.getSelectionStart(); + int end = mEditMessage.getSelectionEnd(); + if (start < 0) { + mEditMessage.append(emojicon.getEmoji()); + } else { + mEditMessage.getText().replace(Math.min(start, end), + Math.max(start, end), emojicon.getEmoji(), 0, + emojicon.getEmoji().length()); + } + } + }); + + //On backspace clicked, emulate the KEYCODE_DEL key event + mEmojPopup.setOnEmojiconBackspaceClickedListener(new EmojiconsPopup.OnEmojiconBackspaceClickedListener() { + + @Override + public void onEmojiconBackspaceClicked(View v) { + KeyEvent event = new KeyEvent( + 0, 0, 0, KeyEvent.KEYCODE_DEL, 0, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL); + mEditMessage.dispatchKeyEvent(event); + } + }); + + // To toggle between text keyboard and emoji keyboard keyboard(Popup) + mEmojButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + + //If popup is not showing => emoji keyboard is not visible, we need to show it + if(!mEmojPopup.isShowing()){ + + //If keyboard is visible, simply show the emoji popup + if(mEmojPopup.isKeyBoardOpen()){ + mEmojPopup.showAtBottom(); + changeEmojiKeyboardIcon(mEmojButton, R.drawable.ic_action_keyboard); + } + + //else, open the text keyboard first and immediately after that show the emoji popup + else{ + mEditMessage.setFocusableInTouchMode(true); + mEditMessage.requestFocus(); + mEmojPopup.showAtBottomPending(); + final InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.showSoftInput(mEditMessage, InputMethodManager.SHOW_IMPLICIT); + changeEmojiKeyboardIcon(mEmojButton, R.drawable.ic_action_keyboard); + } + } + + //If popup is showing, simply dismiss it to show the undelying text keyboard + else{ + mEmojPopup.dismiss(); + } + } + }); + + // End of emojicon + mSendButton = (ImageButton) view.findViewById(R.id.textSendButton); mSendButton.setOnClickListener(this.mSendButtonListener); @@ -451,7 +456,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa snackbarAction = (TextView) view.findViewById(R.id.snackbar_action); messagesView = (ListView) view.findViewById(R.id.messages_view); - messagesView.setOnScrollListener(mOnScrollListener); messagesView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL); messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList); messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() { @@ -506,6 +510,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa registerForContextMenu(messagesView); + // Start of swipe refresh + // New Swipe refresh + swipeLayout = (SwipyRefreshLayout) view.findViewById(R.id.swipe_refresh_container); + swipeLayout.setOnRefreshListener(new ConversationSwipeRefreshListener(messageList, swipeLayout, this, messagesView, messageListAdapter)); + // End of swipe refresh + return view; } @@ -522,16 +532,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa private void populateContextMenu(ContextMenu menu) { final Message m = this.selectedMessage; final Transferable t = m.getTransferable(); - Message relevantForCorrection = m; - while(relevantForCorrection.mergeable(relevantForCorrection.next())) { - relevantForCorrection = relevantForCorrection.next(); - } if (m.getType() != Message.TYPE_STATUS) { activity.getMenuInflater().inflate(R.menu.message_context, menu); menu.setHeaderTitle(R.string.message_options); MenuItem copyText = menu.findItem(R.id.copy_text); MenuItem retryDecryption = menu.findItem(R.id.retry_decryption); - MenuItem correctMessage = menu.findItem(R.id.correct_message); MenuItem shareWith = menu.findItem(R.id.share_with); MenuItem sendAgain = menu.findItem(R.id.send_again); MenuItem copyUrl = menu.findItem(R.id.copy_url); @@ -546,10 +551,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (m.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { retryDecryption.setVisible(true); } - if (relevantForCorrection.getType() == Message.TYPE_TEXT - && relevantForCorrection.isLastCorrectableMessage()) { - correctMessage.setVisible(true); - } + if ((m.getType() != Message.TYPE_TEXT && m.getType() != Message.TYPE_PRIVATE && t == null) @@ -581,15 +583,15 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { + case R.id.msg_ctx_mnu_details: + new MessageDetailsDialog(getActivity(), selectedMessage).show(); + return true; case R.id.share_with: shareWith(selectedMessage); return true; case R.id.copy_text: copyText(selectedMessage); return true; - case R.id.correct_message: - correctMessage(selectedMessage); - return true; case R.id.send_again: resendMessage(selectedMessage); return true; @@ -618,8 +620,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa shareIntent.setType("text/plain"); } else { shareIntent.putExtra(Intent.EXTRA_STREAM, - activity.xmppConnectionService.getFileBackend() - .getJingleFileUri(message)); + FileBackend.getJingleFileUri(message)); shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); String mime = message.getMimeType(); if (mime == null) { @@ -636,7 +637,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } private void copyText(Message message) { - if (activity.copyTextToClipboard(message.getMergedBody(), + if (activity.copyTextToClipboard(message.getBody(), R.string.message_text)) { Toast.makeText(activity, R.string.message_copied_to_clipboard, Toast.LENGTH_SHORT).show(); @@ -645,7 +646,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa private void resendMessage(Message message) { if (message.getType() == Message.TYPE_FILE || message.getType() == Message.TYPE_IMAGE) { - DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + DownloadableFile file = FileBackend.getFile(message); if (!file.exists()) { Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show(); message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); @@ -665,7 +666,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa resId = R.string.file_url; url = message.getFileParams().url.toString(); } else { - url = message.getBody().trim(); + url = message.getBody(); resId = R.string.file_url; } if (activity.copyTextToClipboard(url, resId)) { @@ -701,18 +702,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa updateSendButton(); } - private void correctMessage(Message message) { - while(message.mergeable(message.next())) { - message = message.next(); - } - this.conversation.setCorrectingMessage(message); - this.mEditMessage.getEditableText().clear(); - this.mEditMessage.getEditableText().append(message.getBody()); - - } - protected void highlightInConference(String nick) { - String oldString = mEditMessage.getText().toString().trim(); + String oldString = mEditMessage.getText().toString(); if (oldString.isEmpty() || mEditMessage.getSelectionStart() == 0) { mEditMessage.getText().insert(0, nick + ": "); } else { @@ -767,7 +758,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa this.mEditMessage.setText(""); this.mEditMessage.append(this.conversation.getNextMessage()); this.mEditMessage.setKeyboardListener(this); - messageListAdapter.updatePreferences(); this.messagesView.setAdapter(messageListAdapter); updateMessages(); this.messagesLoaded = true; @@ -775,6 +765,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (size > 0) { messagesView.setSelection(size - 1); } + swipeLayout.setRefreshing(false); } private OnClickListener mEnableAccountListener = new OnClickListener() { @@ -1033,9 +1024,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final String text = this.mEditMessage == null ? "" : this.mEditMessage.getText().toString(); final boolean empty = text.length() == 0; final boolean conference = c.getMode() == Conversation.MODE_MULTI; - if (c.getCorrectingMessage() != null && (empty || text.equals(c.getCorrectingMessage().getBody()))) { - action = SendButtonAction.CANCEL; - } else if (conference && !c.getAccount().httpUploadAvailable()) { + if (conference && !c.getAccount().httpUploadAvailable()) { if (empty && c.getNextCounterpart() != null) { action = SendButtonAction.CANCEL; } else { @@ -1046,11 +1035,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (conference && c.getNextCounterpart() != null) { action = SendButtonAction.CANCEL; } else { - String setting = activity.getPreferences().getString("quick_action", "recent"); + String setting = ConversationsPlusPreferences.quickAction(); if (!setting.equals("none") && UIHelper.receivedLocationQuestion(conversation.getLatestMessage())) { setting = "location"; } else if (setting.equals("recent")) { - setting = activity.getPreferences().getString("recently_used_quick_action", "text"); + setting = ConversationsPlusPreferences.recentlyUsedQuickAction(); } switch (setting) { case "photo": @@ -1074,7 +1063,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa action = SendButtonAction.TEXT; } } - if (activity.useSendButtonToIndicateStatus() && c != null + if (ConversationsPlusPreferences.sendButtonStatus() && c != null && c.getAccount().getStatus() == Account.State.ONLINE) { if (c.getMode() == Conversation.MODE_SINGLE) { status = c.getContact().getMostAvailableStatus(); @@ -1088,11 +1077,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa this.mSendButton.setImageResource(getSendButtonImageResource(action, status)); } - protected void updateStatusMessages() { + public void updateStatusMessages() { synchronized (this.messageList) { - if (showLoadMoreMessages(conversation)) { - this.messageList.add(0, Message.createLoadMoreMessage(conversation)); - } if (conversation.getMode() == Conversation.MODE_SINGLE) { ChatState state = conversation.getIncomingChatState(); if (state == ChatState.COMPOSING) { @@ -1116,21 +1102,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } - private boolean showLoadMoreMessages(final Conversation c) { - final boolean mam = hasMamSupport(c); - final MessageArchiveService service = activity.xmppConnectionService.getMessageArchiveService(); - return mam && (c.getLastClearHistory() != 0 || (c.countMessages() == 0 && c.hasMessagesLeftOnServer() && !service.queryInProgress(c))); - } - - private boolean hasMamSupport(final Conversation c) { - if (c.getMode() == Conversation.MODE_SINGLE) { - final XmppConnection connection = c.getAccount().getXmppConnection(); - return connection != null && connection.getFeatures().mam(); - } else { - return c.getMucOptions().mamSupport(); - } - } - protected void showSnackbar(final int message, final int action, final OnClickListener clickListener) { snackbar.setVisibility(View.VISIBLE); snackbar.setOnClickListener(null); @@ -1291,7 +1262,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public boolean onEnterPressed() { - if (activity.enterIsSend()) { + if (ConversationsPlusPreferences.enterIsSend()) { sendMessage(); return true; } else { @@ -1326,13 +1297,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa updateSendButton(); } - @Override - public void onTextChanged() { - if (conversation != null && conversation.getCorrectingMessage() != null) { - updateSendButton(); - } - } - private int completionIndex = 0; private int lastCompletionLength = 0; private String incomplete; @@ -1399,4 +1363,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } + private void changeEmojiKeyboardIcon(ImageView iconToBeChanged, int drawableResourceId){ + iconToBeChanged.setImageResource(drawableResourceId); + } + } |