add ‘paste as quote’ for api >= 23
This commit is contained in:
		
							parent
							
								
									00281112b9
								
							
						
					
					
						commit
						e8066debf8
					
				| @ -85,6 +85,7 @@ import eu.siacs.conversations.ui.util.ActivityResult; | ||||
| import eu.siacs.conversations.ui.util.AttachmentTool; | ||||
| import eu.siacs.conversations.ui.util.ConversationMenuConfigurator; | ||||
| import eu.siacs.conversations.ui.util.DateSeparator; | ||||
| import eu.siacs.conversations.ui.util.EditMessageActionModeCallback; | ||||
| import eu.siacs.conversations.ui.util.ListViewUtils; | ||||
| import eu.siacs.conversations.ui.util.MenuDoubleTabUtil; | ||||
| import eu.siacs.conversations.ui.util.PendingItem; | ||||
| @ -991,25 +992,16 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke | ||||
| 
 | ||||
| 		registerForContextMenu(binding.messagesView); | ||||
| 
 | ||||
| 		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||||
| 			this.binding.textinput.setCustomInsertionActionModeCallback(new EditMessageActionModeCallback(this.binding.textinput)); | ||||
| 		} | ||||
| 
 | ||||
| 		return binding.getRoot(); | ||||
| 	} | ||||
| 
 | ||||
| 	private void quoteText(String text) { | ||||
| 		if (binding.textinput.isEnabled()) { | ||||
| 			text = text.replaceAll("(\n *){2,}", "\n").replaceAll("(^|\n)", "$1> ").replaceAll("\n$", ""); | ||||
| 			Editable editable = binding.textinput.getEditableText(); | ||||
| 			int position = binding.textinput.getSelectionEnd(); | ||||
| 			if (position == -1) position = editable.length(); | ||||
| 			if (position > 0 && editable.charAt(position - 1) != '\n') { | ||||
| 				editable.insert(position++, "\n"); | ||||
| 			} | ||||
| 			editable.insert(position, text); | ||||
| 			position += text.length(); | ||||
| 			editable.insert(position++, "\n"); | ||||
| 			if (position < editable.length() && editable.charAt(position) != '\n') { | ||||
| 				editable.insert(position, "\n"); | ||||
| 			} | ||||
| 			binding.textinput.setSelection(position); | ||||
| 			binding.textinput.insertAsQuote(text); | ||||
| 			binding.textinput.requestFocus(); | ||||
| 			InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); | ||||
| 			if (inputMethodManager != null) { | ||||
|  | ||||
| @ -0,0 +1,83 @@ | ||||
| /* | ||||
|  * Copyright (c) 2018, Daniel Gultsch All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without modification, | ||||
|  * are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, this | ||||
|  * list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|  * this list of conditions and the following disclaimer in the documentation and/or | ||||
|  * other materials provided with the distribution. | ||||
|  * | ||||
|  * 3. Neither the name of the copyright holder nor the names of its contributors | ||||
|  * may be used to endorse or promote products derived from this software without | ||||
|  * specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||
|  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | ||||
|  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||||
|  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| package eu.siacs.conversations.ui.util; | ||||
| 
 | ||||
| import android.content.ClipData; | ||||
| import android.content.ClipboardManager; | ||||
| import android.content.Context; | ||||
| import android.view.ActionMode; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuInflater; | ||||
| import android.view.MenuItem; | ||||
| 
 | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.ui.widget.EditMessage; | ||||
| 
 | ||||
| public class EditMessageActionModeCallback implements ActionMode.Callback { | ||||
| 
 | ||||
| 	private final EditMessage editMessage; | ||||
| 	private final ClipboardManager clipboardManager; | ||||
| 
 | ||||
| 	public EditMessageActionModeCallback(EditMessage editMessage) { | ||||
| 		this.editMessage = editMessage; | ||||
| 		this.clipboardManager = (ClipboardManager) editMessage.getContext().getSystemService(Context.CLIPBOARD_SERVICE); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public boolean onCreateActionMode(ActionMode mode, Menu menu) { | ||||
| 		MenuInflater inflater = mode.getMenuInflater(); | ||||
| 		inflater.inflate(R.menu.edit_message_actions, menu); | ||||
| 		MenuItem pasteAsQuote = menu.findItem(R.id.paste_as_quote); | ||||
| 		pasteAsQuote.setVisible(clipboardManager.hasPrimaryClip() && clipboardManager.getPrimaryClipDescription().hasMimeType("text/plain")); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public boolean onPrepareActionMode(ActionMode mode, Menu menu) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public boolean onActionItemClicked(ActionMode mode, MenuItem item) { | ||||
| 		if (item.getItemId() == R.id.paste_as_quote) { | ||||
| 			ClipData primaryClip = clipboardManager.getPrimaryClip(); | ||||
| 			if (primaryClip.getItemCount() >= 1) { | ||||
| 				editMessage.insertAsQuote(primaryClip.getItemAt(0).getText().toString()); | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onDestroyActionMode(ActionMode mode) { | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| @ -129,6 +129,23 @@ public class EditMessage extends EmojiAppCompatEditText { | ||||
| 		this.mCommitContentListener = listener; | ||||
| 	} | ||||
| 
 | ||||
| 	public void insertAsQuote(String text) { | ||||
| 		text = text.replaceAll("(\n *){2,}", "\n").replaceAll("(^|\n)", "$1> ").replaceAll("\n$", ""); | ||||
| 		Editable editable = getEditableText(); | ||||
| 		int position = getSelectionEnd(); | ||||
| 		if (position == -1) position = editable.length(); | ||||
| 		if (position > 0 && editable.charAt(position - 1) != '\n') { | ||||
| 			editable.insert(position++, "\n"); | ||||
| 		} | ||||
| 		editable.insert(position, text); | ||||
| 		position += text.length(); | ||||
| 		editable.insert(position++, "\n"); | ||||
| 		if (position < editable.length() && editable.charAt(position) != '\n') { | ||||
| 			editable.insert(position, "\n"); | ||||
| 		} | ||||
| 		setSelection(position); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public InputConnection onCreateInputConnection(EditorInfo editorInfo) { | ||||
| 		final InputConnection ic = super.onCreateInputConnection(editorInfo); | ||||
|  | ||||
							
								
								
									
										38
									
								
								src/main/res/menu/edit_message_actions.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/main/res/menu/edit_message_actions.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- | ||||
|   ~ Copyright (c) 2018, Daniel Gultsch All rights reserved. | ||||
|   ~ | ||||
|   ~ Redistribution and use in source and binary forms, with or without modification, | ||||
|   ~ are permitted provided that the following conditions are met: | ||||
|   ~ | ||||
|   ~ 1. Redistributions of source code must retain the above copyright notice, this | ||||
|   ~ list of conditions and the following disclaimer. | ||||
|   ~ | ||||
|   ~ 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|   ~ this list of conditions and the following disclaimer in the documentation and/or | ||||
|   ~ other materials provided with the distribution. | ||||
|   ~ | ||||
|   ~ 3. Neither the name of the copyright holder nor the names of its contributors | ||||
|   ~ may be used to endorse or promote products derived from this software without | ||||
|   ~ specific prior written permission. | ||||
|   ~ | ||||
|   ~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||
|   ~ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|   ~ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|   ~ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | ||||
|   ~ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|   ~ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|   ~ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||||
|   ~ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|   ~ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|   ~ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|   --> | ||||
| 
 | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/paste_as_quote" | ||||
|         android:title="Paste as quote" | ||||
|         android:orderInCategory="99"/> | ||||
| 
 | ||||
| </menu> | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Daniel Gultsch
						Daniel Gultsch