From 6712a2d91f927784db02fbacc254ac30ebc8aa9b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 28 Apr 2018 16:32:23 +0200 Subject: [PATCH] added search result context menu + date separators --- .../entities/IndividualMessage.java | 13 +++ .../siacs/conversations/entities/Message.java | 10 +- .../ui/ConversationFragment.java | 78 +++----------- .../ui/ConversationsActivity.java | 1 + .../ui/ConversationsOverviewFragment.java | 2 +- .../conversations/ui/SearchActivity.java | 83 +++++++++++++- .../ui/ShareLocationActivity.java | 2 +- .../siacs/conversations/ui/XmppActivity.java | 18 ++-- .../conversations/ui/util/ChangeWatcher.java | 47 ++++++++ .../conversations/ui/util/ShareUtil.java | 101 ++++++++++++++++++ .../conversations/utils/ThemeHelper.java | 7 +- src/main/res/menu/search_result_context.xml | 45 ++++++++ src/main/res/values/colors.xml | 2 + src/main/res/values/themes.xml | 2 +- 14 files changed, 320 insertions(+), 91 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/ui/util/ChangeWatcher.java create mode 100644 src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java create mode 100644 src/main/res/menu/search_result_context.xml diff --git a/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java b/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java index 305fd67df0cbdd73dc212df9bffdb3d4d7f6906b..9794376383dc41a73c63e36e6f6a8b928f064697 100644 --- a/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java +++ b/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java @@ -33,11 +33,16 @@ import android.database.Cursor; import java.util.Set; +import eu.siacs.conversations.ui.adapter.MessageAdapter; import rocks.xmpp.addr.Jid; public class IndividualMessage extends Message { + private IndividualMessage(Conversational conversation) { + super(conversation); + } + private IndividualMessage(Conversational conversation, String uuid, String conversationUUid, Jid counterpart, Jid trueCounterpart, String body, long timeSent, int encryption, int status, int type, boolean carbon, String remoteMsgId, String relativeFilePath, String serverMsgId, String fingerprint, boolean read, String edited, boolean oob, String errorMessage, Set readByMarkers, boolean markable) { super(conversation, uuid, conversationUUid, counterpart, trueCounterpart, body, timeSent, encryption, status, type, carbon, remoteMsgId, relativeFilePath, serverMsgId, fingerprint, read, edited, oob, errorMessage, readByMarkers, markable); } @@ -57,6 +62,14 @@ public class IndividualMessage extends Message { return true; } + public static Message createDateSeparator(Message message) { + final Message separator = new IndividualMessage(message.getConversation()); + separator.setType(Message.TYPE_STATUS); + separator.body = MessageAdapter.DATE_SEPARATOR_BODY; + separator.setTime(message.getTimeSent()); + return separator; + } + public static Message fromCursor(Cursor cursor, Conversational conversation) { Jid jid; try { diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 1bab78b7aa106e3bf798996b2ddf263683223e87..70cbb797972c994ef50750e022540358b1a4b0e6 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -105,7 +105,7 @@ public class Message extends AbstractEntity { private List counterparts; private WeakReference user; - private Message(Conversational conversation) { + protected Message(Conversational conversation) { this.conversation = conversation; } @@ -229,14 +229,6 @@ public class Message extends AbstractEntity { return message; } - public static Message createDateSeparator(Message message) { - final Message separator = new Message(message.getConversation()); - separator.setType(Message.TYPE_STATUS); - separator.body = MessageAdapter.DATE_SEPARATOR_BODY; - separator.setTime(message.getTimeSent()); - return separator; - } - @Override public ContentValues getContentValues() { ContentValues values = new ContentValues(); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index c1d72b4da3e8a9a4db6c393723c009300919c966..8d0bec3f7b550a6c2cf6720ea7efdb9e8d14e45f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -85,6 +85,7 @@ import eu.siacs.conversations.ui.adapter.MessageAdapter; 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.ListViewUtils; import eu.siacs.conversations.ui.util.MenuDoubleTabUtil; import eu.siacs.conversations.ui.util.PendingItem; @@ -92,6 +93,7 @@ import eu.siacs.conversations.ui.util.PresenceSelector; import eu.siacs.conversations.ui.util.ScrollState; import eu.siacs.conversations.ui.util.SendButtonAction; import eu.siacs.conversations.ui.util.SendButtonTool; +import eu.siacs.conversations.ui.util.ShareUtil; import eu.siacs.conversations.ui.widget.EditMessage; import eu.siacs.conversations.utils.MessageUtils; import eu.siacs.conversations.utils.NickValidityChecker; @@ -1111,13 +1113,13 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.share_with: - shareWith(selectedMessage); + ShareUtil.share(activity, selectedMessage); return true; case R.id.correct_message: correctMessage(selectedMessage); return true; case R.id.copy_message: - copyMessage(selectedMessage); + ShareUtil.copyToClipboard(activity, selectedMessage); return true; case R.id.quote_message: quoteMessage(selectedMessage); @@ -1126,7 +1128,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke resendMessage(selectedMessage); return true; case R.id.copy_url: - copyUrl(selectedMessage); + ShareUtil.copyUrlToClipboard(activity, selectedMessage); return true; case R.id.download_file: startDownloadable(selectedMessage); @@ -1570,43 +1572,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke builder.create().show(); } - private void shareWith(Message message) { - Intent shareIntent = new Intent(); - shareIntent.setAction(Intent.ACTION_SEND); - if (message.isGeoUri()) { - shareIntent.putExtra(Intent.EXTRA_TEXT, message.getBody()); - shareIntent.setType("text/plain"); - } else if (!message.isFileOrImage()) { - shareIntent.putExtra(Intent.EXTRA_TEXT, message.getMergedBody().toString()); - shareIntent.setType("text/plain"); - } else { - final DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); - try { - shareIntent.putExtra(Intent.EXTRA_STREAM, FileBackend.getUriForFile(getActivity(), file)); - } catch (SecurityException e) { - Toast.makeText(getActivity(), activity.getString(R.string.no_permission_to_access_x, file.getAbsolutePath()), Toast.LENGTH_SHORT).show(); - return; - } - shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - String mime = message.getMimeType(); - if (mime == null) { - mime = "*/*"; - } - shareIntent.setType(mime); - } - try { - startActivity(Intent.createChooser(shareIntent, getText(R.string.share_with))); - } catch (ActivityNotFoundException e) { - //This should happen only on faulty androids because normally chooser is always available - Toast.makeText(getActivity(), R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT).show(); - } - } - - private void copyMessage(Message message) { - if (activity.copyTextToClipboard(message.getMergedBody().toString(), R.string.message)) { - Toast.makeText(getActivity(), R.string.message_copied_to_clipboard, Toast.LENGTH_SHORT).show(); - } - } private void deleteFile(Message message) { if (activity.xmppConnectionService.getFileBackend().deleteFile(message)) { @@ -1653,24 +1618,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke }); } - private void copyUrl(Message message) { - final String url; - final int resId; - if (message.isGeoUri()) { - resId = R.string.location; - url = message.getBody(); - } else if (message.hasFileOnRemoteHost()) { - resId = R.string.file_url; - url = message.getFileParams().url.toString(); - } else { - url = message.getBody().trim(); - resId = R.string.file_url; - } - if (activity.copyTextToClipboard(url, resId)) { - Toast.makeText(getActivity(), R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT).show(); - } - } - private void cancelTransmission(Message message) { Transferable transferable = message.getTransferable(); if (transferable != null) { @@ -1943,6 +1890,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke final String downloadUuid = extras.getString(ConversationsActivity.EXTRA_DOWNLOAD_UUID); final String text = extras.getString(ConversationsActivity.EXTRA_TEXT); final String nick = extras.getString(ConversationsActivity.EXTRA_NICK); + final boolean asQuote = extras.getBoolean(ConversationsActivity.EXTRA_AS_QUOTE); final boolean pm = extras.getBoolean(ConversationsActivity.EXTRA_IS_PRIVATE_MESSAGE, false); if (nick != null) { if (pm) { @@ -1960,7 +1908,11 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke } } } else { - appendText(text); + if (text != null && asQuote) { + quoteText(text); + } else { + appendText(text); + } } final Message message = downloadUuid == null ? null : conversation.findMessageWithFileAndUuid(downloadUuid); if (message != null) { @@ -2159,13 +2111,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke protected void updateDateSeparators() { synchronized (this.messageList) { - for (int i = 0; i < this.messageList.size(); ++i) { - final Message current = this.messageList.get(i); - if (i == 0 || !UIHelper.sameDay(this.messageList.get(i - 1).getTimeSent(), current.getTimeSent())) { - this.messageList.add(i, Message.createDateSeparator(current)); - i++; - } - } + DateSeparator.addAll(this.messageList); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index 85ef940bd6c1989bcb396db7c3b01a1b5fb24095..40949308d2c38e909f14dddeb5ff43173b0ddd75 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -85,6 +85,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio public static final String EXTRA_CONVERSATION = "conversationUuid"; public static final String EXTRA_DOWNLOAD_UUID = "eu.siacs.conversations.download_uuid"; public static final String EXTRA_TEXT = "text"; + public static final String EXTRA_AS_QUOTE = "as_quote"; public static final String EXTRA_NICK = "nick"; public static final String EXTRA_IS_PRIVATE_MESSAGE = "pm"; diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java index 8852ff2313d057cd37f6cff20d7f5fb81aef7b52..f9b761fc67d4663974c47c0d2d7275c672edf8df 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java @@ -171,7 +171,7 @@ public class ConversationsOverviewFragment extends XmppFragment { } } }); - ThemeHelper.fixTextSize(snackbar); + ThemeHelper.fix(snackbar); snackbar.show(); } }; diff --git a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java index 892be3fbbced97687ccb9ae59a5e6990b9d244cc..233c19fe6153804eadb71696a278583fc3a366ed 100644 --- a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java @@ -36,10 +36,14 @@ import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; import android.util.Log; +import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; import android.widget.EditText; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -47,13 +51,20 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.ActivitySearchBinding; import eu.siacs.conversations.entities.Contact; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Conversational; import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.entities.StubConversation; import eu.siacs.conversations.services.MessageSearchTask; import eu.siacs.conversations.ui.adapter.MessageAdapter; import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable; +import eu.siacs.conversations.ui.util.ChangeWatcher; import eu.siacs.conversations.ui.util.Color; +import eu.siacs.conversations.ui.util.DateSeparator; import eu.siacs.conversations.ui.util.Drawable; import eu.siacs.conversations.ui.util.ListViewUtils; +import eu.siacs.conversations.ui.util.ShareUtil; +import eu.siacs.conversations.utils.MessageUtils; import static eu.siacs.conversations.ui.util.SoftKeyboardUtils.hideSoftKeyboard; import static eu.siacs.conversations.ui.util.SoftKeyboardUtils.showKeyboard; @@ -63,6 +74,8 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc private ActivitySearchBinding binding; private MessageAdapter messageListAdapter; private final List messages = new ArrayList<>(); + private WeakReference selectedMessageReference = new WeakReference<>(null); + private final ChangeWatcher currentSearch = new ChangeWatcher<>(); @Override public void onCreate(final Bundle savedInstanceState) { @@ -73,6 +86,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc this.messageListAdapter = new MessageAdapter(this, this.messages); this.messageListAdapter.setOnContactPictureClicked(this); this.binding.searchResults.setAdapter(messageListAdapter); + registerForContextMenu(this.binding.searchResults); } @Override @@ -82,11 +96,29 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc EditText searchField = searchActionMenuItem.getActionView().findViewById(R.id.search_field); searchField.addTextChangedListener(this); searchField.setHint(R.string.search_messages); - searchField.setInputType(InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); + searchField.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); showKeyboard(searchField); return super.onCreateOptionsMenu(menu); } + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo) menuInfo; + final Message message = this.messages.get(acmi.position); + this.selectedMessageReference = new WeakReference<>(message); + getMenuInflater().inflate(R.menu.search_result_context, menu); + MenuItem copy = menu.findItem(R.id.copy_message); + MenuItem quote = menu.findItem(R.id.quote_message); + MenuItem copyUrl = menu.findItem(R.id.copy_url); + if (message.isGeoUri()) { + copy.setVisible(false); + quote.setVisible(false); + } else { + copyUrl.setVisible(false); + } + super.onCreateContextMenu(menu, v, menuInfo); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { @@ -95,6 +127,43 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc return super.onOptionsItemSelected(item); } + @Override + public boolean onContextItemSelected(MenuItem item) { + final Message message = selectedMessageReference.get(); + if (message != null) { + switch (item.getItemId()) { + case R.id.share_with: + ShareUtil.share(this, message); + break; + case R.id.copy_message: + ShareUtil.copyToClipboard(this, message); + break; + case R.id.copy_url: + ShareUtil.copyUrlToClipboard(this, message); + break; + case R.id.quote_message: + quote(message); + } + } + return super.onContextItemSelected(item); + } + + private void quote(Message message) { + String text = MessageUtils.prepareQuote(message); + final Conversational conversational = message.getConversation(); + final Conversation conversation; + if (conversational instanceof Conversation) { + conversation = (Conversation) conversational; + } else { + conversation = xmppConnectionService.findOrCreateConversation(conversational.getAccount(), + conversational.getJid(), + conversational.getMode() == Conversational.MODE_MULTI, + true, + true); + } + switchToConversationAndQuote(conversation, text); + } + @Override protected void refreshUiReal() { @@ -108,12 +177,12 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc private void changeBackground(boolean hasSearch, boolean hasResults) { if (hasSearch) { if (hasResults) { - binding.searchResults.setBackgroundColor(Color.get(this,R.attr.color_background_secondary)); + binding.searchResults.setBackgroundColor(Color.get(this, R.attr.color_background_secondary)); } else { - binding.searchResults.setBackground(Drawable.get(this,R.attr.activity_background_no_results)); + binding.searchResults.setBackground(Drawable.get(this, R.attr.activity_background_no_results)); } } else { - binding.searchResults.setBackground(Drawable.get(this,R.attr.activity_background_search)); + binding.searchResults.setBackground(Drawable.get(this, R.attr.activity_background_search)); } } @@ -129,7 +198,10 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc @Override public void afterTextChanged(Editable s) { - String term = s.toString().trim(); + final String term = s.toString().trim(); + if (!currentSearch.watch(term)) { + return; + } if (term.length() > 0) { xmppConnectionService.search(s.toString().trim(), this); } else { @@ -144,6 +216,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc public void onSearchResultsAvailable(String term, List messages) { runOnUiThread(() -> { this.messages.clear(); + DateSeparator.addAll(messages); this.messages.addAll(messages); messageListAdapter.notifyDataSetChanged(); changeBackground(true, messages.size() > 0); diff --git a/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java index 734fb7ddaf33922f37b37e2864f34330ef04a3ef..ce5777fa10c6803d5429e3d7db25d71309f45f92 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java @@ -72,7 +72,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); } }); - ThemeHelper.fixTextSize(this.snackBar); + ThemeHelper.fix(this.snackBar); this.binding.shareButton.setOnClickListener(view -> { final Intent result = new Intent(); diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 89c6d58abc6abe97cce06c1d41487ea720ecc105..6c61f62bcedd46f04154824d56ffd995458332d9 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -467,25 +467,31 @@ public abstract class XmppActivity extends ActionBarActivity { switchToConversation(conversation, null, false); } - public void switchToConversation(Conversation conversation, String text, - boolean newTask) { - switchToConversation(conversation, text, null, false, newTask); + public void switchToConversationAndQuote(Conversation conversation, String text) { + switchToConversation(conversation, text, true, null, false, false); + } + + public void switchToConversation(Conversation conversation, String text, boolean newTask) { + switchToConversation(conversation, text, false, null, false, newTask); } public void highlightInMuc(Conversation conversation, String nick) { - switchToConversation(conversation, null, nick, false, false); + switchToConversation(conversation, null, false, nick, false, false); } public void privateMsgInMuc(Conversation conversation, String nick) { - switchToConversation(conversation, null, nick, true, false); + switchToConversation(conversation, null, false, nick, true, false); } - private void switchToConversation(Conversation conversation, String text, String nick, boolean pm, boolean newTask) { + private void switchToConversation(Conversation conversation, String text, boolean asQuote, String nick, boolean pm, boolean newTask) { Intent intent = new Intent(this, ConversationsActivity.class); intent.setAction(ConversationsActivity.ACTION_VIEW_CONVERSATION); intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid()); if (text != null) { intent.putExtra(ConversationsActivity.EXTRA_TEXT, text); + if (asQuote) { + intent.putExtra(ConversationsActivity.EXTRA_AS_QUOTE, asQuote); + } } if (nick != null) { intent.putExtra(ConversationsActivity.EXTRA_NICK, nick); diff --git a/src/main/java/eu/siacs/conversations/ui/util/ChangeWatcher.java b/src/main/java/eu/siacs/conversations/ui/util/ChangeWatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..259236ae8c15e28a5934ee2772c301fe4430fab8 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/util/ChangeWatcher.java @@ -0,0 +1,47 @@ +/* + * 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; + +public class ChangeWatcher { + + private T object = null; + + public synchronized boolean watch(T object) { + if (this.object == null) { + this.object = object; + return object != null; + } else { + final boolean changed = !this.object.equals(object); + this.object = object; + return changed; + } + } + +} diff --git a/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java b/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..1384aba620a749885330a76c275c0a30e0232781 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/util/ShareUtil.java @@ -0,0 +1,101 @@ +/* + * 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.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.support.v4.content.ContextCompat; +import android.widget.Toast; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.DownloadableFile; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.ui.XmppActivity; + +public class ShareUtil { + + public static void share(XmppActivity activity, Message message) { + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + if (message.isGeoUri()) { + shareIntent.putExtra(Intent.EXTRA_TEXT, message.getBody()); + shareIntent.setType("text/plain"); + } else if (!message.isFileOrImage()) { + shareIntent.putExtra(Intent.EXTRA_TEXT, message.getMergedBody().toString()); + shareIntent.setType("text/plain"); + } else { + final DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + try { + shareIntent.putExtra(Intent.EXTRA_STREAM, FileBackend.getUriForFile(activity, file)); + } catch (SecurityException e) { + Toast.makeText(activity, activity.getString(R.string.no_permission_to_access_x, file.getAbsolutePath()), Toast.LENGTH_SHORT).show(); + return; + } + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + String mime = message.getMimeType(); + if (mime == null) { + mime = "*/*"; + } + shareIntent.setType(mime); + } + try { + activity.startActivity(Intent.createChooser(shareIntent, activity.getText(R.string.share_with))); + } catch (ActivityNotFoundException e) { + //This should happen only on faulty androids because normally chooser is always available + Toast.makeText(activity, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT).show(); + } + } + + public static void copyToClipboard(XmppActivity activity, Message message) { + if (activity.copyTextToClipboard(message.getMergedBody().toString(), R.string.message)) { + Toast.makeText(activity, R.string.message_copied_to_clipboard, Toast.LENGTH_SHORT).show(); + } + } + + public static void copyUrlToClipboard(XmppActivity activity, Message message) { + final String url; + final int resId; + if (message.isGeoUri()) { + resId = R.string.location; + url = message.getBody(); + } else if (message.hasFileOnRemoteHost()) { + resId = R.string.file_url; + url = message.getFileParams().url.toString(); + } else { + url = message.getBody().trim(); + resId = R.string.file_url; + } + if (activity.copyTextToClipboard(url, resId)) { + Toast.makeText(activity, R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT).show(); + } + } +} diff --git a/src/main/java/eu/siacs/conversations/utils/ThemeHelper.java b/src/main/java/eu/siacs/conversations/utils/ThemeHelper.java index 460ef9b5f32711f628105b2c31e630672d1d9924..72998c7295af76c40fe2aedf38d006c569448f4a 100644 --- a/src/main/java/eu/siacs/conversations/utils/ThemeHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/ThemeHelper.java @@ -36,6 +36,7 @@ import android.content.res.TypedArray; import android.preference.PreferenceManager; import android.support.annotation.StyleRes; import android.support.design.widget.Snackbar; +import android.support.v4.content.ContextCompat; import android.util.Log; import android.util.TypedValue; import android.widget.TextView; @@ -87,8 +88,9 @@ public class ThemeHelper { } } - public static void fixTextSize(Snackbar snackbar) { - TypedArray typedArray = snackbar.getContext().obtainStyledAttributes(new int[]{R.attr.TextSizeBody1}); + public static void fix(Snackbar snackbar) { + final Context context = snackbar.getContext(); + TypedArray typedArray = context.obtainStyledAttributes(new int[]{R.attr.TextSizeBody1}); final float size = typedArray.getDimension(0,0f); typedArray.recycle(); if (size != 0f) { @@ -97,6 +99,7 @@ public class ThemeHelper { if (text != null && action != null) { text.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); action.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); + action.setTextColor(ContextCompat.getColor(context, R.color.deep_purple_a100)); } } } diff --git a/src/main/res/menu/search_result_context.xml b/src/main/res/menu/search_result_context.xml new file mode 100644 index 0000000000000000000000000000000000000000..ea32659f678d5e59a915bf7b2aca9f629ab389a6 --- /dev/null +++ b/src/main/res/menu/search_result_context.xml @@ -0,0 +1,45 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml index bf3b14b907f7551a849e9120061a36a3918bf027..7842d6ae2ab791e082bd4f20e807f76653bffb8c 100644 --- a/src/main/res/values/colors.xml +++ b/src/main/res/values/colors.xml @@ -22,6 +22,8 @@ #ffff9800 #ffB388FF #ff7C4DFF + #ff651FFF + #ff6200EA #ff4CAF50 #ff43A047 #ff388E3C diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml index bc2508191eb128bbcc62d25859faad8cd28b1a48..193c95c4751490a6c014eade9ff22b6adf5de340 100644 --- a/src/main/res/values/themes.xml +++ b/src/main/res/values/themes.xml @@ -3,7 +3,7 @@