aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger/ui
diff options
context:
space:
mode:
authorChristian Schneppe <christian@pix-art.de>2018-09-23 16:42:56 +0200
committerChristian Schneppe <christian@pix-art.de>2018-09-23 16:42:56 +0200
commit1e63a8291579043659f86dbb46d4d63d3225c471 (patch)
tree8f1f2a24aee230eb63364a80ef04d1d7a379d67c /src/main/java/de/pixart/messenger/ui
parentd159ba22126f7be06f50cb33b677ddcc8786219c (diff)
preview media before sending them and allow sharing and attaching of multiple files
Diffstat (limited to '')
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationFragment.java224
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationsActivity.java15
-rw-r--r--src/main/java/de/pixart/messenger/ui/SearchActivity.java8
-rw-r--r--src/main/java/de/pixart/messenger/ui/SettingsActivity.java3
-rw-r--r--src/main/java/de/pixart/messenger/ui/ShareWithActivity.java297
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java8
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java10
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/ListItemAdapter.java8
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java211
-rw-r--r--src/main/java/de/pixart/messenger/ui/forms/FormFieldWrapper.java8
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/Attachment.java120
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/AttachmentTool.java60
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/Drawable.java43
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/StyledAttributes.java (renamed from src/main/java/de/pixart/messenger/ui/util/Color.java)18
14 files changed, 500 insertions, 533 deletions
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
index def4b8a69..451ac6bde 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
@@ -15,8 +15,6 @@ import android.content.IntentSender.SendIntentException;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.databinding.DataBindingUtil;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -27,7 +25,6 @@ import android.provider.MediaStore;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
-import android.support.media.ExifInterface;
import android.support.v13.view.inputmethod.InputConnectionCompat;
import android.support.v13.view.inputmethod.InputContentInfoCompat;
import android.support.v7.app.AlertDialog;
@@ -54,16 +51,12 @@ import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.CheckBox;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
import net.java.otr4j.session.SessionStatus;
-import java.io.File;
-import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -98,9 +91,10 @@ import de.pixart.messenger.http.HttpDownloadConnection;
import de.pixart.messenger.persistance.FileBackend;
import de.pixart.messenger.services.MessageArchiveService;
import de.pixart.messenger.services.XmppConnectionService;
+import de.pixart.messenger.ui.adapter.MediaPreviewAdapter;
import de.pixart.messenger.ui.adapter.MessageAdapter;
import de.pixart.messenger.ui.util.ActivityResult;
-import de.pixart.messenger.ui.util.AttachmentTool;
+import de.pixart.messenger.ui.util.Attachment;
import de.pixart.messenger.ui.util.ConversationMenuConfigurator;
import de.pixart.messenger.ui.util.DateSeparator;
import de.pixart.messenger.ui.util.EditMessageActionModeCallback;
@@ -113,7 +107,6 @@ import de.pixart.messenger.ui.util.SendButtonAction;
import de.pixart.messenger.ui.util.SendButtonTool;
import de.pixart.messenger.ui.util.ShareUtil;
import de.pixart.messenger.ui.widget.EditMessage;
-import de.pixart.messenger.utils.FileUtils;
import de.pixart.messenger.utils.MenuDoubleTabUtil;
import de.pixart.messenger.utils.MessageUtils;
import de.pixart.messenger.utils.NickValidityChecker;
@@ -129,7 +122,6 @@ import rocks.xmpp.addr.Jid;
import static de.pixart.messenger.ui.XmppActivity.EXTRA_ACCOUNT;
import static de.pixart.messenger.ui.XmppActivity.REQUEST_INVITE_TO_CONVERSATION;
-import static de.pixart.messenger.ui.util.SendButtonAction.TEXT;
import static de.pixart.messenger.ui.util.SoftKeyboardUtils.hideSoftKeyboard;
import static de.pixart.messenger.xmpp.Patches.ENCRYPTION_EXCEPTIONS;
@@ -179,6 +171,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
private Toast messageLoaderToast;
private ConversationsActivity activity;
private boolean reInitRequiredOnStart = true;
+ private MediaPreviewAdapter mediaPreviewAdapter;
private SimpleFingerGestures gesturesDetector = new SimpleFingerGestures();
@@ -851,111 +844,19 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
public void attachEditorContentToConversation(Uri uri) {
- this.attachFileToConversation(conversation, uri, null);
+ mediaPreviewAdapter.addMediaPreviews(Attachment.of(getActivity(), uri, Attachment.Type.FILE));
+ toggleInputMethod();
}
- private void attachImageToConversation(Conversation conversation, Uri uri, boolean sendAsIs) {
+ private void attachImageToConversation(Conversation conversation, Uri uri) {
if (conversation == null) {
return;
}
- if (sendAsIs) {
- sendImage(conversation, uri);
- return;
- }
- final Conversation conversation_preview = conversation;
- final Uri uri_preview = uri;
- Bitmap bitmap = null;
- try {
- bitmap = BitmapFactory.decodeFile(FileUtils.getPath(activity, uri));
- } catch (Exception e) {
- e.printStackTrace();
- }
- File file = null;
- ExifInterface exif = null;
- int orientation = 0;
- try {
- file = new File(FileUtils.getPath(activity, uri));
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (file != null) {
- try {
- exif = new ExifInterface(file.toString());
- } catch (IOException e) {
- e.printStackTrace();
- }
- orientation = exif != null ? exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) : 0;
- }
- Log.d(Config.LOGTAG, "EXIF: " + orientation);
- Bitmap rotated_image = null;
- Log.d(Config.LOGTAG, "Rotate image");
- try {
- rotated_image = FileBackend.rotateBitmap(file, bitmap, orientation);
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (rotated_image != null) {
- int scaleSize = 600;
- int originalWidth = rotated_image.getWidth();
- int originalHeight = rotated_image.getHeight();
- int newWidth = -1;
- int newHeight = -1;
- float multFactor;
- if (originalHeight > originalWidth) {
- newHeight = scaleSize;
- multFactor = (float) originalWidth / (float) originalHeight;
- newWidth = (int) (newHeight * multFactor);
- } else if (originalWidth > originalHeight) {
- newWidth = scaleSize;
- multFactor = (float) originalHeight / (float) originalWidth;
- newHeight = (int) (newWidth * multFactor);
- } else if (originalHeight == originalWidth) {
- newHeight = scaleSize;
- newWidth = scaleSize;
- }
- Log.d(Config.LOGTAG, "Scaling preview image from " + originalHeight + "px x " + originalWidth + "px to " + newHeight + "px x " + newWidth + "px");
- Bitmap preview = null;
-
- try {
- preview = Bitmap.createScaledBitmap(rotated_image, newWidth, newHeight, false);
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (preview != null) {
- ImageView ImagePreview = new ImageView(activity);
- LinearLayout.LayoutParams vp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
- ImagePreview.setLayoutParams(vp);
- ImagePreview.setMaxWidth(newWidth);
- ImagePreview.setMaxHeight(newHeight);
- ImagePreview.setPadding(5, 5, 5, 5);
- ImagePreview.setImageBitmap(preview);
- getActivity().runOnUiThread(() -> {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setView(ImagePreview);
- builder.setTitle(R.string.send_image);
- builder.setPositiveButton(R.string.ok, (dialog, which) -> sendImage(conversation_preview, uri_preview));
- builder.setOnCancelListener(dialog -> mPendingImageUris.clear());
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- builder.setOnDismissListener(dialog -> mPendingImageUris.clear());
- }
- AlertDialog alertDialog = builder.create();
- alertDialog.show();
- });
- } else {
- getActivity().runOnUiThread(() -> Toast.makeText(getActivity(), getText(R.string.error_file_not_found), Toast.LENGTH_LONG).show());
- }
- } else {
- getActivity().runOnUiThread(() -> Toast.makeText(getActivity(), getText(R.string.error_file_not_found), Toast.LENGTH_LONG).show());
- }
- }
-
- private void sendImage(Conversation conversation, Uri uri) {
final Toast prepareFileToast = Toast.makeText(getActivity(), getText(R.string.preparing_image), Toast.LENGTH_LONG);
prepareFileToast.show();
activity.delegateUriPermissionsToService(uri);
activity.xmppConnectionService.attachImageToConversation(conversation, uri,
new UiCallback<Message>() {
-
@Override
public void userInputRequried(PendingIntent pi, Message object) {
hidePrepareFileToast(prepareFileToast);
@@ -981,6 +882,10 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
private void sendMessage() {
+ if (mediaPreviewAdapter.hasAttachments()) {
+ commitAttachments();
+ return;
+ }
final String body = binding.textinput.getText().toString();
final Conversation conversation = this.conversation;
if (body.length() == 0 || conversation == null) {
@@ -1086,7 +991,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
private void handlePositiveActivityResult(int requestCode, final Intent data) {
- final String type = data == null ? null : data.getType();
switch (requestCode) {
case REQUEST_TRUST_KEYS_TEXT:
final String body = binding.textinput.getText().toString();
@@ -1098,51 +1002,32 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
selectPresenceToAttachFile(choice);
break;
case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
- final List<Uri> imageUris = AttachmentTool.extractUriFromIntent(data);
- final int ImageUrisCount = imageUris.size();
- Log.d(Config.LOGTAG, "ConversationsActivity.onActivityResult() - attaching image - number of uris: " + ImageUrisCount);
- if (ImageUrisCount == 1) {
- Uri uri = imageUris.get(0);
- Log.d(Config.LOGTAG, "ConversationsActivity.onActivityResult() - attaching image to conversations. CHOOSE_IMAGE");
- attachImageToConversation(conversation, uri, false);
- } else {
- for (Iterator<Uri> i = imageUris.iterator(); i.hasNext(); i.remove()) {
- Log.d(Config.LOGTAG, "ConversationsActivity.onActivityResult() - attaching images to conversations. CHOOSE_IMAGES");
- attachImagesToConversation(conversation, i.next());
- }
- }
+ final List<Attachment> imageUris = Attachment.extractAttachments(getActivity(), data, Attachment.Type.IMAGE);
+ mediaPreviewAdapter.addMediaPreviews(imageUris);
+ toggleInputMethod();
break;
case ATTACHMENT_CHOICE_TAKE_FROM_CAMERA:
final Uri takePhotoUri = pendingTakePhotoUri.pop();
- final Uri takeVideoUri = pendingTakeVideoUri.pop();
if (takePhotoUri != null) {
- attachPhotoToConversation(conversation, takePhotoUri);
- } else if (takeVideoUri != null) {
- attachFileToConversation(conversation, takeVideoUri, type);
+ mediaPreviewAdapter.addMediaPreviews(Attachment.of(getActivity(), takePhotoUri, Attachment.Type.IMAGE));
+ toggleInputMethod();
} else {
- Log.d(Config.LOGTAG, "lost take uri. unable to to attach");
+ Log.d(Config.LOGTAG, "lost take photo uri. unable to to attach");
}
break;
case ATTACHMENT_CHOICE_CHOOSE_FILE:
case ATTACHMENT_CHOICE_RECORD_VOICE:
- final List<Uri> fileUris = AttachmentTool.extractUriFromIntent(data);
- final PresenceSelector.OnPresenceSelected callback = () -> {
- for (Iterator<Uri> i = fileUris.iterator(); i.hasNext(); i.remove()) {
- Log.d(Config.LOGTAG, "ConversationsActivity.onActivityResult() - attaching file to conversations. CHOOSE_FILE/RECORD_VOICE");
- attachFileToConversation(conversation, i.next(), type);
- }
- };
- if (conversation == null || conversation.getMode() == Conversation.MODE_MULTI || FileBackend.allFilesUnderSize(getActivity(), fileUris, getMaxHttpUploadSize(conversation))) {
- callback.onPresenceSelected();
- } else {
- activity.selectPresence(conversation, callback);
- }
+ final Attachment.Type type = requestCode == ATTACHMENT_CHOICE_RECORD_VOICE ? Attachment.Type.RECORDING : Attachment.Type.FILE;
+ final List<Attachment> fileUris = Attachment.extractAttachments(getActivity(), data, type);
+ mediaPreviewAdapter.addMediaPreviews(fileUris);
+ toggleInputMethod();
break;
case ATTACHMENT_CHOICE_LOCATION:
double latitude = data.getDoubleExtra("latitude", 0);
double longitude = data.getDoubleExtra("longitude", 0);
Uri geo = Uri.parse("geo:" + String.valueOf(latitude) + "," + String.valueOf(longitude));
- attachLocationToConversation(conversation, geo);
+ mediaPreviewAdapter.addMediaPreviews(Attachment.of(getActivity(), geo, Attachment.Type.LOCATION));
+ toggleInputMethod();
break;
case REQUEST_INVITE_TO_CONVERSATION:
XmppActivity.ConferenceInvite invite = XmppActivity.ConferenceInvite.parse(data);
@@ -1156,6 +1041,38 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
}
+ private void commitAttachments() {
+ final List<Attachment> attachments = mediaPreviewAdapter.getAttachments();
+ final PresenceSelector.OnPresenceSelected callback = () -> {
+ for (Iterator<Attachment> i = attachments.iterator(); i.hasNext(); i.remove()) {
+ final Attachment attachment = i.next();
+ if (attachment.getType() == Attachment.Type.LOCATION) {
+ attachLocationToConversation(conversation, attachment.getUri());
+ } else if (attachment.getType() == Attachment.Type.IMAGE) {
+ Log.d(Config.LOGTAG, "ConversationsActivity.commitAttachments() - attaching image to conversations. CHOOSE_IMAGE");
+ attachImageToConversation(conversation, attachment.getUri());
+ } else {
+ Log.d(Config.LOGTAG, "ConversationsActivity.commitAttachments() - attaching file to conversations. CHOOSE_FILE/RECORD_VOICE/RECORD_VIDEO");
+ attachFileToConversation(conversation, attachment.getUri(), attachment.getMime());
+ }
+ }
+ mediaPreviewAdapter.notifyDataSetChanged();
+ toggleInputMethod();
+ };
+ if (conversation == null || conversation.getMode() == Conversation.MODE_MULTI || FileBackend.allFilesUnderSize(getActivity(), attachments, getMaxHttpUploadSize(conversation))) {
+ callback.onPresenceSelected();
+ } else {
+ activity.selectPresence(conversation, callback);
+ }
+ }
+
+ public void toggleInputMethod() {
+ boolean hasAttachments = mediaPreviewAdapter.hasAttachments();
+ binding.textinput.setVisibility(hasAttachments ? View.GONE : View.VISIBLE);
+ binding.mediaPreview.setVisibility(hasAttachments ? View.VISIBLE : View.GONE);
+ updateSendButton();
+ }
+
private void handleNegativeActivityResult(int requestCode) {
switch (requestCode) {
//nothing to do for now
@@ -1253,6 +1170,8 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
binding.messagesView.setOnScrollListener(mOnScrollListener);
binding.messagesView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
+ mediaPreviewAdapter = new MediaPreviewAdapter(this);
+ binding.mediaPreview.setAdapter(mediaPreviewAdapter);
messageListAdapter = new MessageAdapter((XmppActivity) getActivity(), this.messageList);
messageListAdapter.setOnContactPictureClicked(message -> {
String fingerprint;
@@ -1871,6 +1790,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
case ATTACHMENT_CHOICE_CHOOSE_FILE:
chooser = true;
intent.setType("*/*");
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setAction(Intent.ACTION_GET_CONTENT);
break;
@@ -2361,6 +2281,12 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
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);
+ final List<Uri> uris = extractUris(extras);
+ if (uris != null && uris.size() > 0) {
+ mediaPreviewAdapter.addMediaPreviews(Attachment.of(getActivity(), uris));
+ toggleInputMethod();
+ return;
+ }
if (nick != null) {
if (pm) {
Jid jid = conversation.getJid();
@@ -2389,6 +2315,19 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
}
+ private List<Uri> extractUris(Bundle extras) {
+ final List<Uri> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
+ if (uris != null) {
+ return uris;
+ }
+ final Uri uri = extras.getParcelable(Intent.EXTRA_STREAM);
+ if (uri != null) {
+ return Collections.singletonList(uri);
+ } else {
+ return null;
+ }
+ }
+
private boolean showBlockSubmenu(View view) {
final Jid jid = conversation.getJid();
if (jid.getLocal() == null) {
@@ -2603,11 +2542,17 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
public void updateSendButton() {
+ boolean hasAttachments = mediaPreviewAdapter != null && mediaPreviewAdapter.hasAttachments();
boolean useSendButtonToIndicateStatus = PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean("send_button_status", getResources().getBoolean(R.bool.send_button_status));
final Conversation c = this.conversation;
final Presence.Status status;
final String text = this.binding.textinput == null ? "" : this.binding.textinput.getText().toString();
- SendButtonAction action = SendButtonTool.getAction(getActivity(), c, text);
+ final SendButtonAction action;
+ if (hasAttachments) {
+ action = SendButtonAction.TEXT;
+ } else {
+ action = SendButtonTool.getAction(getActivity(), c, text);
+ }
if (useSendButtonToIndicateStatus && c.getAccount().getStatus() == Account.State.ONLINE) {
if (activity.xmppConnectionService != null && activity.xmppConnectionService.getMessageArchiveService().isCatchingUp(c)) {
status = Presence.Status.OFFLINE;
@@ -2619,9 +2564,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
} else {
status = Presence.Status.OFFLINE;
}
- if (action.toString().equals("CHOOSE_ATTACHMENT") && !activity.xmppConnectionService.getAttachmentChoicePreference()) {
- action = TEXT;
- }
this.binding.textSendButton.setTag(action);
this.binding.textSendButton.setImageResource(SendButtonTool.getSendButtonImageResource(getActivity(), action, status));
}
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationsActivity.java b/src/main/java/de/pixart/messenger/ui/ConversationsActivity.java
index 11d4cc31f..05cfe3ab4 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationsActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationsActivity.java
@@ -63,6 +63,7 @@ import net.java.otr4j.session.SessionStatus;
import org.openintents.openpgp.util.OpenPgpApi;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -111,6 +112,11 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
public static final String ACTION_DESTROY_MUC = "de.pixart.messenger.DESTROY_MUC";
public static final int REQUEST_OPEN_MESSAGE = 0x9876;
public static final int REQUEST_PLAY_PAUSE = 0x5432;
+ private static List<String> VIEW_AND_SHARE_ACTIONS = Arrays.asList(
+ ACTION_VIEW_CONVERSATION,
+ Intent.ACTION_SEND,
+ Intent.ACTION_SEND_MULTIPLE
+ );
private boolean showLastSeen = false;
@@ -126,8 +132,9 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
private boolean mActivityPaused = true;
private AtomicBoolean mRedirectInProcess = new AtomicBoolean(false);
- private static boolean isViewIntent(Intent i) {
- return i != null && ACTION_VIEW_CONVERSATION.equals(i.getAction()) && i.hasExtra(EXTRA_CONVERSATION);
+ private static boolean isViewOrShareIntent(Intent i) {
+ Log.d(Config.LOGTAG, "action: " + (i == null ? null : i.getAction()));
+ return i != null && VIEW_AND_SHARE_ACTIONS.contains(i.getAction()) && i.hasExtra(EXTRA_CONVERSATION);
}
private static Intent createLauncherIntent(Context context) {
@@ -451,7 +458,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
} else {
intent = savedInstanceState.getParcelable("intent");
}
- if (isViewIntent(intent)) {
+ if (isViewOrShareIntent(intent)) {
pendingViewIntent.push(intent);
setIntent(createLauncherIntent(this));
}
@@ -626,7 +633,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
@Override
protected void onNewIntent(final Intent intent) {
- if (isViewIntent(intent)) {
+ if (isViewOrShareIntent(intent)) {
if (xmppConnectionService != null) {
processViewIntent(intent);
} else {
diff --git a/src/main/java/de/pixart/messenger/ui/SearchActivity.java b/src/main/java/de/pixart/messenger/ui/SearchActivity.java
index cc3172670..9ea9e7592 100644
--- a/src/main/java/de/pixart/messenger/ui/SearchActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/SearchActivity.java
@@ -56,7 +56,7 @@ import de.pixart.messenger.services.MessageSearchTask;
import de.pixart.messenger.ui.adapter.MessageAdapter;
import de.pixart.messenger.ui.interfaces.OnSearchResultsAvailable;
import de.pixart.messenger.ui.util.ChangeWatcher;
-import de.pixart.messenger.ui.util.Color;
+import de.pixart.messenger.ui.util.StyledAttributes;
import de.pixart.messenger.ui.util.DateSeparator;
import de.pixart.messenger.ui.util.Drawable;
import de.pixart.messenger.ui.util.ListViewUtils;
@@ -213,12 +213,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(StyledAttributes.getColor(this, R.attr.color_background_secondary));
} else {
- binding.searchResults.setBackground(Drawable.get(this, R.attr.activity_background_no_results));
+ binding.searchResults.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_background_no_results));
}
} else {
- binding.searchResults.setBackground(Drawable.get(this, R.attr.activity_background_search));
+ binding.searchResults.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_background_search));
}
}
diff --git a/src/main/java/de/pixart/messenger/ui/SettingsActivity.java b/src/main/java/de/pixart/messenger/ui/SettingsActivity.java
index 0e4b5d391..c9c6006de 100644
--- a/src/main/java/de/pixart/messenger/ui/SettingsActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/SettingsActivity.java
@@ -38,7 +38,6 @@ import de.pixart.messenger.crypto.OmemoSetting;
import de.pixart.messenger.entities.Account;
import de.pixart.messenger.services.ExportLogsService;
import de.pixart.messenger.services.MemorizingTrustManager;
-import de.pixart.messenger.ui.util.Color;
import de.pixart.messenger.utils.TimeframeUtils;
import rocks.xmpp.addr.Jid;
@@ -85,7 +84,7 @@ public class SettingsActivity extends XmppActivity implements
fm.beginTransaction().replace(R.id.settings_content, mSettingsFragment).commit();
}
mSettingsFragment.setActivityIntent(getIntent());
- getWindow().getDecorView().setBackgroundColor(Color.get(this, R.attr.color_background_secondary));
+ getWindow().getDecorView().setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_secondary));
setSupportActionBar(findViewById(R.id.toolbar));
configureActionBar(getSupportActionBar());
}
diff --git a/src/main/java/de/pixart/messenger/ui/ShareWithActivity.java b/src/main/java/de/pixart/messenger/ui/ShareWithActivity.java
index a820378a3..da3d2ff8f 100644
--- a/src/main/java/de/pixart/messenger/ui/ShareWithActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/ShareWithActivity.java
@@ -1,6 +1,5 @@
package de.pixart.messenger.ui;
-import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
@@ -12,116 +11,32 @@ import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
-import java.net.URLConnection;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
import de.pixart.messenger.Config;
import de.pixart.messenger.R;
import de.pixart.messenger.entities.Account;
import de.pixart.messenger.entities.Conversation;
-import de.pixart.messenger.entities.Message;
-import de.pixart.messenger.persistance.FileBackend;
import de.pixart.messenger.services.EmojiService;
import de.pixart.messenger.services.XmppConnectionService;
import de.pixart.messenger.ui.adapter.ConversationAdapter;
-import de.pixart.messenger.ui.util.PresenceSelector;
-import de.pixart.messenger.xmpp.XmppConnection;
import rocks.xmpp.addr.Jid;
import static de.pixart.messenger.ui.SettingsActivity.USE_BUNDLED_EMOJIS;
-import static java.lang.String.format;
public class ShareWithActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate {
private static final int REQUEST_STORAGE_PERMISSION = 0x733f32;
- private boolean mReturnToPrevious = false;
+ private static final int REQUEST_START_NEW_CONVERSATION = 0x0501;
private Conversation mPendingConversation = null;
-
- @Override
- public void onConversationUpdate() {
- refreshUi();
- }
-
- private class Share {
- public List<Uri> uris = new ArrayList<>();
- public boolean image;
- public String account;
- public String contact;
- public String text;
- public String uuid;
- public boolean multiple = false;
- public String type;
- }
-
private Share share;
-
- private static final int REQUEST_START_NEW_CONVERSATION = 0x0501;
- private RecyclerView mListView;
private ConversationAdapter mAdapter;
private List<Conversation> mConversations = new ArrayList<>();
- private Toast mToast;
- private AtomicInteger attachmentCounter = new AtomicInteger(0);
-
- private UiInformableCallback<Message> attachFileCallback = new UiInformableCallback<Message>() {
-
- @Override
- public void inform(final String text) {
- runOnUiThread(() -> replaceToast(text));
- }
-
- @Override
- public void userInputRequried(PendingIntent pi, Message object) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void success(final Message message) {
- runOnUiThread(() -> {
- if (attachmentCounter.decrementAndGet() <= 0) {
- int resId;
- if (share.image && share.multiple) {
- resId = R.string.shared_images_with_x;
- } else if (share.image) {
- resId = R.string.shared_image_with_x;
- } else {
- resId = R.string.shared_file_with_x;
- }
- Conversation conversation = (Conversation) message.getConversation();
- replaceToast(getString(resId, conversation.getName()));
- if (mReturnToPrevious) {
- finish();
- } else {
- switchToConversation(conversation);
- }
- }
- });
- }
-
- @Override
- public void error(final int errorCode, Message object) {
- runOnUiThread(() -> {
- replaceToast(getString(errorCode));
- if (attachmentCounter.decrementAndGet() <= 0) {
- finish();
- }
- });
- }
- };
-
- protected void hideToast() {
- if (mToast != null) {
- mToast.cancel();
- }
- }
- protected void replaceToast(String msg) {
- hideToast();
- mToast = Toast.makeText(this, msg, Toast.LENGTH_LONG);
- mToast.show();
+ @Override
+ public void onConversationUpdate() {
+ refreshUi();
}
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
@@ -160,20 +75,16 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
super.onCreate(savedInstanceState);
boolean useBundledEmoji = getPreferences().getBoolean(USE_BUNDLED_EMOJIS, getResources().getBoolean(R.bool.use_bundled_emoji));
new EmojiService(this).init(useBundledEmoji);
-
setContentView(R.layout.activity_share_with);
-
setSupportActionBar(findViewById(R.id.toolbar));
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
}
-
setTitle(getString(R.string.title_activity_sharewith));
-
- mListView = findViewById(R.id.choose_conversation_list);
+ RecyclerView mListView = findViewById(R.id.choose_conversation_list);
mAdapter = new ConversationAdapter(this, this.mConversations);
- mListView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
+ mListView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
mListView.setAdapter(mAdapter);
mAdapter.setConversationClickListener((view, conversation) -> share(conversation));
this.share = new Share();
@@ -203,57 +114,28 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
if (intent == null) {
return;
}
- this.mReturnToPrevious = getBooleanPreference("return_to_previous", R.bool.return_to_previous);
final String type = intent.getType();
final String action = intent.getAction();
- Log.d(Config.LOGTAG, "action: " + action + ", type:" + type);
- share.uuid = intent.getStringExtra("uuid");
if (Intent.ACTION_SEND.equals(action)) {
- final String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
final String text = intent.getStringExtra(Intent.EXTRA_TEXT);
final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (type != null && uri != null && (text == null || !type.equals("text/plain"))) {
this.share.uris.clear();
this.share.uris.add(uri);
- this.share.image = type.startsWith("image/") || isImage(uri);
- this.share.type = type;
} else {
- if (subject != null) {
- this.share.text = format("[%s]%n%s", subject, text);
- } else {
- this.share.text = text;
- }
+ this.share.text = text;
}
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
- this.share.image = type != null && type.startsWith("image/");
- if (!this.share.image) {
- return;
- }
this.share.uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
}
if (xmppConnectionServiceBound) {
- if (share.uuid != null) {
- share();
- } else {
- xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0);
- }
- }
-
- }
-
- protected boolean isImage(Uri uri) {
- try {
- String guess = URLConnection.guessContentTypeFromName(uri.toString());
- return (guess != null && guess.startsWith("image/"));
- } catch (final StringIndexOutOfBoundsException ignored) {
- return false;
+ xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0);
}
}
@Override
void onBackendConnected() {
- if (xmppConnectionServiceBound && share != null
- && ((share.contact != null && share.account != null) || share.uuid != null)) {
+ if (xmppConnectionServiceBound && share != null && ((share.contact != null && share.account != null))) {
share();
return;
}
@@ -262,28 +144,19 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
private void share() {
final Conversation conversation;
- if (share.uuid != null) {
- conversation = xmppConnectionService.findConversationByUuid(share.uuid);
- if (conversation == null) {
- return;
- }
- } else {
- Account account;
- try {
- account = xmppConnectionService.findAccountByJid(Jid.of(share.account));
- } catch (final IllegalArgumentException e) {
- account = null;
- }
- if (account == null) {
- return;
- }
-
- try {
- conversation = xmppConnectionService
- .findOrCreateConversation(account, Jid.of(share.contact), false, true);
- } catch (final IllegalArgumentException e) {
- return;
- }
+ Account account;
+ try {
+ account = xmppConnectionService.findAccountByJid(Jid.of(share.account));
+ } catch (final IllegalArgumentException e) {
+ account = null;
+ }
+ if (account == null) {
+ return;
+ }
+ try {
+ conversation = xmppConnectionService.findOrCreateConversation(account, Jid.of(share.contact), false, true);
+ } catch (final IllegalArgumentException e) {
+ return;
}
share(conversation);
}
@@ -293,110 +166,18 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
mPendingConversation = conversation;
return;
}
- final Account account = conversation.getAccount();
- final XmppConnection connection = account.getXmppConnection();
- final long max = connection == null ? -1 : connection.getFeatures().getMaxHttpUploadSize();
- mListView.setEnabled(false);
- if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP && !hasPgp()) {
- if (share.uuid == null) {
- showInstallPgpDialog();
- } else {
- Toast.makeText(this, R.string.openkeychain_not_installed, Toast.LENGTH_SHORT).show();
- finish();
- }
- return;
+ Intent intent = new Intent(this, ConversationsActivity.class);
+ intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());
+ if (share.uris.size() > 0) {
+ intent.setAction(Intent.ACTION_SEND_MULTIPLE);
+ intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, share.uris);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ } else if (share.text != null) {
+ intent.setAction(ConversationsActivity.ACTION_VIEW_CONVERSATION);
+ intent.putExtra(ConversationsActivity.EXTRA_TEXT, share.text);
}
- if (share.uris.size() != 0) {
- PresenceSelector.OnPresenceSelected callback = () -> {
- attachmentCounter.set(share.uris.size());
- if (share.image) {
- Log.d(Config.LOGTAG, "ShareWithActivity share() image " + share.uris.size() + " uri(s) " + share.uris.toString());
- share.multiple = share.uris.size() > 1;
- replaceToast(getString(share.multiple ? R.string.preparing_images : R.string.preparing_image));
- for (Iterator<Uri> i = share.uris.iterator(); i.hasNext(); i.remove()) {
- final Uri uri = i.next();
- delegateUriPermissionsToService(uri);
- xmppConnectionService.attachImageToConversation(conversation, uri, attachFileCallback);
- }
- } else {
- Log.d(Config.LOGTAG, "ShareWithActivity share() file " + share.uris.size() + " uri(s) " + share.uris.toString());
- replaceToast(getString(R.string.preparing_file));
- final Uri uri = share.uris.get(0);
- delegateUriPermissionsToService(uri);
- xmppConnectionService.attachFileToConversation(conversation, uri, share.type, attachFileCallback);
- finish();
- }
- };
- if (account.httpUploadAvailable()
- && ((share.image && !neverCompressPictures())
- || conversation.getMode() == Conversation.MODE_MULTI
- || FileBackend.allFilesUnderSize(this, share.uris, max))
- && conversation.getNextEncryption() != Message.ENCRYPTION_OTR) {
- callback.onPresenceSelected();
- } else {
- selectPresence(conversation, callback);
- }
- } else {
- if (mReturnToPrevious && this.share.text != null && !this.share.text.isEmpty()) {
- final PresenceSelector.OnPresenceSelected callback = new PresenceSelector.OnPresenceSelected() {
-
- private void finishAndSend(Message message) {
- replaceToast(getString(R.string.shared_text_with_x, conversation.getName()));
- finish();
- }
-
- private UiCallback<Message> messageEncryptionCallback = new UiCallback<Message>() {
- @Override
- public void success(final Message message) {
- runOnUiThread(() -> finishAndSend(message));
- }
-
- @Override
- public void error(final int errorCode, Message object) {
- runOnUiThread(() -> {
- replaceToast(getString(errorCode));
- finish();
- });
- }
-
- @Override
- public void userInputRequried(PendingIntent pi, Message object) {
- finish();
- }
- };
-
- @Override
- public void onPresenceSelected() {
-
- final int encryption = conversation.getNextEncryption();
-
- Message message = new Message(conversation,share.text, encryption);
-
- Log.d(Config.LOGTAG,"on presence selected encrpytion="+encryption);
-
- if (encryption == Message.ENCRYPTION_PGP) {
- replaceToast(getString(R.string.encrypting_message));
- xmppConnectionService.getPgpEngine().encrypt(message,messageEncryptionCallback);
- return;
- }
-
- if (encryption == Message.ENCRYPTION_OTR) {
- message.setCounterpart(conversation.getNextCounterpart());
- }
- xmppConnectionService.sendMessage(message);
- finishAndSend(message);
- }
- };
- if (conversation.getNextEncryption() == Message.ENCRYPTION_OTR) {
- selectPresence(conversation, callback);
- } else {
- callback.onPresenceSelected();
- }
- } else {
- switchToConversation(conversation, this.share.text, true);
- }
- }
-
+ startActivity(intent);
+ finish();
}
public void refreshUiReal() {
@@ -404,12 +185,10 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
mAdapter.notifyDataSetChanged();
}
- @Override
- public void onBackPressed() {
- if (attachmentCounter.get() >= 1) {
- replaceToast(getString(R.string.sharing_files_please_wait));
- } else {
- super.onBackPressed();
- }
+ private class Share {
+ public String account;
+ public String contact;
+ public String text;
+ ArrayList<Uri> uris = new ArrayList<>();
}
} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java
index 01b432d65..e37ea6121 100644
--- a/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java
+++ b/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java
@@ -24,7 +24,7 @@ import de.pixart.messenger.R;
import de.pixart.messenger.entities.Account;
import de.pixart.messenger.ui.ManageAccountActivity;
import de.pixart.messenger.ui.XmppActivity;
-import de.pixart.messenger.ui.util.Color;
+import de.pixart.messenger.ui.util.StyledAttributes;
import de.pixart.messenger.utils.UIHelper;
public class AccountAdapter extends ArrayAdapter<Account> {
@@ -65,14 +65,14 @@ public class AccountAdapter extends ArrayAdapter<Account> {
statusView.setText(getContext().getString(account.getStatus().getReadableId()));
switch (account.getStatus()) {
case ONLINE:
- statusView.setTextColor(Color.get(activity, R.attr.TextColorOnline));
+ statusView.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline));
break;
case DISABLED:
case CONNECTING:
- statusView.setTextColor(Color.get(activity, android.R.attr.textColorSecondary));
+ statusView.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary));
break;
default:
- statusView.setTextColor(Color.get(activity, R.attr.TextColorError));
+ statusView.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorError));
break;
}
final SwitchCompat tglAccountState = view.findViewById(R.id.tgl_account_status);
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java
index 36cae0eb3..55dd6d65f 100644
--- a/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java
@@ -31,7 +31,7 @@ import de.pixart.messenger.entities.MucOptions;
import de.pixart.messenger.entities.Transferable;
import de.pixart.messenger.ui.ConversationFragment;
import de.pixart.messenger.ui.XmppActivity;
-import de.pixart.messenger.ui.util.Color;
+import de.pixart.messenger.ui.util.StyledAttributes;
import de.pixart.messenger.ui.widget.UnreadCountCustomView;
import de.pixart.messenger.utils.EmojiWrapper;
import de.pixart.messenger.utils.IrregularUnicodeDetector;
@@ -97,9 +97,9 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte
}
if (conversation == ConversationFragment.getConversation(activity)) {
- viewHolder.frame.setBackgroundColor(Color.get(activity, R.attr.color_background_tertiary));
+ viewHolder.frame.setBackgroundColor(StyledAttributes.getColor(activity, R.attr.color_background_tertiary));
} else {
- viewHolder.frame.setBackgroundColor(Color.get(activity, R.attr.color_background_secondary));
+ viewHolder.frame.setBackgroundColor(StyledAttributes.getColor(activity, R.attr.color_background_secondary));
}
Message message = conversation.getLatestMessage();
@@ -250,11 +250,11 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte
viewHolder.name.setTextColor(ContextCompat.getColor(activity, R.color.notavailable));
break;
default:
- viewHolder.name.setTextColor(Color.get(activity, R.attr.text_Color_Main));
+ viewHolder.name.setTextColor(StyledAttributes.getColor(activity, R.attr.text_Color_Main));
break;
}
} else {
- viewHolder.name.setTextColor(Color.get(activity, R.attr.text_Color_Main));
+ viewHolder.name.setTextColor(StyledAttributes.getColor(activity, R.attr.text_Color_Main));
}
if (activity.xmppConnectionService.indicateReceived()) {
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/ListItemAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/ListItemAdapter.java
index 64d432041..1f1b2877e 100644
--- a/src/main/java/de/pixart/messenger/ui/adapter/ListItemAdapter.java
+++ b/src/main/java/de/pixart/messenger/ui/adapter/ListItemAdapter.java
@@ -27,7 +27,7 @@ import de.pixart.messenger.databinding.ContactBinding;
import de.pixart.messenger.entities.ListItem;
import de.pixart.messenger.ui.SettingsActivity;
import de.pixart.messenger.ui.XmppActivity;
-import de.pixart.messenger.ui.util.Color;
+import de.pixart.messenger.ui.util.StyledAttributes;
import de.pixart.messenger.utils.IrregularUnicodeDetector;
import de.pixart.messenger.utils.UIHelper;
import rocks.xmpp.addr.Jid;
@@ -105,16 +105,16 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
}
}
if (offline) {
- viewHolder.name.setTextColor(Color.get(activity, R.attr.text_Color_Main));
+ viewHolder.name.setTextColor(StyledAttributes.get(activity, R.attr.text_Color_Main));
viewHolder.name.setAlpha(INACTIVE_ALPHA);
viewHolder.jid.setAlpha(INACTIVE_ALPHA);
viewHolder.avatar.setAlpha(INACTIVE_ALPHA);
viewHolder.tags.setAlpha(INACTIVE_ALPHA);
} else {
if (ShowPresenceColoredNames()) {
- viewHolder.name.setTextColor(color != 0 ? color : Color.get(activity, R.attr.text_Color_Main));
+ viewHolder.name.setTextColor(color != 0 ? color : StyledAttributes.get(activity, R.attr.text_Color_Main));
} else {
- viewHolder.name.setTextColor(Color.get(activity, R.attr.text_Color_Main));
+ viewHolder.name.setTextColor(StyledAttributes.get(activity, R.attr.text_Color_Main));
}
viewHolder.name.setAlpha(ACTIVE_ALPHA);
viewHolder.jid.setAlpha(ACTIVE_ALPHA);
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java
new file mode 100644
index 000000000..bbcaa5dc6
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/adapter/MediaPreviewAdapter.java
@@ -0,0 +1,211 @@
+package de.pixart.messenger.ui.adapter;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.databinding.DataBindingUtil;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.support.annotation.AttrRes;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import de.pixart.messenger.R;
+import de.pixart.messenger.databinding.MediaPreviewBinding;
+import de.pixart.messenger.ui.ConversationFragment;
+import de.pixart.messenger.ui.XmppActivity;
+import de.pixart.messenger.ui.util.Attachment;
+import de.pixart.messenger.ui.util.StyledAttributes;
+
+public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapter.MediaPreviewViewHolder> {
+
+ private final List<Attachment> mediaPreviews = new ArrayList<>();
+
+ private final ConversationFragment conversationFragment;
+
+ public MediaPreviewAdapter(ConversationFragment fragment) {
+ this.conversationFragment = fragment;
+ }
+
+ private static boolean cancelPotentialWork(Attachment attachment, ImageView imageView) {
+ final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
+
+ if (bitmapWorkerTask != null) {
+ final Attachment oldAttachment = bitmapWorkerTask.attachment;
+ if (oldAttachment == null || !oldAttachment.equals(attachment)) {
+ bitmapWorkerTask.cancel(true);
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
+ if (imageView != null) {
+ final Drawable drawable = imageView.getDrawable();
+ if (drawable instanceof AsyncDrawable) {
+ final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+ return asyncDrawable.getBitmapWorkerTask();
+ }
+ }
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public MediaPreviewViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+ MediaPreviewBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.media_preview, parent, false);
+ return new MediaPreviewViewHolder(binding);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull MediaPreviewViewHolder holder, int position) {
+ final Context context = conversationFragment.getActivity();
+ final Attachment attachment = mediaPreviews.get(position);
+ if (attachment.renderThumbnail()) {
+ holder.binding.mediaPreview.setImageAlpha(255);
+ loadPreview(attachment, holder.binding.mediaPreview);
+ } else {
+ cancelPotentialWork(attachment, holder.binding.mediaPreview);
+ holder.binding.mediaPreview.setBackgroundColor(StyledAttributes.getColor(context, R.attr.color_background_tertiary));
+ holder.binding.mediaPreview.setImageAlpha(Math.round(StyledAttributes.getFloat(context, R.attr.icon_alpha) * 255));
+ final @AttrRes int attr;
+ if (attachment.getType() == Attachment.Type.LOCATION) {
+ attr = R.attr.media_preview_location;
+ } else if (attachment.getType() == Attachment.Type.RECORDING) {
+ attr = R.attr.media_preview_recording;
+ } else {
+ final String mime = attachment.getMime();
+ if (mime == null) {
+ attr = R.attr.media_preview_file;
+ } else if (mime.startsWith("audio/")) {
+ attr = R.attr.media_preview_audio;
+ } else if (mime.equals("text/calendar") || (mime.equals("text/x-vcalendar"))) {
+ attr = R.attr.media_preview_calendar;
+ } else if (mime.equals("text/x-vcard")) {
+ attr = R.attr.media_preview_contact;
+ } else if (mime.equals("application/vnd.android.package-archive")) {
+ attr = R.attr.media_preview_app;
+ } else if (mime.equals("application/zip") || mime.equals("application/rar")) {
+ attr = R.attr.media_preview_archive;
+ } else {
+ attr = R.attr.media_preview_file;
+ }
+ }
+ holder.binding.mediaPreview.setImageDrawable(StyledAttributes.getDrawable(context, attr));
+ }
+ holder.binding.deleteButton.setOnClickListener(v -> {
+ int pos = mediaPreviews.indexOf(attachment);
+ mediaPreviews.remove(pos);
+ notifyItemRemoved(pos);
+ conversationFragment.toggleInputMethod();
+ });
+ }
+
+ public void addMediaPreviews(List<Attachment> attachments) {
+ this.mediaPreviews.addAll(attachments);
+ notifyDataSetChanged();
+ }
+
+ private void loadPreview(Attachment attachment, ImageView imageView) {
+ if (cancelPotentialWork(attachment, imageView)) {
+ XmppActivity activity = (XmppActivity) conversationFragment.getActivity();
+ final Bitmap bm = activity.xmppConnectionService.getFileBackend().getPreviewForUri(attachment, Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)), true);
+ if (bm != null) {
+ cancelPotentialWork(attachment, imageView);
+ imageView.setImageBitmap(bm);
+ imageView.setBackgroundColor(0x00000000);
+ } else {
+ imageView.setBackgroundColor(0xff333333);
+ imageView.setImageDrawable(null);
+ final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
+ final AsyncDrawable asyncDrawable = new AsyncDrawable(conversationFragment.getActivity().getResources(), null, task);
+ imageView.setImageDrawable(asyncDrawable);
+ try {
+ task.execute(attachment);
+ } catch (final RejectedExecutionException ignored) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return mediaPreviews.size();
+ }
+
+ public boolean hasAttachments() {
+ return mediaPreviews.size() > 0;
+ }
+
+ public List<Attachment> getAttachments() {
+ return mediaPreviews;
+ }
+
+ static class AsyncDrawable extends BitmapDrawable {
+ private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
+
+ AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
+ super(res, bitmap);
+ bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
+ }
+
+ BitmapWorkerTask getBitmapWorkerTask() {
+ return bitmapWorkerTaskReference.get();
+ }
+ }
+
+ class MediaPreviewViewHolder extends RecyclerView.ViewHolder {
+
+ private final MediaPreviewBinding binding;
+
+ MediaPreviewViewHolder(MediaPreviewBinding binding) {
+ super(binding.getRoot());
+ this.binding = binding;
+ }
+ }
+
+ class BitmapWorkerTask extends AsyncTask<Attachment, Void, Bitmap> {
+ private final WeakReference<ImageView> imageViewReference;
+ private Attachment attachment = null;
+
+ BitmapWorkerTask(ImageView imageView) {
+ imageViewReference = new WeakReference<>(imageView);
+ }
+
+ @Override
+ protected Bitmap doInBackground(Attachment... params) {
+ Activity activity = conversationFragment.getActivity();
+ if (activity instanceof XmppActivity) {
+ final XmppActivity xmppActivity = (XmppActivity) activity;
+ this.attachment = params[0];
+ return xmppActivity.xmppConnectionService.getFileBackend().getPreviewForUri(this.attachment, Math.round(xmppActivity.getResources().getDimension(R.dimen.media_preview_size)), false);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ if (bitmap != null && !isCancelled()) {
+ final ImageView imageView = imageViewReference.get();
+ if (imageView != null) {
+ imageView.setImageBitmap(bitmap);
+ imageView.setBackgroundColor(0x00000000);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/forms/FormFieldWrapper.java b/src/main/java/de/pixart/messenger/ui/forms/FormFieldWrapper.java
index adcc11809..0dfd86327 100644
--- a/src/main/java/de/pixart/messenger/ui/forms/FormFieldWrapper.java
+++ b/src/main/java/de/pixart/messenger/ui/forms/FormFieldWrapper.java
@@ -1,7 +1,6 @@
package de.pixart.messenger.ui.forms;
import android.content.Context;
-import android.support.v4.content.ContextCompat;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
@@ -11,6 +10,7 @@ import android.view.View;
import java.util.List;
import de.pixart.messenger.R;
+import de.pixart.messenger.ui.util.StyledAttributes;
import de.pixart.messenger.xmpp.forms.Field;
public abstract class FormFieldWrapper {
@@ -18,9 +18,9 @@ public abstract class FormFieldWrapper {
protected final Context context;
protected final Field field;
protected final View view;
- protected OnFormFieldValuesEdited onFormFieldValuesEditedListener;
+ OnFormFieldValuesEdited onFormFieldValuesEditedListener;
- protected FormFieldWrapper(Context context, Field field) {
+ FormFieldWrapper(Context context, Field field) {
this.context = context;
this.field = field;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -58,7 +58,7 @@ public abstract class FormFieldWrapper {
int start = label.length();
int end = label.length() + 2;
spannableString.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), start, end, 0);
- spannableString.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, R.color.accent)), start, end, 0);
+ spannableString.setSpan(new ForegroundColorSpan(StyledAttributes.getColor(context, R.color.accent)), start, end, 0);
}
return spannableString;
}
diff --git a/src/main/java/de/pixart/messenger/ui/util/Attachment.java b/src/main/java/de/pixart/messenger/ui/util/Attachment.java
new file mode 100644
index 000000000..8c1d0c75e
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/util/Attachment.java
@@ -0,0 +1,120 @@
+/*
+ * 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 de.pixart.messenger.ui.util;
+
+import android.content.ClipData;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import de.pixart.messenger.Config;
+import de.pixart.messenger.utils.MimeUtils;
+
+public class Attachment {
+ private final Uri uri;
+ private final Type type;
+ private final UUID uuid;
+ private final String mime;
+ private Attachment(Uri uri, Type type, String mime) {
+ this.uri = uri;
+ this.type = type;
+ this.mime = mime;
+ this.uuid = UUID.randomUUID();
+ }
+
+ public static List<Attachment> of(final Context context, Uri uri, Type type) {
+ final String mime = type == Type.LOCATION ? null : MimeUtils.guessMimeTypeFromUri(context, uri);
+ return Collections.singletonList(new Attachment(uri, type, mime));
+ }
+
+ public static List<Attachment> of(final Context context, List<Uri> uris) {
+ List<Attachment> attachments = new ArrayList<>();
+ for (Uri uri : uris) {
+ final String mime = MimeUtils.guessMimeTypeFromUri(context, uri);
+ attachments.add(new Attachment(uri, mime != null && mime.startsWith("image/") ? Type.IMAGE : Type.FILE, mime));
+ }
+ return attachments;
+ }
+
+ public static List<Attachment> extractAttachments(final Context context, final Intent intent, Type type) {
+ List<Attachment> uris = new ArrayList<>();
+ if (intent == null) {
+ return uris;
+ }
+ final String contentType = intent.getType();
+ final Uri data = intent.getData();
+ if (data == null) {
+ final ClipData clipData = intent.getClipData();
+ if (clipData != null) {
+ for (int i = 0; i < clipData.getItemCount(); ++i) {
+ final Uri uri = clipData.getItemAt(i).getUri();
+ Log.d(Config.LOGTAG, "uri=" + uri + " contentType=" + contentType);
+ final String mime = contentType != null ? contentType : MimeUtils.guessMimeTypeFromUri(context, uri);
+ Log.d(Config.LOGTAG, "mime=" + mime);
+ uris.add(new Attachment(uri, type, mime));
+ }
+ }
+ } else {
+ final String mime = contentType != null ? contentType : MimeUtils.guessMimeTypeFromUri(context, data);
+ uris.add(new Attachment(data, type, mime));
+ }
+ return uris;
+ }
+
+ public String getMime() {
+ return mime;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public boolean renderThumbnail() {
+ return type == Type.IMAGE || (type == Type.FILE && mime != null && (mime.startsWith("video/") || mime.startsWith("image/")));
+ }
+
+ public Uri getUri() {
+ return uri;
+ }
+
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ public enum Type {
+ FILE, IMAGE, LOCATION, RECORDING
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/util/AttachmentTool.java b/src/main/java/de/pixart/messenger/ui/util/AttachmentTool.java
deleted file mode 100644
index c56f27ebf..000000000
--- a/src/main/java/de/pixart/messenger/ui/util/AttachmentTool.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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 de.pixart.messenger.ui.util;
-
-import android.annotation.SuppressLint;
-import android.content.ClipData;
-import android.content.Intent;
-import android.net.Uri;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class AttachmentTool {
- @SuppressLint("NewApi")
- public static List<Uri> extractUriFromIntent(final Intent intent) {
- List<Uri> uris = new ArrayList<>();
- if (intent == null) {
- return uris;
- }
- final Uri uri = intent.getData();
- if (uri == null) {
- final ClipData clipData = intent.getClipData();
- if (clipData != null) {
- for (int i = 0; i < clipData.getItemCount(); ++i) {
- uris.add(clipData.getItemAt(i).getUri());
- }
- }
- } else {
- uris.add(uri);
- }
- return uris;
- }
-} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/util/Drawable.java b/src/main/java/de/pixart/messenger/ui/util/Drawable.java
deleted file mode 100644
index 5e0c770d4..000000000
--- a/src/main/java/de/pixart/messenger/ui/util/Drawable.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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 de.pixart.messenger.ui.util;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.support.annotation.AttrRes;
-
-public class Drawable {
- public static android.graphics.drawable.Drawable get(Context context, @AttrRes int id) {
- TypedArray typedArray = context.obtainStyledAttributes(new int[]{id});
- android.graphics.drawable.Drawable drawable = typedArray.getDrawable(0);
- typedArray.recycle();
- return drawable;
- }
-} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/ui/util/Color.java b/src/main/java/de/pixart/messenger/ui/util/StyledAttributes.java
index 58ce6a465..cd4ad3e49 100644
--- a/src/main/java/de/pixart/messenger/ui/util/Color.java
+++ b/src/main/java/de/pixart/messenger/ui/util/StyledAttributes.java
@@ -35,14 +35,26 @@ import android.content.res.TypedArray;
import android.support.annotation.AttrRes;
import android.support.annotation.ColorInt;
-public class Color {
+public class StyledAttributes {
+ public static android.graphics.drawable.Drawable getDrawable(Context context, @AttrRes int id) {
+ TypedArray typedArray = context.obtainStyledAttributes(new int[]{id});
+ android.graphics.drawable.Drawable drawable = typedArray.getDrawable(0);
+ typedArray.recycle();
+ return drawable;
+ }
+
+ public static float getFloat(Context context, @AttrRes int id) {
+ TypedArray typedArray = context.obtainStyledAttributes(new int[]{id});
+ float value = typedArray.getFloat(0, 0f);
+ typedArray.recycle();
+ return value;
+ }
public static @ColorInt
- int get(Context context, @AttrRes int attr) {
+ int getColor(Context context, @AttrRes int attr) {
TypedArray typedArray = context.obtainStyledAttributes(new int[]{attr});
int color = typedArray.getColor(0, 0);
typedArray.recycle();
return color;
}
-
} \ No newline at end of file