diff --git a/mastodon/src/main/AndroidManifest.xml b/mastodon/src/main/AndroidManifest.xml
index 15bfddb5d..bb9b716d4 100644
--- a/mastodon/src/main/AndroidManifest.xml
+++ b/mastodon/src/main/AndroidManifest.xml
@@ -33,6 +33,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mastodon/src/main/java/org/joinmastodon/android/ExternalShareActivity.java b/mastodon/src/main/java/org/joinmastodon/android/ExternalShareActivity.java
new file mode 100644
index 000000000..d2e0f27bc
--- /dev/null
+++ b/mastodon/src/main/java/org/joinmastodon/android/ExternalShareActivity.java
@@ -0,0 +1,94 @@
+package org.joinmastodon.android;
+
+import android.app.Fragment;
+import android.content.ClipData;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.drawable.ColorDrawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+import org.joinmastodon.android.api.session.AccountSession;
+import org.joinmastodon.android.api.session.AccountSessionManager;
+import org.joinmastodon.android.fragments.ComposeFragment;
+import org.joinmastodon.android.ui.M3AlertDialogBuilder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import androidx.annotation.Nullable;
+import me.grishka.appkit.FragmentStackActivity;
+
+public class ExternalShareActivity extends FragmentStackActivity{
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState){
+ super.onCreate(savedInstanceState);
+ if(savedInstanceState==null){
+ List sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
+ if(sessions.isEmpty()){
+ Toast.makeText(this, R.string.err_not_logged_in, Toast.LENGTH_SHORT).show();
+ finish();
+ }else if(sessions.size()==1){
+ openComposeFragment(sessions.get(0).getID());
+ }else{
+ getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000));
+ new M3AlertDialogBuilder(this)
+ .setItems(sessions.stream().map(as->"@"+as.self.username+"@"+as.domain).toArray(String[]::new), (dialog, which)->{
+ openComposeFragment(sessions.get(which).getID());
+ })
+ .setTitle(R.string.choose_account)
+ .setOnCancelListener(dialog -> finish())
+ .show();
+ }
+ }
+ }
+
+ private void openComposeFragment(String accountID){
+ getWindow().setBackgroundDrawable(null);
+
+ Intent intent=getIntent();
+ String text=intent.getStringExtra(Intent.EXTRA_TEXT);
+ List mediaUris;
+ if(Intent.ACTION_SEND.equals(intent.getAction())){
+ Uri singleUri=intent.getParcelableExtra(Intent.EXTRA_STREAM);
+ mediaUris=singleUri!=null ? Collections.singletonList(singleUri) : null;
+ }else if(Intent.ACTION_SEND_MULTIPLE.equals(intent.getAction())){
+ ClipData clipData=intent.getClipData();
+ if(clipData!=null){
+ mediaUris=new ArrayList<>(clipData.getItemCount());
+ for(int i=0;i ArrayList toArrayList(List l){
+ if(l instanceof ArrayList)
+ return (ArrayList) l;
+ if(l==null)
+ return null;
+ return new ArrayList<>(l);
+ }
+}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java
index edf4e1194..d802892c8 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java
@@ -125,8 +125,9 @@ public class PushNotificationReceiver extends BroadcastReceiver{
.setStyle(new Notification.BigTextStyle().bigText(pn.body))
.setSmallIcon(R.drawable.ic_ntf_logo)
.setContentIntent(PendingIntent.getActivity(context, accountID.hashCode() & 0xFFFF, contentIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT))
- .setWhen(System.currentTimeMillis())
+ .setWhen(notification==null ? System.currentTimeMillis() : notification.createdAt.toEpochMilli())
.setShowWhen(true)
+ .setCategory(Notification.CATEGORY_SOCIAL)
.setAutoCancel(true)
.setColor(context.getColor(R.color.primary_700));
if(avatar!=null){
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
index 9eef2ae4b..b37565478 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
@@ -7,6 +7,7 @@ import android.content.ClipData;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
+import android.database.Cursor;
import android.graphics.Outline;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
@@ -17,6 +18,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
+import android.provider.OpenableColumns;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Layout;
@@ -51,6 +53,7 @@ import com.twitter.twittertext.Regex;
import com.twitter.twittertext.TwitterTextEmojiRegex;
import org.joinmastodon.android.E;
+import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.ProgressListener;
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
@@ -88,6 +91,7 @@ import org.parceler.Parcels;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -175,6 +179,7 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
private FrameLayout mainEditTextWrap;
private ComposeAutocompleteViewController autocompleteViewController;
private Instance instance;
+ private boolean attachmentsErrorShowing;
@Override
public void onCreate(Bundle savedInstanceState){
@@ -452,6 +457,12 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
mainEditText.setSelection(mainEditText.length());
initialText=prefilledText;
}
+ ArrayList mediaUris=getArguments().getParcelableArrayList("mediaAttachments");
+ if(mediaUris!=null && !mediaUris.isEmpty()){
+ for(Uri uri:mediaUris){
+ addMediaAttachment(uri);
+ }
+ }
}
}
@@ -684,8 +695,29 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
}
private void addMediaAttachment(Uri uri){
- if(getMediaAttachmentsCount()==MAX_ATTACHMENTS)
+ if(getMediaAttachmentsCount()==MAX_ATTACHMENTS){
+ showMediaAttachmentError(getResources().getQuantityString(R.plurals.cant_add_more_than_x_attachments, MAX_ATTACHMENTS, MAX_ATTACHMENTS));
return;
+ }
+ String type=getActivity().getContentResolver().getType(uri);
+ if(instance.configuration!=null && instance.configuration.mediaAttachments!=null){
+ if(instance.configuration.mediaAttachments.supportedMimeTypes!=null && !instance.configuration.mediaAttachments.supportedMimeTypes.contains(type)){
+ showMediaAttachmentError(getString(R.string.media_attachment_unsupported_type, UiUtils.getFileName(uri)));
+ return;
+ }
+ int sizeLimit=type.startsWith("image/") ? instance.configuration.mediaAttachments.imageSizeLimit : instance.configuration.mediaAttachments.videoSizeLimit;
+ int size;
+ try(Cursor cursor=MastodonApp.context.getContentResolver().query(uri, new String[]{OpenableColumns.SIZE}, null, null, null)){
+ cursor.moveToFirst();
+ size=cursor.getInt(0);
+ }
+ if(size>sizeLimit){
+ float mb=sizeLimit/(float)(1024*1024);
+ String sMb=String.format(Locale.getDefault(), mb%1f==0f ? "%f" : "%.2f", mb);
+ showMediaAttachmentError(getString(R.string.media_attachment_too_big, UiUtils.getFileName(uri), sMb));
+ return;
+ }
+ }
pollBtn.setEnabled(false);
DraftMediaAttachment draft=new DraftMediaAttachment();
draft.uri=uri;
@@ -706,6 +738,14 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
mediaBtn.setEnabled(false);
}
+ private void showMediaAttachmentError(String text){
+ if(!attachmentsErrorShowing){
+ Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
+ attachmentsErrorShowing=true;
+ contentView.postDelayed(()->attachmentsErrorShowing=false, 2000);
+ }
+ }
+
private View createMediaAttachmentView(DraftMediaAttachment draft){
View thumb=getActivity().getLayoutInflater().inflate(R.layout.compose_media_thumb, attachmentsView, false);
ImageView img=thumb.findViewById(R.id.thumb);
@@ -812,10 +852,9 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
DraftMediaAttachment att=(DraftMediaAttachment) v.getTag();
if(att==uploadingAttachment){
att.uploadRequest.cancel();
+ uploadingAttachment=null;
if(!queuedAttachments.isEmpty())
uploadMediaAttachment(queuedAttachments.remove(0));
- else
- uploadingAttachment=null;
}else{
attachments.remove(att);
queuedAttachments.remove(att);
diff --git a/mastodon/src/main/res/values/strings.xml b/mastodon/src/main/res/values/strings.xml
index 60c5eb3cd..64eb3fb7e 100644
--- a/mastodon/src/main/res/values/strings.xml
+++ b/mastodon/src/main/res/values/strings.xml
@@ -228,4 +228,12 @@
Boosts
Mentions
Polls
+ Choose account
+ Please log into Mastodon first
+
+ - You can\'t add more than %d media attachment
+ - You can\'t add more than %d media attachments
+
+ File %s is of an unsupported type
+ File %1$s exceeds the size limit of %2$s MB
\ No newline at end of file