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