Merge branch 'feature/open-urls-in-app'

This commit is contained in:
sk 2022-12-21 23:50:14 +01:00
commit ccb0b59e17
3 changed files with 95 additions and 6 deletions

View File

@ -20,6 +20,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import androidx.annotation.CallSuper;
import androidx.annotation.StringRes;
@ -101,9 +102,14 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
}
public MastodonAPIRequest<T> wrapProgress(Activity activity, @StringRes int message, boolean cancelable){
return wrapProgress(activity, message, cancelable, null);
}
public MastodonAPIRequest<T> wrapProgress(Activity activity, @StringRes int message, boolean cancelable, Consumer<ProgressDialog> transform){
progressDialog=new ProgressDialog(activity);
progressDialog.setMessage(activity.getString(message));
progressDialog.setCancelable(cancelable);
if (transform != null) transform.accept(progressDialog);
if(cancelable){
progressDialog.setOnCancelListener(dialog->cancel());
}

View File

@ -5,10 +5,12 @@ import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@ -50,6 +52,7 @@ import org.joinmastodon.android.api.requests.accounts.SetDomainBlocked;
import org.joinmastodon.android.api.requests.accounts.AuthorizeFollowRequest;
import org.joinmastodon.android.api.requests.accounts.RejectFollowRequest;
import org.joinmastodon.android.api.requests.notifications.DismissNotification;
import org.joinmastodon.android.api.requests.search.GetSearchResults;
import org.joinmastodon.android.api.requests.statuses.DeleteStatus;
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
import org.joinmastodon.android.api.requests.statuses.SetStatusPinned;
@ -69,6 +72,7 @@ import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.ListTimeline;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.model.SearchResults;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.text.CustomEmojiSpan;
@ -77,6 +81,8 @@ import org.parceler.Parcels;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@ -697,12 +703,61 @@ public class UiUtils{
return theme==GlobalUserPreferences.ThemePreference.DARK;
}
public static void openURL(Context context, @Nullable String accountID, String url){
// https://mastodon.foo.bar/@User
// https://mastodon.foo.bar/@User/43456787654678
// https://pleroma.foo.bar/users/User
// https://pleroma.foo.bar/users/9qTHT2ANWUdXzENqC0
// https://pleroma.foo.bar/notice/9sBHWIlwwGZi5QGlHc
// https://pleroma.foo.bar/objects/d4643c42-3ae0-4b73-b8b0-c725f5819207
// https://friendica.foo.bar/profile/user
// https://friendica.foo.bar/display/d4643c42-3ae0-4b73-b8b0-c725f5819207
// https://misskey.foo.bar/notes/83w6r388br (always lowercase)
// https://pixelfed.social/p/connyduck/391263492998670833
// https://pixelfed.social/connyduck
// https://gts.foo.bar/@goblin/statuses/01GH9XANCJ0TA8Y95VE9H3Y0Q2
// https://gts.foo.bar/@goblin
// https://foo.microblog.pub/o/5b64045effd24f48a27d7059f6cb38f5
//
// COPIED FROM https://github.com/tuskyapp/Tusky/blob/develop/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt
public static boolean looksLikeMastodonUrl(String urlString) {
URI uri;
try {
uri = new URI(urlString);
} catch (URISyntaxException e) {
return false;
}
if (uri.getQuery() != null || uri.getFragment() != null || uri.getPath() == null) return false;
String it = uri.getPath();
return it.matches("^/@[^/]+$") ||
it.matches("^/@[^/]+/\\d+$") ||
it.matches("^/users/\\w+$") ||
it.matches("^/notice/[a-zA-Z0-9]+$") ||
it.matches("^/objects/[-a-f0-9]+$") ||
it.matches("^/notes/[a-z0-9]+$") ||
it.matches("^/display/[-a-f0-9]+$") ||
it.matches("^/profile/\\w+$") ||
it.matches("^/p/\\w+/\\d+$") ||
it.matches("^/\\w+$") ||
it.matches("^/@[^/]+/statuses/[a-zA-Z0-9]+$") ||
it.matches("^/o/[a-f0-9]+$");
}
public static void openURL(Context context, String accountID, String url){
Consumer<ProgressDialog> transformDialogForLookup = dialog -> {
dialog.setTitle(R.string.sk_loading_fediverse_resource_title);
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.cancel), (d, which) -> d.cancel());
dialog.setButton(DialogInterface.BUTTON_POSITIVE, context.getString(R.string.open_in_browser), (d, which) -> {
d.cancel();
launchWebBrowser(context, url);
});
};
Uri uri=Uri.parse(url);
if(accountID!=null && "https".equals(uri.getScheme()) && AccountSessionManager.getInstance().getAccount(accountID).domain.equalsIgnoreCase(uri.getAuthority())){
List<String> path=uri.getPathSegments();
// Match URLs like https://mastodon.social/@Gargron/108132679274083591
if(path.size()==2 && path.get(0).matches("^@[a-zA-Z0-9_]+$") && path.get(1).matches("^[0-9]+$")){
if(accountID!=null && "https".equals(uri.getScheme())){
if(path.size()==2 && path.get(0).matches("^@[a-zA-Z0-9_]+$") && path.get(1).matches("^[0-9]+$") && AccountSessionManager.getInstance().getAccount(accountID).domain.equalsIgnoreCase(uri.getAuthority())){
new GetStatusByID(path.get(1))
.setCallback(new Callback<>(){
@Override
@ -719,7 +774,34 @@ public class UiUtils{
launchWebBrowser(context, url);
}
})
.wrapProgress((Activity)context, R.string.loading, true)
.wrapProgress((Activity)context, R.string.loading, true, transformDialogForLookup)
.exec(accountID);
return;
} else if (looksLikeMastodonUrl(url)) {
new GetSearchResults(url, null, true)
.setCallback(new Callback<>() {
@Override
public void onSuccess(SearchResults results) {
Bundle args=new Bundle();
args.putString("account", accountID);
if (!results.statuses.isEmpty()) {
args.putParcelable("status", Parcels.wrap(results.statuses.get(0)));
Nav.go((Activity) context, ThreadFragment.class, args);
} else if (!results.accounts.isEmpty()) {
args.putParcelable("profileAccount", Parcels.wrap(results.accounts.get(0)));
Nav.go((Activity) context, ProfileFragment.class, args);
} else {
launchWebBrowser(context, url);
}
}
@Override
public void onError(ErrorResponse error) {
error.showToast(context);
launchWebBrowser(context, url);
}
})
.wrapProgress((Activity)context, R.string.loading, true, transformDialogForLookup)
.exec(accountID);
return;
}

View File

@ -82,4 +82,5 @@
<string name="sk_settings_hide_translate_in_timeline">Hide translate button in timeline</string>
<string name="sk_settings_translation_availability_note_available">%s supports translation!</string>
<string name="sk_settings_translation_availability_note_unavailable">%s does not appear to support translation.</string>
<string name="sk_loading_fediverse_resource_title">Looking it up on the Fediverse…</string>
</resources>