Merge remote-tracking branch 'upstream/master' into upstream-release

This commit is contained in:
sk 2023-01-17 02:23:25 +01:00
commit a3b6decb72
5 changed files with 77 additions and 17 deletions

View File

@ -3,10 +3,17 @@ Mastodon for Android
[![Crowdin](https://badges.crowdin.net/mastodon-for-android/localized.svg)](https://crowdin.com/project/mastodon-for-android) [![Crowdin](https://badges.crowdin.net/mastodon-for-android/localized.svg)](https://crowdin.com/project/mastodon-for-android)
<a href="https://play.google.com/store/apps/details?id=org.joinmastodon.android"><img src="img/google-play-badge.png" height="50"></a>
This is the repository for the official Android app for Mastodon. This is the repository for the official Android app for Mastodon.
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/org.joinmastodon.android/)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png"
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=org.joinmastodon.android)
Or get the APK from the [The Releases Section](https://github.com/mastodon/mastodon-android/releases/latest).
## Contributing ## Contributing
Our goal is delivering a polished, professionally designed and user-friendly app. We proceed according to wireframes provided by a professional UX designer that works with Mastodon gGmbH. This means that any outside contributions that change the app visually must first be coordinated with the UX designer. *This can take time.* Furthermore, we work off of an internal roadmap and aim for feature-parity and consistency with our iOS app. The iOS app is designated as the "primary" between the two, therefore, if you want to request features, please do so in the [Mastodon for iOS](https://github.com/mastodon/mastodon-ios) repository, as you are requesting a feature to be both in iOS and Android (exceptions being system integrations specific to Android). On the other hand, any contributions that improve existing functionality, performance, or accessibility should not have any roadblocks to being merged. Our goal is delivering a polished, professionally designed and user-friendly app. We proceed according to wireframes provided by a professional UX designer that works with Mastodon gGmbH. This means that any outside contributions that change the app visually must first be coordinated with the UX designer. *This can take time.* Furthermore, we work off of an internal roadmap and aim for feature-parity and consistency with our iOS app. The iOS app is designated as the "primary" between the two, therefore, if you want to request features, please do so in the [Mastodon for iOS](https://github.com/mastodon/mastodon-ios) repository, as you are requesting a feature to be both in iOS and Android (exceptions being system integrations specific to Android). On the other hand, any contributions that improve existing functionality, performance, or accessibility should not have any roadblocks to being merged.

View File

@ -162,6 +162,8 @@ public class PushSubscriptionManager{
@Override @Override
public void onSuccess(PushSubscription result){ public void onSuccess(PushSubscription result){
MastodonAPIController.runInBackground(()->{ MastodonAPIController.runInBackground(()->{
result.serverKey=result.serverKey.replace('/','_');
result.serverKey=result.serverKey.replace('+','-');
serverKey=deserializeRawPublicKey(Base64.decode(result.serverKey, Base64.URL_SAFE)); serverKey=deserializeRawPublicKey(Base64.decode(result.serverKey, Base64.URL_SAFE));
AccountSession session=AccountSessionManager.getInstance().tryGetAccount(accountID); AccountSession session=AccountSessionManager.getInstance().tryGetAccount(accountID);

View File

@ -8,9 +8,11 @@ import org.joinmastodon.android.model.Status;
import java.util.List; import java.util.List;
public class GetTrendingStatuses extends MastodonAPIRequest<List<Status>>{ public class GetTrendingStatuses extends MastodonAPIRequest<List<Status>>{
public GetTrendingStatuses(int limit){ public GetTrendingStatuses(int offset, int limit){
super(HttpMethod.GET, "/trends/statuses", new TypeToken<>(){}); super(HttpMethod.GET, "/trends/statuses", new TypeToken<>(){});
if(limit>0) if(limit>0)
addQueryParameter("limit", ""+limit); addQueryParameter("limit", ""+limit);
if(offset>0)
addQueryParameter("offset", ""+offset);
} }
} }

View File

@ -1,5 +1,7 @@
package org.joinmastodon.android.fragments; package org.joinmastodon.android.fragments;
import static android.os.ext.SdkExtensions.getExtensionVersion;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
@ -20,6 +22,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.MediaStore;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
import android.text.Editable; import android.text.Editable;
import android.text.InputFilter; import android.text.InputFilter;
@ -410,6 +413,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
mainEditText.setSelectionListener(this); mainEditText.setSelectionListener(this);
mainEditText.addTextChangedListener(new TextWatcher(){ mainEditText.addTextChangedListener(new TextWatcher(){
private int lastChangeStart, lastChangeCount;
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after){ public void beforeTextChanged(CharSequence s, int start, int count, int after){
@ -419,6 +424,16 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
public void onTextChanged(CharSequence s, int start, int before, int count){ public void onTextChanged(CharSequence s, int start, int before, int count){
if(s.length()==0) if(s.length()==0)
return; return;
lastChangeStart=start;
lastChangeCount=count;
}
@Override
public void afterTextChanged(Editable s){
if(s.length()==0)
return;
int start=lastChangeStart;
int count=lastChangeCount;
// offset one char back to catch an already typed '@' or '#' or ':' // offset one char back to catch an already typed '@' or '#' or ':'
int realStart=start; int realStart=start;
start=Math.max(0, start-1); start=Math.max(0, start-1);
@ -464,10 +479,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
editable.removeSpan(span); editable.removeSpan(span);
} }
} }
}
@Override
public void afterTextChanged(Editable s){
updateCharCounter(); updateCharCounter();
} }
}); });
@ -514,7 +526,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
DraftMediaAttachment da=new DraftMediaAttachment(); DraftMediaAttachment da=new DraftMediaAttachment();
da.serverAttachment=att; da.serverAttachment=att;
da.description=att.description; da.description=att.description;
da.uri=Uri.parse(att.previewUrl); da.uri=att.previewUrl!=null ? Uri.parse(att.previewUrl) : null;
da.state=AttachmentUploadState.DONE; da.state=AttachmentUploadState.DONE;
attachmentsView.addView(createMediaAttachmentView(da)); attachmentsView.addView(createMediaAttachmentView(da));
attachments.add(da); attachments.add(da);
@ -782,14 +794,50 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
.show(); .show();
} }
/**
* Check to see if Android platform photopicker is available on the device\
* @return whether the device supports photopicker intents.
*/
private boolean isPhotoPickerAvailable() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
return true;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return getExtensionVersion(Build.VERSION_CODES.R) >= 2;
} else
return false;
}
/**
* Builds the correct intent for the device version to select media.
*
* <p>For Device version > T or R_SDK_v2, use the android platform photopicker via
* {@link MediaStore#ACTION_PICK_IMAGES}
*
* <p>For earlier versions use the built in docs ui via {@link Intent#ACTION_GET_CONTENT}
*/
private void openFilePicker(){ private void openFilePicker(){
Intent intent=new Intent(Intent.ACTION_GET_CONTENT); Intent intent;
intent.addCategory(Intent.CATEGORY_OPENABLE); boolean usePhotoPicker = isPhotoPickerAvailable();
intent.setType("*/*"); if (usePhotoPicker) {
if(instance.configuration!=null && instance.configuration.mediaAttachments!=null && instance.configuration.mediaAttachments.supportedMimeTypes!=null && !instance.configuration.mediaAttachments.supportedMimeTypes.isEmpty()){ intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
intent.putExtra(Intent.EXTRA_MIME_TYPES, instance.configuration.mediaAttachments.supportedMimeTypes.toArray(new String[0])); intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit());
}else{ } else {
intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/*", "video/*"}); intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
}
if (!usePhotoPicker && instance.configuration != null &&
instance.configuration.mediaAttachments != null &&
instance.configuration.mediaAttachments.supportedMimeTypes != null &&
!instance.configuration.mediaAttachments.supportedMimeTypes.isEmpty()) {
intent.putExtra(Intent.EXTRA_MIME_TYPES,
instance.configuration.mediaAttachments.supportedMimeTypes.toArray(
new String[0]));
} else {
if (!usePhotoPicker) {
// If photo picker is being used these are the default mimetypes.
intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/*", "video/*"});
}
} }
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(intent, MEDIA_RESULT); startActivityForResult(intent, MEDIA_RESULT);
@ -871,7 +919,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
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);
if(draft.serverAttachment!=null){ if(draft.serverAttachment!=null){
ViewImageLoader.load(img, draft.serverAttachment.blurhashPlaceholder, new UrlImageLoaderRequest(draft.serverAttachment.previewUrl, V.dp(250), V.dp(250))); if(draft.serverAttachment.previewUrl!=null)
ViewImageLoader.load(img, draft.serverAttachment.blurhashPlaceholder, new UrlImageLoaderRequest(draft.serverAttachment.previewUrl, V.dp(250), V.dp(250)));
}else{ }else{
if(draft.mimeType.startsWith("image/")){ if(draft.mimeType.startsWith("image/")){
ViewImageLoader.load(img, null, new UrlImageLoaderRequest(draft.uri, V.dp(250), V.dp(250))); ViewImageLoader.load(img, null, new UrlImageLoaderRequest(draft.uri, V.dp(250), V.dp(250)));

View File

@ -17,11 +17,11 @@ public class DiscoverPostsFragment extends StatusListFragment{
@Override @Override
protected void doLoadData(int offset, int count){ protected void doLoadData(int offset, int count){
currentRequest=new GetTrendingStatuses(count) currentRequest=new GetTrendingStatuses(offset, count)
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
onDataLoaded(result, false); onDataLoaded(result, !result.isEmpty());
} }
}).exec(accountID); }).exec(accountID);
} }