mirror of
https://github.com/mastodon/mastodon-android.git
synced 2025-02-09 00:18:48 +01:00
System share support
This commit is contained in:
parent
fd3613109d
commit
0661ce265a
@ -33,6 +33,18 @@
|
|||||||
<data android:scheme="mastodon-android-auth" android:host="callback"/>
|
<data android:scheme="mastodon-android-auth" android:host="callback"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".ExternalShareActivity" android:exported="true" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
<data android:mimeType="*/*"/>
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
<data android:mimeType="*/*"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<service android:name=".AudioPlayerService" android:foregroundServiceType="mediaPlayback"/>
|
<service android:name=".AudioPlayerService" android:foregroundServiceType="mediaPlayback"/>
|
||||||
|
|
||||||
|
@ -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<AccountSession> 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<Uri> 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<clipData.getItemCount();i++){
|
||||||
|
ClipData.Item item=clipData.getItemAt(i);
|
||||||
|
mediaUris.add(item.getUri());
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
mediaUris=null;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Toast.makeText(this, "Unexpected intent action: "+intent.getAction(), Toast.LENGTH_SHORT).show();
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bundle args=new Bundle();
|
||||||
|
args.putString("account", accountID);
|
||||||
|
if(!TextUtils.isEmpty(text))
|
||||||
|
args.putString("prefilledText", text);
|
||||||
|
if(mediaUris!=null && !mediaUris.isEmpty())
|
||||||
|
args.putParcelableArrayList("mediaAttachments", toArrayList(mediaUris));
|
||||||
|
Fragment fragment=new ComposeFragment();
|
||||||
|
fragment.setArguments(args);
|
||||||
|
showFragmentClearingBackStack(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> ArrayList<T> toArrayList(List<T> l){
|
||||||
|
if(l instanceof ArrayList)
|
||||||
|
return (ArrayList<T>) l;
|
||||||
|
if(l==null)
|
||||||
|
return null;
|
||||||
|
return new ArrayList<>(l);
|
||||||
|
}
|
||||||
|
}
|
@ -125,8 +125,9 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
|||||||
.setStyle(new Notification.BigTextStyle().bigText(pn.body))
|
.setStyle(new Notification.BigTextStyle().bigText(pn.body))
|
||||||
.setSmallIcon(R.drawable.ic_ntf_logo)
|
.setSmallIcon(R.drawable.ic_ntf_logo)
|
||||||
.setContentIntent(PendingIntent.getActivity(context, accountID.hashCode() & 0xFFFF, contentIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT))
|
.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)
|
.setShowWhen(true)
|
||||||
|
.setCategory(Notification.CATEGORY_SOCIAL)
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setColor(context.getColor(R.color.primary_700));
|
.setColor(context.getColor(R.color.primary_700));
|
||||||
if(avatar!=null){
|
if(avatar!=null){
|
||||||
|
@ -7,6 +7,7 @@ import android.content.ClipData;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.database.Cursor;
|
||||||
import android.graphics.Outline;
|
import android.graphics.Outline;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@ -17,6 +18,7 @@ import android.net.Uri;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputFilter;
|
import android.text.InputFilter;
|
||||||
import android.text.Layout;
|
import android.text.Layout;
|
||||||
@ -51,6 +53,7 @@ import com.twitter.twittertext.Regex;
|
|||||||
import com.twitter.twittertext.TwitterTextEmojiRegex;
|
import com.twitter.twittertext.TwitterTextEmojiRegex;
|
||||||
|
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
|
import org.joinmastodon.android.MastodonApp;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.ProgressListener;
|
import org.joinmastodon.android.api.ProgressListener;
|
||||||
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
||||||
@ -88,6 +91,7 @@ import org.parceler.Parcels;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -175,6 +179,7 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
|||||||
private FrameLayout mainEditTextWrap;
|
private FrameLayout mainEditTextWrap;
|
||||||
private ComposeAutocompleteViewController autocompleteViewController;
|
private ComposeAutocompleteViewController autocompleteViewController;
|
||||||
private Instance instance;
|
private Instance instance;
|
||||||
|
private boolean attachmentsErrorShowing;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState){
|
public void onCreate(Bundle savedInstanceState){
|
||||||
@ -452,6 +457,12 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
|||||||
mainEditText.setSelection(mainEditText.length());
|
mainEditText.setSelection(mainEditText.length());
|
||||||
initialText=prefilledText;
|
initialText=prefilledText;
|
||||||
}
|
}
|
||||||
|
ArrayList<Uri> 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){
|
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;
|
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);
|
pollBtn.setEnabled(false);
|
||||||
DraftMediaAttachment draft=new DraftMediaAttachment();
|
DraftMediaAttachment draft=new DraftMediaAttachment();
|
||||||
draft.uri=uri;
|
draft.uri=uri;
|
||||||
@ -706,6 +738,14 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
|||||||
mediaBtn.setEnabled(false);
|
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){
|
private View createMediaAttachmentView(DraftMediaAttachment draft){
|
||||||
View thumb=getActivity().getLayoutInflater().inflate(R.layout.compose_media_thumb, attachmentsView, false);
|
View thumb=getActivity().getLayoutInflater().inflate(R.layout.compose_media_thumb, attachmentsView, false);
|
||||||
ImageView img=thumb.findViewById(R.id.thumb);
|
ImageView img=thumb.findViewById(R.id.thumb);
|
||||||
@ -812,10 +852,9 @@ public class ComposeFragment extends ToolbarFragment implements OnBackPressedLis
|
|||||||
DraftMediaAttachment att=(DraftMediaAttachment) v.getTag();
|
DraftMediaAttachment att=(DraftMediaAttachment) v.getTag();
|
||||||
if(att==uploadingAttachment){
|
if(att==uploadingAttachment){
|
||||||
att.uploadRequest.cancel();
|
att.uploadRequest.cancel();
|
||||||
|
uploadingAttachment=null;
|
||||||
if(!queuedAttachments.isEmpty())
|
if(!queuedAttachments.isEmpty())
|
||||||
uploadMediaAttachment(queuedAttachments.remove(0));
|
uploadMediaAttachment(queuedAttachments.remove(0));
|
||||||
else
|
|
||||||
uploadingAttachment=null;
|
|
||||||
}else{
|
}else{
|
||||||
attachments.remove(att);
|
attachments.remove(att);
|
||||||
queuedAttachments.remove(att);
|
queuedAttachments.remove(att);
|
||||||
|
@ -228,4 +228,12 @@
|
|||||||
<string name="notification_type_reblog">Boosts</string>
|
<string name="notification_type_reblog">Boosts</string>
|
||||||
<string name="notification_type_mention">Mentions</string>
|
<string name="notification_type_mention">Mentions</string>
|
||||||
<string name="notification_type_poll">Polls</string>
|
<string name="notification_type_poll">Polls</string>
|
||||||
|
<string name="choose_account">Choose account</string>
|
||||||
|
<string name="err_not_logged_in">Please log into Mastodon first</string>
|
||||||
|
<plurals name="cant_add_more_than_x_attachments">
|
||||||
|
<item quantity="one">You can\'t add more than %d media attachment</item>
|
||||||
|
<item quantity="other">You can\'t add more than %d media attachments</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="media_attachment_unsupported_type">File %s is of an unsupported type</string>
|
||||||
|
<string name="media_attachment_too_big">File %1$s exceeds the size limit of %2$s MB</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user