mirror of
https://codeberg.org/tom79/Fedilab.git
synced 2025-01-03 14:40:07 +02:00
Share feature
This commit is contained in:
parent
1a37063295
commit
499f10ea39
7 changed files with 416 additions and 5 deletions
|
@ -26,13 +26,30 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.MainActivity"
|
android:name=".activities.MainActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:exported="true"
|
android:exported="true">
|
||||||
>
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
|
|
@ -28,11 +28,15 @@ import android.content.SharedPreferences;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
|
import android.text.Html;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.util.Patterns;
|
||||||
import android.view.ContextThemeWrapper;
|
import android.view.ContextThemeWrapper;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -72,8 +76,12 @@ import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.jaredrummler.cyanea.Cyanea;
|
import com.jaredrummler.cyanea.Cyanea;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import app.fedilab.android.activities.AboutActivity;
|
import app.fedilab.android.activities.AboutActivity;
|
||||||
|
@ -115,6 +123,7 @@ import app.fedilab.android.client.entities.app.PinnedTimeline;
|
||||||
import app.fedilab.android.databinding.ActivityMainBinding;
|
import app.fedilab.android.databinding.ActivityMainBinding;
|
||||||
import app.fedilab.android.databinding.NavHeaderMainBinding;
|
import app.fedilab.android.databinding.NavHeaderMainBinding;
|
||||||
import app.fedilab.android.exception.DBException;
|
import app.fedilab.android.exception.DBException;
|
||||||
|
import app.fedilab.android.helper.CrossActionHelper;
|
||||||
import app.fedilab.android.helper.Helper;
|
import app.fedilab.android.helper.Helper;
|
||||||
import app.fedilab.android.helper.MastodonHelper;
|
import app.fedilab.android.helper.MastodonHelper;
|
||||||
import app.fedilab.android.helper.PinnedTimelineHelper;
|
import app.fedilab.android.helper.PinnedTimelineHelper;
|
||||||
|
@ -128,6 +137,11 @@ import app.fedilab.android.viewmodel.mastodon.InstancesVM;
|
||||||
import app.fedilab.android.viewmodel.mastodon.TimelinesVM;
|
import app.fedilab.android.viewmodel.mastodon.TimelinesVM;
|
||||||
import app.fedilab.android.viewmodel.mastodon.TopBarVM;
|
import app.fedilab.android.viewmodel.mastodon.TopBarVM;
|
||||||
import es.dmoral.toasty.Toasty;
|
import es.dmoral.toasty.Toasty;
|
||||||
|
import okhttp3.Call;
|
||||||
|
import okhttp3.Callback;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
public abstract class BaseMainActivity extends BaseActivity implements NetworkStateReceiver.NetworkStateReceiverListener {
|
public abstract class BaseMainActivity extends BaseActivity implements NetworkStateReceiver.NetworkStateReceiverListener {
|
||||||
|
|
||||||
|
@ -234,6 +248,8 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
|
||||||
private void mamageNewIntent(Intent intent) {
|
private void mamageNewIntent(Intent intent) {
|
||||||
if (intent == null)
|
if (intent == null)
|
||||||
return;
|
return;
|
||||||
|
String action = intent.getAction();
|
||||||
|
String type = intent.getType();
|
||||||
Bundle extras = intent.getExtras();
|
Bundle extras = intent.getExtras();
|
||||||
String userIdIntent, instanceIntent;
|
String userIdIntent, instanceIntent;
|
||||||
if (extras != null && extras.containsKey(Helper.INTENT_ACTION)) {
|
if (extras != null && extras.containsKey(Helper.INTENT_ACTION)) {
|
||||||
|
@ -270,6 +286,142 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
|
||||||
intent.removeExtra(Helper.INTENT_ACTION);
|
intent.removeExtra(Helper.INTENT_ACTION);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} else if (Intent.ACTION_SEND.equals(action) && type != null) {
|
||||||
|
if ("text/plain".equals(type)) {
|
||||||
|
final String[] url = {null};
|
||||||
|
String sharedSubject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
|
||||||
|
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||||
|
//SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(BaseMainActivity.this);
|
||||||
|
//boolean shouldRetrieveMetaData = sharedpreferences.getBoolean(getString(R.string.SET_RETRIEVE_METADATA_IF_URL_FROM_EXTERAL), true);
|
||||||
|
if (sharedText != null) {
|
||||||
|
/* Some apps don't send the URL as the first part of the EXTRA_TEXT,
|
||||||
|
the BBC News app being one such, in this case find where the URL
|
||||||
|
is and strip that out into sharedText.
|
||||||
|
*/
|
||||||
|
Matcher matcher;
|
||||||
|
matcher = Patterns.WEB_URL.matcher(sharedText);
|
||||||
|
while (matcher.find()) {
|
||||||
|
int matchStart = matcher.start(1);
|
||||||
|
int matchEnd = matcher.end();
|
||||||
|
if (matchStart < matchEnd && sharedText.length() >= matchEnd)
|
||||||
|
url[0] = sharedText.substring(matchStart, matchEnd);
|
||||||
|
}
|
||||||
|
new Thread(() -> {
|
||||||
|
if (url[0].startsWith("www."))
|
||||||
|
url[0] = "http://" + url[0];
|
||||||
|
Matcher matcherPattern = Patterns.WEB_URL.matcher(url[0]);
|
||||||
|
String potentialUrl = null;
|
||||||
|
while (matcherPattern.find()) {
|
||||||
|
int matchStart = matcherPattern.start(1);
|
||||||
|
int matchEnd = matcherPattern.end();
|
||||||
|
if (matchStart < matchEnd && url[0].length() >= matchEnd)
|
||||||
|
potentialUrl = url[0].substring(matchStart, matchEnd);
|
||||||
|
}
|
||||||
|
// If we actually have a URL then make use of it.
|
||||||
|
if (potentialUrl != null && potentialUrl.length() > 0) {
|
||||||
|
Pattern titlePattern = Pattern.compile("meta[ a-zA-Z=\"'-]+property=[\"']og:title[\"']\\s+content=[\"']([^>]*)[\"']");
|
||||||
|
Pattern descriptionPattern = Pattern.compile("meta[ a-zA-Z=\"'-]+property=[\"']og:description[\"']\\s+content=[\"']([^>]*)[\"']");
|
||||||
|
Pattern imagePattern = Pattern.compile("meta[ a-zA-Z=\"'-]+property=[\"']og:image[\"']\\s+content=[\"']([^>]*)[\"']");
|
||||||
|
try {
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.proxy(Helper.getProxy(getApplication().getApplicationContext()))
|
||||||
|
.readTimeout(10, TimeUnit.SECONDS).build();
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(potentialUrl)
|
||||||
|
.build();
|
||||||
|
client.newCall(request).enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
runOnUiThread(() -> Toasty.warning(BaseMainActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull Call call, @NonNull final Response response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
try {
|
||||||
|
String data = response.body().string();
|
||||||
|
Matcher matcherTitle;
|
||||||
|
matcherTitle = titlePattern.matcher(data);
|
||||||
|
Matcher matcherDescription = descriptionPattern.matcher(data);
|
||||||
|
Matcher matcherImage = imagePattern.matcher(data);
|
||||||
|
String titleEncoded = null;
|
||||||
|
String descriptionEncoded = null;
|
||||||
|
while (matcherTitle.find())
|
||||||
|
titleEncoded = matcherTitle.group(1);
|
||||||
|
while (matcherDescription.find())
|
||||||
|
descriptionEncoded = matcherDescription.group(1);
|
||||||
|
String image = null;
|
||||||
|
while (matcherImage.find())
|
||||||
|
image = matcherImage.group(1);
|
||||||
|
String title = null;
|
||||||
|
String description = null;
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
if (titleEncoded != null)
|
||||||
|
title = Html.fromHtml(titleEncoded, Html.FROM_HTML_MODE_LEGACY).toString();
|
||||||
|
if (descriptionEncoded != null)
|
||||||
|
description = Html.fromHtml(descriptionEncoded, Html.FROM_HTML_MODE_LEGACY).toString();
|
||||||
|
} else {
|
||||||
|
if (titleEncoded != null)
|
||||||
|
title = Html.fromHtml(titleEncoded).toString();
|
||||||
|
if (descriptionEncoded != null)
|
||||||
|
description = Html.fromHtml(descriptionEncoded).toString();
|
||||||
|
}
|
||||||
|
String finalImage = image;
|
||||||
|
String finalTitle = title;
|
||||||
|
String finalDescription = description;
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
|
||||||
|
|
||||||
|
Bundle b = new Bundle();
|
||||||
|
b.putString(Helper.ARG_SHARE_URL, url[0]);
|
||||||
|
b.putString(Helper.ARG_SHARE_URL_MEDIA, finalImage);
|
||||||
|
b.putString(Helper.ARG_SHARE_TITLE, finalTitle);
|
||||||
|
b.putString(Helper.ARG_SHARE_DESCRIPTION, finalDescription);
|
||||||
|
b.putString(Helper.ARG_SHARE_SUBJECT, sharedSubject);
|
||||||
|
b.putString(Helper.ARG_SHARE_CONTENT, sharedText);
|
||||||
|
CrossActionHelper.doCrossShare(BaseMainActivity.this, b);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
runOnUiThread(() -> Toasty.warning(BaseMainActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
Toasty.warning(BaseMainActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (type.startsWith("image/") || type.startsWith("video/")) {
|
||||||
|
Uri imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||||
|
if (imageUri != null) {
|
||||||
|
intent = new Intent(BaseMainActivity.this, ComposeActivity.class);
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||||
|
intent.putExtra(Helper.ARG_SHARE_URI, imageUri.toString());
|
||||||
|
startActivity(intent);
|
||||||
|
} else {
|
||||||
|
Toasty.warning(BaseMainActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
|
||||||
|
if (type.startsWith("image/") || type.startsWith("video/")) {
|
||||||
|
ArrayList<Uri> imageList = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
|
||||||
|
if (imageList != null) {
|
||||||
|
Bundle b = new Bundle();
|
||||||
|
b.putParcelableArrayList(Helper.ARG_SHARE_URI_LIST, imageList);
|
||||||
|
CrossActionHelper.doCrossShare(BaseMainActivity.this, b);
|
||||||
|
} else {
|
||||||
|
Toasty.warning(BaseMainActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,6 @@ import app.fedilab.android.client.entities.api.EmojiInstance;
|
||||||
import app.fedilab.android.client.entities.api.Mention;
|
import app.fedilab.android.client.entities.api.Mention;
|
||||||
import app.fedilab.android.client.entities.api.ScheduledStatus;
|
import app.fedilab.android.client.entities.api.ScheduledStatus;
|
||||||
import app.fedilab.android.client.entities.api.Status;
|
import app.fedilab.android.client.entities.api.Status;
|
||||||
import app.fedilab.android.client.entities.app.Account;
|
|
||||||
import app.fedilab.android.client.entities.app.BaseAccount;
|
import app.fedilab.android.client.entities.app.BaseAccount;
|
||||||
import app.fedilab.android.client.entities.app.StatusDraft;
|
import app.fedilab.android.client.entities.app.StatusDraft;
|
||||||
import app.fedilab.android.databinding.ActivityPaginationBinding;
|
import app.fedilab.android.databinding.ActivityPaginationBinding;
|
||||||
|
@ -84,6 +83,7 @@ import app.fedilab.android.helper.MastodonHelper;
|
||||||
import app.fedilab.android.helper.MediaHelper;
|
import app.fedilab.android.helper.MediaHelper;
|
||||||
import app.fedilab.android.helper.SpannableHelper;
|
import app.fedilab.android.helper.SpannableHelper;
|
||||||
import app.fedilab.android.helper.ThemeHelper;
|
import app.fedilab.android.helper.ThemeHelper;
|
||||||
|
import app.fedilab.android.interfaces.OnDownloadInterface;
|
||||||
import app.fedilab.android.jobs.ScheduleThreadWorker;
|
import app.fedilab.android.jobs.ScheduleThreadWorker;
|
||||||
import app.fedilab.android.services.PostMessageService;
|
import app.fedilab.android.services.PostMessageService;
|
||||||
import app.fedilab.android.services.ThreadMessageService;
|
import app.fedilab.android.services.ThreadMessageService;
|
||||||
|
@ -134,6 +134,9 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
||||||
private app.fedilab.android.client.entities.api.Account accountMention;
|
private app.fedilab.android.client.entities.api.Account accountMention;
|
||||||
private String statusReplyId;
|
private String statusReplyId;
|
||||||
private app.fedilab.android.client.entities.api.Account mentionBooster;
|
private app.fedilab.android.client.entities.api.Account mentionBooster;
|
||||||
|
private ArrayList<Uri> sharedUriList = new ArrayList<>();
|
||||||
|
private Uri sharedUri;
|
||||||
|
private String sharedSubject, sharedContent, sharedTitle, sharedDescription, shareURL, sharedUrlMedia;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
@ -160,13 +163,24 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
||||||
scheduledStatus = (ScheduledStatus) b.getSerializable(Helper.ARG_STATUS_SCHEDULED);
|
scheduledStatus = (ScheduledStatus) b.getSerializable(Helper.ARG_STATUS_SCHEDULED);
|
||||||
statusReplyId = b.getString(Helper.ARG_STATUS_REPLY_ID);
|
statusReplyId = b.getString(Helper.ARG_STATUS_REPLY_ID);
|
||||||
statusMention = (Status) b.getSerializable(Helper.ARG_STATUS_MENTION);
|
statusMention = (Status) b.getSerializable(Helper.ARG_STATUS_MENTION);
|
||||||
account = (Account) b.getSerializable(Helper.ARG_ACCOUNT);
|
account = (BaseAccount) b.getSerializable(Helper.ARG_ACCOUNT);
|
||||||
instance = b.getString(Helper.ARG_INSTANCE, null);
|
instance = b.getString(Helper.ARG_INSTANCE, null);
|
||||||
token = b.getString(Helper.ARG_TOKEN, null);
|
token = b.getString(Helper.ARG_TOKEN, null);
|
||||||
visibility = b.getString(Helper.ARG_VISIBILITY, null);
|
visibility = b.getString(Helper.ARG_VISIBILITY, null);
|
||||||
mentionBooster = (app.fedilab.android.client.entities.api.Account) b.getSerializable(Helper.ARG_MENTION_BOOSTER);
|
mentionBooster = (app.fedilab.android.client.entities.api.Account) b.getSerializable(Helper.ARG_MENTION_BOOSTER);
|
||||||
accountMention = (app.fedilab.android.client.entities.api.Account) b.getSerializable(Helper.ARG_ACCOUNT_MENTION);
|
accountMention = (app.fedilab.android.client.entities.api.Account) b.getSerializable(Helper.ARG_ACCOUNT_MENTION);
|
||||||
|
//Shared elements
|
||||||
|
sharedUriList = b.getParcelableArrayList(Helper.ARG_SHARE_URI_LIST);
|
||||||
|
sharedUri = b.getParcelable(Helper.ARG_SHARE_URI);
|
||||||
|
sharedUrlMedia = b.getString(Helper.ARG_SHARE_URL_MEDIA);
|
||||||
|
sharedSubject = b.getString(Helper.ARG_SHARE_SUBJECT, null);
|
||||||
|
sharedContent = b.getString(Helper.ARG_SHARE_CONTENT, null);
|
||||||
|
sharedTitle = b.getString(Helper.ARG_SHARE_TITLE, null);
|
||||||
|
sharedDescription = b.getString(Helper.ARG_SHARE_DESCRIPTION, null);
|
||||||
|
shareURL = b.getString(Helper.ARG_SHARE_URL, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
binding.toolbar.setPopupTheme(Helper.popupStyle());
|
binding.toolbar.setPopupTheme(Helper.popupStyle());
|
||||||
//Edit a scheduled status from server
|
//Edit a scheduled status from server
|
||||||
if (scheduledStatus != null) {
|
if (scheduledStatus != null) {
|
||||||
|
@ -342,6 +356,28 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
|
||||||
storeDraft(false);
|
storeDraft(false);
|
||||||
}
|
}
|
||||||
}, 0, 10000);
|
}, 0, 10000);
|
||||||
|
|
||||||
|
if (sharedUriList != null && sharedUriList.size() > 0) {
|
||||||
|
List<Uri> uris = new ArrayList<>(sharedUriList);
|
||||||
|
composeAdapter.addAttachment(-1, uris);
|
||||||
|
} else if (sharedUri != null && !sharedUri.toString().startsWith("http")) {
|
||||||
|
List<Uri> uris = new ArrayList<>();
|
||||||
|
uris.add(sharedUri);
|
||||||
|
composeAdapter.addAttachment(-1, uris);
|
||||||
|
} else if (shareURL != null) {
|
||||||
|
Helper.download(ComposeActivity.this, sharedUrlMedia, new OnDownloadInterface() {
|
||||||
|
@Override
|
||||||
|
public void onDownloaded(String saveFilePath, String downloadUrl, Error error) {
|
||||||
|
composeAdapter.addSharing(shareURL, sharedTitle, sharedDescription, sharedSubject, sharedContent, saveFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdateProgress(int progress) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,6 +17,7 @@ package app.fedilab.android.helper;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import app.fedilab.android.BaseMainActivity;
|
import app.fedilab.android.BaseMainActivity;
|
||||||
import app.fedilab.android.R;
|
import app.fedilab.android.R;
|
||||||
|
import app.fedilab.android.activities.BaseActivity;
|
||||||
import app.fedilab.android.activities.ComposeActivity;
|
import app.fedilab.android.activities.ComposeActivity;
|
||||||
import app.fedilab.android.client.endpoints.MastodonSearchService;
|
import app.fedilab.android.client.endpoints.MastodonSearchService;
|
||||||
import app.fedilab.android.client.entities.api.Results;
|
import app.fedilab.android.client.entities.api.Results;
|
||||||
|
@ -399,6 +401,49 @@ public class CrossActionHelper {
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void doCrossShare(final Context context, final Bundle bundle) {
|
||||||
|
List<BaseAccount> accounts;
|
||||||
|
try {
|
||||||
|
accounts = new Account(context).getAll();
|
||||||
|
List<app.fedilab.android.client.entities.api.Account> accountList = new ArrayList<>();
|
||||||
|
for (BaseAccount account : accounts) {
|
||||||
|
accountList.add(account.mastodon_account);
|
||||||
|
}
|
||||||
|
if (accounts.size() == 1) {
|
||||||
|
Intent intentToot = new Intent(context, ComposeActivity.class);
|
||||||
|
intentToot.putExtras(bundle);
|
||||||
|
context.startActivity(intentToot);
|
||||||
|
((BaseActivity) context).finish();
|
||||||
|
} else {
|
||||||
|
AlertDialog.Builder builderSingle = new AlertDialog.Builder(context, Helper.dialogStyle());
|
||||||
|
builderSingle.setTitle(context.getString(R.string.choose_accounts));
|
||||||
|
final AccountsSearchAdapter accountsSearchAdapter = new AccountsSearchAdapter(context, accountList);
|
||||||
|
final BaseAccount[] accountArray = new BaseAccount[accounts.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (BaseAccount account : accounts) {
|
||||||
|
accountArray[i] = account;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
builderSingle.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
|
||||||
|
builderSingle.setAdapter(accountsSearchAdapter, (dialog, which) -> {
|
||||||
|
final BaseAccount account = accountArray[which];
|
||||||
|
Intent intentToot = new Intent(context, ComposeActivity.class);
|
||||||
|
bundle.putSerializable(Helper.ARG_ACCOUNT, account);
|
||||||
|
intentToot.putExtras(bundle);
|
||||||
|
context.startActivity(intentToot);
|
||||||
|
((BaseActivity) context).finish();
|
||||||
|
dialog.dismiss();
|
||||||
|
});
|
||||||
|
builderSingle.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (DBException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public enum TypeOfCrossAction {
|
public enum TypeOfCrossAction {
|
||||||
FOLLOW_ACTION,
|
FOLLOW_ACTION,
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package app.fedilab.android.helper;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work from https://stackoverflow.com/a/26420820
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class FileNameCleaner {
|
||||||
|
private final static int[] illegalChars = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};
|
||||||
|
|
||||||
|
static {
|
||||||
|
Arrays.sort(illegalChars);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String cleanFileName(String badFileName) {
|
||||||
|
StringBuilder cleanName = new StringBuilder();
|
||||||
|
if (badFileName.contains("?")) {
|
||||||
|
badFileName = badFileName.split("\\?")[0];
|
||||||
|
}
|
||||||
|
int len = badFileName.codePointCount(0, badFileName.length());
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
int c = badFileName.codePointAt(i);
|
||||||
|
if (Arrays.binarySearch(illegalChars, c) < 0) {
|
||||||
|
cleanName.appendCodePoint(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cleanName.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -107,10 +107,12 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.Authenticator;
|
import java.net.Authenticator;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.PasswordAuthentication;
|
import java.net.PasswordAuthentication;
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
|
import java.net.URL;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
@ -131,6 +133,7 @@ import java.util.regex.Pattern;
|
||||||
import app.fedilab.android.BaseMainActivity;
|
import app.fedilab.android.BaseMainActivity;
|
||||||
import app.fedilab.android.MainApplication;
|
import app.fedilab.android.MainApplication;
|
||||||
import app.fedilab.android.R;
|
import app.fedilab.android.R;
|
||||||
|
import app.fedilab.android.activities.ComposeActivity;
|
||||||
import app.fedilab.android.activities.LoginActivity;
|
import app.fedilab.android.activities.LoginActivity;
|
||||||
import app.fedilab.android.activities.MainActivity;
|
import app.fedilab.android.activities.MainActivity;
|
||||||
import app.fedilab.android.activities.WebviewActivity;
|
import app.fedilab.android.activities.WebviewActivity;
|
||||||
|
@ -139,6 +142,7 @@ import app.fedilab.android.client.entities.api.Attachment;
|
||||||
import app.fedilab.android.client.entities.app.Account;
|
import app.fedilab.android.client.entities.app.Account;
|
||||||
import app.fedilab.android.client.entities.app.BaseAccount;
|
import app.fedilab.android.client.entities.app.BaseAccount;
|
||||||
import app.fedilab.android.exception.DBException;
|
import app.fedilab.android.exception.DBException;
|
||||||
|
import app.fedilab.android.interfaces.OnDownloadInterface;
|
||||||
import app.fedilab.android.sqlite.Sqlite;
|
import app.fedilab.android.sqlite.Sqlite;
|
||||||
import app.fedilab.android.viewmodel.mastodon.OauthVM;
|
import app.fedilab.android.viewmodel.mastodon.OauthVM;
|
||||||
import app.fedilab.android.watermark.androidwm.WatermarkBuilder;
|
import app.fedilab.android.watermark.androidwm.WatermarkBuilder;
|
||||||
|
@ -206,6 +210,14 @@ public class Helper {
|
||||||
public static final String ARG_MINIFIED = "ARG_MINIFIED";
|
public static final String ARG_MINIFIED = "ARG_MINIFIED";
|
||||||
public static final String ARG_STATUS_REPORT = "ARG_STATUS_REPORT";
|
public static final String ARG_STATUS_REPORT = "ARG_STATUS_REPORT";
|
||||||
public static final String ARG_STATUS_MENTION = "ARG_STATUS_MENTION";
|
public static final String ARG_STATUS_MENTION = "ARG_STATUS_MENTION";
|
||||||
|
public static final String ARG_SHARE_URI = "ARG_SHARE_URI";
|
||||||
|
public static final String ARG_SHARE_URL_MEDIA = "ARG_SHARE_URL_MEDIA";
|
||||||
|
public static final String ARG_SHARE_URL = "ARG_SHARE_URL";
|
||||||
|
public static final String ARG_SHARE_URI_LIST = "ARG_SHARE_URI_LIST";
|
||||||
|
public static final String ARG_SHARE_TITLE = "ARG_SHARE_TITLE";
|
||||||
|
public static final String ARG_SHARE_SUBJECT = "ARG_SHARE_SUBJECT";
|
||||||
|
public static final String ARG_SHARE_DESCRIPTION = "ARG_SHARE_DESCRIPTION";
|
||||||
|
public static final String ARG_SHARE_CONTENT = "ARG_SHARE_CONTENT";
|
||||||
public static final String ARG_FOLLOW_TYPE = "ARG_FOLLOW_TYPE";
|
public static final String ARG_FOLLOW_TYPE = "ARG_FOLLOW_TYPE";
|
||||||
public static final String ARG_TYPE_OF_INFO = "ARG_TYPE_OF_INFO";
|
public static final String ARG_TYPE_OF_INFO = "ARG_TYPE_OF_INFO";
|
||||||
public static final String ARG_TOKEN = "ARG_TOKEN";
|
public static final String ARG_TOKEN = "ARG_TOKEN";
|
||||||
|
@ -1244,6 +1256,21 @@ public class Helper {
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void createAttachmentFromPAth(String path, OnAttachmentCopied callBack) {
|
||||||
|
new Thread(() -> {
|
||||||
|
Attachment attachment = new Attachment();
|
||||||
|
attachment.mimeType = "image/*";
|
||||||
|
String extension = "jpg";
|
||||||
|
SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_" + counter, Locale.getDefault());
|
||||||
|
attachment.local_path = path;
|
||||||
|
Date now = new Date();
|
||||||
|
attachment.filename = formatter.format(now) + "." + extension;
|
||||||
|
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||||
|
Runnable myRunnable = () -> callBack.onAttachmentCopied(attachment);
|
||||||
|
mainHandler.post(myRunnable);
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* change color of a drawable
|
* change color of a drawable
|
||||||
*
|
*
|
||||||
|
@ -1623,4 +1650,74 @@ public class Helper {
|
||||||
})
|
})
|
||||||
.create();
|
.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Download method which works for http and https connections
|
||||||
|
* @param downloadUrl String download url
|
||||||
|
* @param listener OnDownloadInterface, listener which manages progress
|
||||||
|
*/
|
||||||
|
public static void download(Context context, final String downloadUrl, final OnDownloadInterface listener) {
|
||||||
|
new Thread(() -> {
|
||||||
|
URL url;
|
||||||
|
int CHUNK_SIZE = 4096;
|
||||||
|
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
boolean enable_proxy = sharedpreferences.getBoolean(context.getString(R.string.SET_PROXY_ENABLED), false);
|
||||||
|
Proxy proxy = null;
|
||||||
|
if (enable_proxy) {
|
||||||
|
proxy = getProxy(context);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
url = new URL(downloadUrl);
|
||||||
|
HttpURLConnection httpURLConnection;
|
||||||
|
if (proxy != null)
|
||||||
|
httpURLConnection = (HttpURLConnection) url.openConnection(proxy);
|
||||||
|
else
|
||||||
|
httpURLConnection = (HttpURLConnection) url.openConnection();
|
||||||
|
httpURLConnection.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
|
int responseCode = httpURLConnection.getResponseCode();
|
||||||
|
|
||||||
|
// always check HTTP response code first
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
|
String fileName = "";
|
||||||
|
String disposition = httpURLConnection.getHeaderField("Content-Disposition");
|
||||||
|
|
||||||
|
if (disposition != null) {
|
||||||
|
// extracts file name from header field
|
||||||
|
int index = disposition.indexOf("filename=");
|
||||||
|
if (index > 0) {
|
||||||
|
fileName = disposition.substring(index + 10,
|
||||||
|
disposition.length() - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// extracts file name from URL
|
||||||
|
fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1);
|
||||||
|
}
|
||||||
|
fileName = FileNameCleaner.cleanFileName(fileName);
|
||||||
|
// opens input stream from the HTTP connection
|
||||||
|
InputStream inputStream = httpURLConnection.getInputStream();
|
||||||
|
File saveDir = context.getCacheDir();
|
||||||
|
final String saveFilePath = saveDir + File.separator + fileName;
|
||||||
|
// opens an output stream to save into file
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
|
||||||
|
|
||||||
|
int bytesRead;
|
||||||
|
byte[] buffer = new byte[CHUNK_SIZE];
|
||||||
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
outputStream.close();
|
||||||
|
inputStream.close();
|
||||||
|
((ComposeActivity) context).runOnUiThread(() -> listener.onDownloaded(saveFilePath, downloadUrl, null));
|
||||||
|
} else {
|
||||||
|
((ComposeActivity) context).runOnUiThread(() -> listener.onDownloaded(null, downloadUrl, new Error()));
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
((ComposeActivity) context).runOnUiThread(() -> listener.onDownloaded(null, downloadUrl, new Error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,9 +74,12 @@ import com.bumptech.glide.request.transition.Transition;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.text.Normalizer;
|
import java.text.Normalizer;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -390,6 +393,37 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a shared element
|
||||||
|
* If title and description are empty, it will use subject and content coming from the intent
|
||||||
|
*
|
||||||
|
* @param url - String url that is shared
|
||||||
|
* @param title - String title gather from the URL
|
||||||
|
* @param description - String description gathered from the URL
|
||||||
|
* @param subject - String subject (title) comming from the shared elements
|
||||||
|
* @param content - String content (description) coming from the shared elements
|
||||||
|
*/
|
||||||
|
public void addSharing(String url, String title, String description, String subject, String content, String saveFilePath) {
|
||||||
|
int position = statusList.size() - 1;
|
||||||
|
statusList.get(position).text = title != null ? title : subject;
|
||||||
|
statusList.get(position).text += "\n\n";
|
||||||
|
statusList.get(position).text += description != null ? description : content;
|
||||||
|
statusList.get(position).text += "\n\n";
|
||||||
|
statusList.get(position).text += url;
|
||||||
|
Attachment attachment = new Attachment();
|
||||||
|
attachment.mimeType = "image/*";
|
||||||
|
String extension = "jpg";
|
||||||
|
SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_", Locale.getDefault());
|
||||||
|
attachment.local_path = saveFilePath;
|
||||||
|
Date now = new Date();
|
||||||
|
attachment.filename = formatter.format(now) + "." + extension;
|
||||||
|
if (statusList.get(position).media_attachments == null) {
|
||||||
|
statusList.get(position).media_attachments = new ArrayList<>();
|
||||||
|
}
|
||||||
|
statusList.get(position).media_attachments.add(attachment);
|
||||||
|
notifyItemChanged(position);
|
||||||
|
}
|
||||||
|
|
||||||
//<------ Manage contact from compose activity
|
//<------ Manage contact from compose activity
|
||||||
//It only targets last message in a thread
|
//It only targets last message in a thread
|
||||||
//Return content of last compose message
|
//Return content of last compose message
|
||||||
|
|
Loading…
Reference in a new issue