Share feature

pull/254/head
Thomas 2 years ago
parent 1a37063295
commit 499f10ea39

@ -26,13 +26,30 @@
<activity
android:name=".activities.MainActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
>
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</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

@ -28,11 +28,15 @@ import android.content.SharedPreferences;
import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.util.Patterns;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -72,8 +76,12 @@ import com.google.android.material.snackbar.Snackbar;
import com.jaredrummler.cyanea.Cyanea;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.NavHeaderMainBinding;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.CrossActionHelper;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastodonHelper;
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.TopBarVM;
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 {
@ -234,6 +248,8 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
private void mamageNewIntent(Intent intent) {
if (intent == null)
return;
String action = intent.getAction();
String type = intent.getType();
Bundle extras = intent.getExtras();
String userIdIntent, instanceIntent;
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);
}
} 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.ScheduledStatus;
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.StatusDraft;
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.SpannableHelper;
import app.fedilab.android.helper.ThemeHelper;
import app.fedilab.android.interfaces.OnDownloadInterface;
import app.fedilab.android.jobs.ScheduleThreadWorker;
import app.fedilab.android.services.PostMessageService;
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 String statusReplyId;
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
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);
statusReplyId = b.getString(Helper.ARG_STATUS_REPLY_ID);
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);
token = b.getString(Helper.ARG_TOKEN, null);
visibility = b.getString(Helper.ARG_VISIBILITY, null);
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);
//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());
//Edit a scheduled status from server
if (scheduledStatus != null) {
@ -342,6 +356,28 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
storeDraft(false);
}
}, 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

@ -17,6 +17,7 @@ package app.fedilab.android.helper;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@ -34,6 +35,7 @@ import java.util.concurrent.TimeUnit;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.activities.BaseActivity;
import app.fedilab.android.activities.ComposeActivity;
import app.fedilab.android.client.endpoints.MastodonSearchService;
import app.fedilab.android.client.entities.api.Results;
@ -399,6 +401,49 @@ public class CrossActionHelper {
}).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 {
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.OutputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URL;
import java.security.Security;
import java.text.DateFormat;
import java.text.ParseException;
@ -131,6 +133,7 @@ import java.util.regex.Pattern;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.MainApplication;
import app.fedilab.android.R;
import app.fedilab.android.activities.ComposeActivity;
import app.fedilab.android.activities.LoginActivity;
import app.fedilab.android.activities.MainActivity;
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.BaseAccount;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.interfaces.OnDownloadInterface;
import app.fedilab.android.sqlite.Sqlite;
import app.fedilab.android.viewmodel.mastodon.OauthVM;
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_STATUS_REPORT = "ARG_STATUS_REPORT";
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_TYPE_OF_INFO = "ARG_TYPE_OF_INFO";
public static final String ARG_TOKEN = "ARG_TOKEN";
@ -1244,6 +1256,21 @@ public class Helper {
}).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
*
@ -1623,4 +1650,74 @@ public class Helper {
})
.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.text.Normalizer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.regex.Matcher;
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
//It only targets last message in a thread
//Return content of last compose message

Loading…
Cancel
Save