From ed5564d4d5578710ee4e5c868897788ad514df63 Mon Sep 17 00:00:00 2001 From: torrentcome Date: Mon, 15 May 2017 12:05:10 +0200 Subject: [PATCH 01/11] (receiver) create package for receiver --- app/src/main/AndroidManifest.xml | 2 +- .../main/java/com/keylesspalace/tusky/AccountActivity.java | 2 +- .../com/keylesspalace/tusky/fragment/TimelineFragment.java | 4 ++-- .../NotificationClearBroadcastReceiver.java | 2 +- .../tusky/{util => receiver}/TimelineReceiver.java | 2 +- .../java/com/keylesspalace/tusky/util/NotificationMaker.java | 2 ++ 6 files changed, 8 insertions(+), 6 deletions(-) rename app/src/main/java/com/keylesspalace/tusky/{util => receiver}/NotificationClearBroadcastReceiver.java (96%) rename app/src/main/java/com/keylesspalace/tusky/{util => receiver}/TimelineReceiver.java (96%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 058d165b3..23c638a70 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -81,7 +81,7 @@ android:name="com.theartofdev.edmodo.cropper.CropImageActivity" android:theme="@style/Base.Theme.AppCompat" /> - + . */ -package com.keylesspalace.tusky.util; +package com.keylesspalace.tusky.receiver; import android.content.BroadcastReceiver; import android.content.Context; diff --git a/app/src/main/java/com/keylesspalace/tusky/util/TimelineReceiver.java b/app/src/main/java/com/keylesspalace/tusky/receiver/TimelineReceiver.java similarity index 96% rename from app/src/main/java/com/keylesspalace/tusky/util/TimelineReceiver.java rename to app/src/main/java/com/keylesspalace/tusky/receiver/TimelineReceiver.java index f6acc0d9c..71a094139 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/TimelineReceiver.java +++ b/app/src/main/java/com/keylesspalace/tusky/receiver/TimelineReceiver.java @@ -1,4 +1,4 @@ -package com.keylesspalace.tusky.util; +package com.keylesspalace.tusky.receiver; import android.content.BroadcastReceiver; import android.content.Context; diff --git a/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java b/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java index e5bc70033..22947dc02 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/NotificationMaker.java @@ -32,6 +32,8 @@ import android.support.v4.app.TaskStackBuilder; import com.keylesspalace.tusky.MainActivity; import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.entity.Notification; +import com.keylesspalace.tusky.receiver.NotificationClearBroadcastReceiver; +import com.keylesspalace.tusky.view.RoundedTransformation; import com.squareup.picasso.Picasso; import com.squareup.picasso.Target; From 0a6a2e44c2d3998b23bb86d2ef72d62b8efe1c42 Mon Sep 17 00:00:00 2001 From: torrentcome Date: Mon, 15 May 2017 12:07:01 +0200 Subject: [PATCH 02/11] (view) create package view --- .../main/java/com/keylesspalace/tusky/ComposeActivity.java | 2 +- .../com/keylesspalace/tusky/adapter/StatusViewHolder.java | 2 +- .../com/keylesspalace/tusky/fragment/AccountListFragment.java | 2 +- .../keylesspalace/tusky/fragment/NotificationsFragment.java | 2 +- .../com/keylesspalace/tusky/fragment/ViewThreadFragment.java | 2 +- .../tusky/{util => view}/ConversationLineItemDecoration.java | 2 +- .../com/keylesspalace/tusky/{util => view}/EditTextTyped.java | 4 +++- .../tusky/{util => view}/EndlessOnScrollListener.java | 2 +- .../com/keylesspalace/tusky/{util => view}/FlowLayout.java | 3 ++- .../tusky/{util => view}/RoundedTransformation.java | 2 +- app/src/main/res/layout/activity_compose.xml | 2 +- app/src/main/res/layout/item_status.xml | 4 ++-- 12 files changed, 16 insertions(+), 13 deletions(-) rename app/src/main/java/com/keylesspalace/tusky/{util => view}/ConversationLineItemDecoration.java (98%) rename app/src/main/java/com/keylesspalace/tusky/{util => view}/EditTextTyped.java (96%) rename app/src/main/java/com/keylesspalace/tusky/{util => view}/EndlessOnScrollListener.java (98%) rename app/src/main/java/com/keylesspalace/tusky/{util => view}/FlowLayout.java (98%) rename app/src/main/java/com/keylesspalace/tusky/{util => view}/RoundedTransformation.java (98%) diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java index f0089fd2f..f1e3eb342 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java @@ -73,7 +73,7 @@ import com.keylesspalace.tusky.entity.Media; import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.fragment.ComposeOptionsFragment; import com.keylesspalace.tusky.util.DownsizeImageTask; -import com.keylesspalace.tusky.util.EditTextTyped; +import com.keylesspalace.tusky.view.EditTextTyped; import com.keylesspalace.tusky.util.CountUpDownLatch; import com.keylesspalace.tusky.util.IOUtils; import com.keylesspalace.tusky.util.Log; diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java index 1d029e86b..abfecd8ed 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java @@ -28,7 +28,7 @@ import android.widget.TextView; import android.widget.ToggleButton; import com.keylesspalace.tusky.R; -import com.keylesspalace.tusky.util.RoundedTransformation; +import com.keylesspalace.tusky.view.RoundedTransformation; import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.util.DateUtils; diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java index eed0d72a1..db12f323e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.java @@ -42,7 +42,7 @@ import com.keylesspalace.tusky.entity.Relationship; import com.keylesspalace.tusky.interfaces.AccountActionListener; import com.keylesspalace.tusky.network.MastodonAPI; import com.keylesspalace.tusky.R; -import com.keylesspalace.tusky.util.EndlessOnScrollListener; +import com.keylesspalace.tusky.view.EndlessOnScrollListener; import com.keylesspalace.tusky.util.Log; import com.keylesspalace.tusky.util.ThemeUtils; diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java index bef04290d..cd95b215e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java @@ -39,7 +39,7 @@ import com.keylesspalace.tusky.entity.Notification; import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.interfaces.StatusRemoveListener; -import com.keylesspalace.tusky.util.EndlessOnScrollListener; +import com.keylesspalace.tusky.view.EndlessOnScrollListener; import com.keylesspalace.tusky.util.Log; import com.keylesspalace.tusky.util.ThemeUtils; diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java index d02f43596..32a371429 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java @@ -38,7 +38,7 @@ import com.keylesspalace.tusky.network.MastodonAPI; import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.interfaces.StatusRemoveListener; -import com.keylesspalace.tusky.util.ConversationLineItemDecoration; +import com.keylesspalace.tusky.view.ConversationLineItemDecoration; import com.keylesspalace.tusky.util.Log; import com.keylesspalace.tusky.util.ThemeUtils; diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ConversationLineItemDecoration.java b/app/src/main/java/com/keylesspalace/tusky/view/ConversationLineItemDecoration.java similarity index 98% rename from app/src/main/java/com/keylesspalace/tusky/util/ConversationLineItemDecoration.java rename to app/src/main/java/com/keylesspalace/tusky/view/ConversationLineItemDecoration.java index dab773c35..fee358d0f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ConversationLineItemDecoration.java +++ b/app/src/main/java/com/keylesspalace/tusky/view/ConversationLineItemDecoration.java @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License along with Tusky; if not, * see . */ -package com.keylesspalace.tusky.util; +package com.keylesspalace.tusky.view; import android.content.Context; import android.graphics.Canvas; diff --git a/app/src/main/java/com/keylesspalace/tusky/util/EditTextTyped.java b/app/src/main/java/com/keylesspalace/tusky/view/EditTextTyped.java similarity index 96% rename from app/src/main/java/com/keylesspalace/tusky/util/EditTextTyped.java rename to app/src/main/java/com/keylesspalace/tusky/view/EditTextTyped.java index c32f666f4..2c8f85219 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/EditTextTyped.java +++ b/app/src/main/java/com/keylesspalace/tusky/view/EditTextTyped.java @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License along with Tusky; if not, * see . */ -package com.keylesspalace.tusky.util; +package com.keylesspalace.tusky.view; import android.content.Context; import android.support.v13.view.inputmethod.EditorInfoCompat; @@ -23,6 +23,8 @@ import android.util.AttributeSet; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; +import com.keylesspalace.tusky.util.Assert; + public class EditTextTyped extends AppCompatEditText { InputConnectionCompat.OnCommitContentListener onCommitContentListener; String[] mimeTypes; diff --git a/app/src/main/java/com/keylesspalace/tusky/util/EndlessOnScrollListener.java b/app/src/main/java/com/keylesspalace/tusky/view/EndlessOnScrollListener.java similarity index 98% rename from app/src/main/java/com/keylesspalace/tusky/util/EndlessOnScrollListener.java rename to app/src/main/java/com/keylesspalace/tusky/view/EndlessOnScrollListener.java index 0b149de05..8b45d11fe 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/EndlessOnScrollListener.java +++ b/app/src/main/java/com/keylesspalace/tusky/view/EndlessOnScrollListener.java @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License along with Tusky; if not, * see . */ -package com.keylesspalace.tusky.util; +package com.keylesspalace.tusky.view; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; diff --git a/app/src/main/java/com/keylesspalace/tusky/util/FlowLayout.java b/app/src/main/java/com/keylesspalace/tusky/view/FlowLayout.java similarity index 98% rename from app/src/main/java/com/keylesspalace/tusky/util/FlowLayout.java rename to app/src/main/java/com/keylesspalace/tusky/view/FlowLayout.java index cf1f9e686..df762377f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/FlowLayout.java +++ b/app/src/main/java/com/keylesspalace/tusky/view/FlowLayout.java @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License along with Tusky; if not, * see . */ -package com.keylesspalace.tusky.util; +package com.keylesspalace.tusky.view; import android.content.Context; import android.content.res.TypedArray; @@ -22,6 +22,7 @@ import android.view.View; import android.view.ViewGroup; import com.keylesspalace.tusky.R; +import com.keylesspalace.tusky.util.Assert; public class FlowLayout extends ViewGroup { private int paddingHorizontal; // internal padding between child views diff --git a/app/src/main/java/com/keylesspalace/tusky/util/RoundedTransformation.java b/app/src/main/java/com/keylesspalace/tusky/view/RoundedTransformation.java similarity index 98% rename from app/src/main/java/com/keylesspalace/tusky/util/RoundedTransformation.java rename to app/src/main/java/com/keylesspalace/tusky/view/RoundedTransformation.java index ff153d687..9a0230104 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/RoundedTransformation.java +++ b/app/src/main/java/com/keylesspalace/tusky/view/RoundedTransformation.java @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License along with Tusky; if not, * see . */ -package com.keylesspalace.tusky.util; +package com.keylesspalace.tusky.view; import android.graphics.Bitmap; import android.graphics.BitmapShader; diff --git a/app/src/main/res/layout/activity_compose.xml b/app/src/main/res/layout/activity_compose.xml index 0252cce7b..1f5b14f16 100644 --- a/app/src/main/res/layout/activity_compose.xml +++ b/app/src/main/res/layout/activity_compose.xml @@ -54,7 +54,7 @@ android:paddingLeft="16dp" android:paddingRight="16dp"> - - - + Date: Mon, 15 May 2017 12:07:11 +0200 Subject: [PATCH 03/11] (jsoup) add jsoup --- app/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/app/build.gradle b/app/build.gradle index cf42c9791..3248afb32 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -59,6 +59,7 @@ dependencies { compile 'com.github.arimorty:floatingsearchview:2.0.4' compile 'com.theartofdev.edmodo:android-image-cropper:2.4.3' compile 'com.jakewharton:butterknife:8.5.1' + compile 'org.jsoup:jsoup:1.10.2' googleCompile 'com.google.firebase:firebase-messaging:10.2.4' googleCompile 'com.google.firebase:firebase-crash:10.2.4' testCompile 'junit:junit:4.12' From 1f62c34a131decd2b3fc55e9b496eb6f47c59aa4 Mon Sep 17 00:00:00 2001 From: torrentcome Date: Tue, 16 May 2017 10:10:37 +0200 Subject: [PATCH 04/11] (edit text typed) add onPast listener on the view --- .../tusky/view/EditTextTyped.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/app/src/main/java/com/keylesspalace/tusky/view/EditTextTyped.java b/app/src/main/java/com/keylesspalace/tusky/view/EditTextTyped.java index 2c8f85219..4693ee35c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/view/EditTextTyped.java +++ b/app/src/main/java/com/keylesspalace/tusky/view/EditTextTyped.java @@ -26,8 +26,10 @@ import android.view.inputmethod.InputConnection; import com.keylesspalace.tusky.util.Assert; public class EditTextTyped extends AppCompatEditText { + InputConnectionCompat.OnCommitContentListener onCommitContentListener; String[] mimeTypes; + private OnPasteListener mOnPasteListener; public EditTextTyped(Context context) { super(context); @@ -37,6 +39,10 @@ public class EditTextTyped extends AppCompatEditText { super(context, attributeSet); } + public void addOnPasteListener(OnPasteListener mOnPasteListener) { + this.mOnPasteListener = mOnPasteListener; + } + public void setMimeTypes(String[] types, InputConnectionCompat.OnCommitContentListener listener) { mimeTypes = types; @@ -55,4 +61,26 @@ public class EditTextTyped extends AppCompatEditText { return connection; } } + + @Override + public boolean onTextContextMenuItem(int id) { + boolean consumed = super.onTextContextMenuItem(id); + switch (id) { + case android.R.id.paste: + onPaste(); + } + return consumed; + } + + /** + * Text was pasted into the EditText. + */ + public void onPaste() { + if (mOnPasteListener != null) + mOnPasteListener.onPaste(); + } + + public interface OnPasteListener { + void onPaste(); + } } From 583983e58f7416fae0e93e63f1bec2ee27e0b656 Mon Sep 17 00:00:00 2001 From: torrentcome Date: Tue, 16 May 2017 10:40:12 +0200 Subject: [PATCH 05/11] (string utils) create string utils for start to group all function there --- .../keylesspalace/tusky/util/StringUtils.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/StringUtils.java diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.java new file mode 100644 index 000000000..ff050f2c7 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.java @@ -0,0 +1,19 @@ +package com.keylesspalace.tusky.util; + +import java.util.Random; + +public class StringUtils { + + public final static String carriageReturn = System.getProperty("line.separator"); + final static String QUOTE = "\""; + + public static String randomAlphanumericString(int count) { + char[] chars = new char[count]; + Random random = new Random(); + final String POSSIBLE_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + for (int i = 0; i < count; i++) { + chars[i] = POSSIBLE_CHARS.charAt(random.nextInt(POSSIBLE_CHARS.length())); + } + return new String(chars); + } +} From 27db497ff2ca28868d611ea2a93d75e7c74ac54e Mon Sep 17 00:00:00 2001 From: torrentcome Date: Tue, 16 May 2017 10:41:14 +0200 Subject: [PATCH 06/11] (media utils) create media utils for start to group all function linked to the media there too --- .../keylesspalace/tusky/util/MediaUtils.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.java diff --git a/app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.java new file mode 100644 index 000000000..76d18bdea --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.java @@ -0,0 +1,117 @@ +package com.keylesspalace.tusky.util; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Environment; +import android.provider.OpenableColumns; +import android.support.annotation.Nullable; +import android.support.v4.content.FileProvider; + +import com.squareup.picasso.Picasso; +import com.squareup.picasso.Target; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Class who will have all the code link with Media + *

+ * Motivation : try to keep the ComposeActivity "smaller" and make modular method + */ +public class MediaUtils { + public static final int MEDIA_SIZE_UNKNOWN = -1; + + @Nullable + public static byte[] inputStreamGetBytes(InputStream stream) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int read; + byte[] data = new byte[16384]; + try { + while ((read = stream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, read); + } + buffer.flush(); + } catch (IOException e) { + return null; + } + return buffer.toByteArray(); + } + + public static long getMediaSize(ContentResolver contentResolver, Uri uri) { + long mediaSize; + Cursor cursor = contentResolver.query(uri, null, null, null, null); + if (cursor != null) { + int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE); + cursor.moveToFirst(); + mediaSize = cursor.getLong(sizeIndex); + cursor.close(); + } else { + mediaSize = MEDIA_SIZE_UNKNOWN; + } + return mediaSize; + } + + // Download an image with picasso + public static Target picassoImageTarget(final Context context, final MediaListener mediaListener) { + final String imageName = "temp"; + return new Target() { + @Override + public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) { + new Thread(new Runnable() { + @Override + public void run() { + FileOutputStream fos = null; + Uri uriForFile; + try { + // we download only a "temp" file + File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); + File tempFile = File.createTempFile( + imageName, + ".jpg", + storageDir + ); + + fos = new FileOutputStream(tempFile); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); + uriForFile = FileProvider.getUriForFile(context, + "com.keylesspalace.tusky.fileprovider", + tempFile); + + // giving to the activity the URI callback + mediaListener.onCallback(uriForFile); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (fos != null) { + fos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + }).start(); + } + + @Override + public void onBitmapFailed(Drawable errorDrawable) { + } + + @Override + public void onPrepareLoad(Drawable placeHolderDrawable) { + } + }; + } + + public interface MediaListener { + void onCallback(Uri headerInfo); + } +} From 6dd2aba3c6871537d4f94b3f79b44381aa5a1602 Mon Sep 17 00:00:00 2001 From: torrentcome Date: Tue, 16 May 2017 10:42:31 +0200 Subject: [PATCH 07/11] (parser utils) class who will get header information of an given Url - will redistribute that to the activity by listener --- .../keylesspalace/tusky/util/ParserUtils.java | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java new file mode 100644 index 000000000..215765261 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java @@ -0,0 +1,113 @@ +package com.keylesspalace.tusky.util; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.os.AsyncTask; +import android.text.TextUtils; +import android.webkit.URLUtil; + +import org.jsoup.Connection; +import org.jsoup.Jsoup; +import org.jsoup.helper.HttpConnection; +import org.jsoup.nodes.Document; +import org.jsoup.select.Elements; + +import static com.keylesspalace.tusky.util.StringUtils.QUOTE; + +/** + * Inspect and Get the information from an URL + */ +public class ParserUtils { + private static final String TAG = "ParserUtils"; + private ParserListener parserListener; + + public ParserUtils(ParserListener parserListener) { + this.parserListener = parserListener; + } + + // ComposeActivity : EditText inside the onTextChanged + public String getPastedURLText(Context context) { + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + String pasteData; + if (clipboard.hasPrimaryClip()) { + // get what is in the clipboard + ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0); + pasteData = item.getText().toString(); + + // we have to find an url for start it + if (URLUtil.isValidUrl(pasteData)) { + new ThreadHeaderInfo().execute(pasteData); + } + } + return null; + } + + // parse the HTML page + private HeaderInfo parsePageHeaderInfo(String urlStr) throws Exception { + Connection con = Jsoup.connect(urlStr); + HeaderInfo headerInfo = new HeaderInfo(); + con.userAgent(HttpConnection.DEFAULT_UA); + Document doc = con.get(); + + // get info + String text; + Elements metaOgTitle = doc.select("meta[property=og:title]"); + if (metaOgTitle != null) { + text = metaOgTitle.attr("content"); + } else { + text = doc.title(); + } + + String imageUrl = null; + Elements metaOgImage = doc.select("meta[property=og:image]"); + if (metaOgImage != null) { + imageUrl = metaOgImage.attr("content"); + } + + // set info + headerInfo.baseUrl = urlStr; + if (!TextUtils.isEmpty(text)) { + headerInfo.title = QUOTE + text.toUpperCase() + QUOTE; + } + if (!TextUtils.isEmpty(imageUrl)) { + if (URLUtil.isValidUrl(imageUrl)) { + headerInfo.image = (imageUrl); + } + } + return headerInfo; + } + + public interface ParserListener { + void onReceiveHeaderInfo(HeaderInfo headerInfo); + + void onErrorHeaderInfo(); + } + + public class HeaderInfo { + public String baseUrl; + public String title; + public String image; + } + + private class ThreadHeaderInfo extends AsyncTask { + protected HeaderInfo doInBackground(String... urls) { + try { + String url = urls[0]; + return parsePageHeaderInfo(url); + } catch (Exception e) { + Log.e(TAG, "ThreadHeaderInfo#parsePageHeaderInfo() failed." + e.getMessage()); + return null; + } + } + + protected void onPostExecute(HeaderInfo headerInfo) { + if (headerInfo != null) { + Log.i(TAG, "ThreadHeaderInfo#parsePageHeaderInfo() success." + headerInfo.title + " " + headerInfo.image); + parserListener.onReceiveHeaderInfo(headerInfo); + } else { + parserListener.onErrorHeaderInfo(); + } + } + } +} From b1bbcb39d58089bc90860eae8611ff25fd3ec111 Mon Sep 17 00:00:00 2001 From: torrentcome Date: Tue, 16 May 2017 10:43:32 +0200 Subject: [PATCH 08/11] (ComposeActivity) clean up, automatique format and implementation of - Share a link and extract the title, images, author's name #136 --- .../keylesspalace/tusky/ComposeActivity.java | 326 ++++++++++-------- 1 file changed, 177 insertions(+), 149 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java index f1e3eb342..7f7a31b96 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java @@ -24,7 +24,6 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; -import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; @@ -39,10 +38,8 @@ import android.os.Environment; import android.os.Parcel; import android.os.Parcelable; import android.provider.MediaStore; -import android.provider.OpenableColumns; import android.support.annotation.AttrRes; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.design.widget.Snackbar; import android.support.v13.view.inputmethod.InputConnectionCompat; @@ -56,6 +53,7 @@ import android.support.v7.widget.Toolbar; import android.text.Editable; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.URLSpan; import android.view.MenuItem; @@ -72,15 +70,17 @@ import android.widget.TextView; import com.keylesspalace.tusky.entity.Media; import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.fragment.ComposeOptionsFragment; -import com.keylesspalace.tusky.util.DownsizeImageTask; -import com.keylesspalace.tusky.view.EditTextTyped; import com.keylesspalace.tusky.util.CountUpDownLatch; +import com.keylesspalace.tusky.util.DownsizeImageTask; import com.keylesspalace.tusky.util.IOUtils; import com.keylesspalace.tusky.util.Log; +import com.keylesspalace.tusky.util.MediaUtils; +import com.keylesspalace.tusky.util.ParserUtils; import com.keylesspalace.tusky.util.SpanUtils; import com.keylesspalace.tusky.util.ThemeUtils; +import com.keylesspalace.tusky.view.EditTextTyped; +import com.squareup.picasso.Picasso; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -92,7 +92,6 @@ import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; -import java.util.Random; import butterknife.BindView; import butterknife.ButterKnife; @@ -103,17 +102,43 @@ import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -public class ComposeActivity extends BaseActivity implements ComposeOptionsFragment.Listener { +import static com.keylesspalace.tusky.util.MediaUtils.MEDIA_SIZE_UNKNOWN; +import static com.keylesspalace.tusky.util.MediaUtils.getMediaSize; +import static com.keylesspalace.tusky.util.MediaUtils.inputStreamGetBytes; +import static com.keylesspalace.tusky.util.StringUtils.carriageReturn; +import static com.keylesspalace.tusky.util.StringUtils.randomAlphanumericString; + +public class ComposeActivity extends BaseActivity implements ComposeOptionsFragment.Listener, ParserUtils.ParserListener { private static final String TAG = "ComposeActivity"; // logging tag private static final int STATUS_CHARACTER_LIMIT = 500; private static final int STATUS_MEDIA_SIZE_LIMIT = 4000000; // 4MB private static final int MEDIA_PICK_RESULT = 1; private static final int MEDIA_TAKE_PHOTO_RESULT = 2; private static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1; - private static final int MEDIA_SIZE_UNKNOWN = -1; private static final int COMPOSE_SUCCESS = -1; private static final int THUMBNAIL_SIZE = 128; // pixels - + @BindView(R.id.compose_edit_field) + EditTextTyped textEditor; + @BindView(R.id.compose_media_preview_bar) + LinearLayout mediaPreviewBar; + @BindView(R.id.compose_content_warning_bar) + View contentWarningBar; + @BindView(R.id.field_content_warning) + EditText contentWarningEditor; + @BindView(R.id.characters_left) + TextView charactersLeft; + @BindView(R.id.floating_btn) + Button floatingBtn; + @BindView(R.id.compose_photo_pick) + ImageButton pickBtn; + @BindView(R.id.compose_photo_take) + ImageButton takeBtn; + @BindView(R.id.action_toggle_nsfw) + Button nsfwBtn; + @BindView(R.id.postProgress) + ProgressBar postProgress; + @BindView(R.id.action_toggle_visibility) + ImageButton visibilityBtn; private String inReplyToId; private ArrayList mediaQueued; private CountUpDownLatch waitForMediaLatch; @@ -127,93 +152,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag private Uri photoUploadUri; // this only exists when a status is trying to be sent, but uploads are still occurring private ProgressDialog finishingUploadDialog; - @BindView(R.id.compose_edit_field) - EditTextTyped textEditor; - @BindView(R.id.compose_media_preview_bar) LinearLayout mediaPreviewBar; - @BindView(R.id.compose_content_warning_bar) View contentWarningBar; - @BindView(R.id.field_content_warning) EditText contentWarningEditor; - @BindView(R.id.characters_left) TextView charactersLeft; - @BindView(R.id.floating_btn) Button floatingBtn; - @BindView(R.id.compose_photo_pick) ImageButton pickBtn; - @BindView(R.id.compose_photo_take) ImageButton takeBtn; - @BindView(R.id.action_toggle_nsfw) Button nsfwBtn; - @BindView(R.id.postProgress) ProgressBar postProgress; - @BindView(R.id.action_toggle_visibility) ImageButton visibilityBtn; - private static class QueuedMedia { - enum Type { - IMAGE, - VIDEO - } - - enum ReadyStage { - DOWNSIZING, - UPLOADING - } - - Type type; - ImageView preview; - Uri uri; - String id; - Call uploadRequest; - URLSpan uploadUrl; - ReadyStage readyStage; - byte[] content; - long mediaSize; - - QueuedMedia(Type type, Uri uri, ImageView preview, long mediaSize) { - this.type = type; - this.uri = uri; - this.preview = preview; - this.mediaSize = mediaSize; - } - } - - /**This saves enough information to re-enqueue an attachment when restoring the activity. */ - private static class SavedQueuedMedia implements Parcelable { - QueuedMedia.Type type; - Uri uri; - Bitmap preview; - long mediaSize; - - SavedQueuedMedia(QueuedMedia.Type type, Uri uri, ImageView view, long mediaSize) { - this.type = type; - this.uri = uri; - this.preview = ((BitmapDrawable) view.getDrawable()).getBitmap(); - this.mediaSize = mediaSize; - } - - SavedQueuedMedia(Parcel parcel) { - type = (QueuedMedia.Type) parcel.readSerializable(); - uri = parcel.readParcelable(Uri.class.getClassLoader()); - preview = parcel.readParcelable(Bitmap.class.getClassLoader()); - mediaSize = parcel.readLong(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeSerializable(type); - dest.writeParcelable(uri, flags); - dest.writeParcelable(preview, flags); - dest.writeLong(mediaSize); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public SavedQueuedMedia createFromParcel(Parcel in) { - return new SavedQueuedMedia(in); - } - - public SavedQueuedMedia[] newArray(int size) { - return new SavedQueuedMedia[size]; - } - }; - } @Override public void onCreate(Bundle savedInstanceState) { @@ -337,6 +276,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag postProgress.setVisibility(View.INVISIBLE); updateNsfwButtonColor(); + final ParserUtils parser = new ParserUtils(this); + // Setup the main text field. setEditTextMimeTypes(null); // new String[] { "image/gif", "image/webp" } final int mentionColour = ThemeUtils.getColor(this, R.attr.compose_mention_color); @@ -348,7 +289,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag } @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } @Override public void afterTextChanged(Editable editable) { @@ -356,6 +298,13 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag } }); + textEditor.addOnPasteListener(new EditTextTyped.OnPasteListener() { + @Override + public void onPaste() { + parser.getPastedURLText(ComposeActivity.this); + } + }); + // Add any mentions to the text field when a reply is first composed. if (mentionedUsernames != null) { StringBuilder builder = new StringBuilder(); @@ -371,7 +320,8 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag // Initialise the content warning editor. contentWarningEditor.addTextChangedListener(new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { @@ -379,10 +329,11 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag } @Override - public void afterTextChanged(Editable s) {} + public void afterTextChanged(Editable s) { + } }); showContentWarning(startingHideText); - if(startingContentWarning != null){ + if (startingContentWarning != null) { contentWarningEditor.setText(startingContentWarning); } @@ -637,7 +588,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag } private boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, - String[] mimeTypes) { + String[] mimeTypes) { try { if (currentInputContentInfo != null) { currentInputContentInfo.releasePermission(); @@ -816,9 +767,9 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag private void onMediaPick() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { + != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, - new String[] { Manifest.permission.READ_EXTERNAL_STORAGE }, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE); } else { initiateMediaPicking(); @@ -827,7 +778,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag @Override public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], - @NonNull int[] grantResults) { + @NonNull int[] grantResults) { switch (requestCode) { case PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: { if (grantResults.length > 0 @@ -888,7 +839,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { intent.setType("image/* video/*"); } else { - String[] mimeTypes = new String[] { "image/*", "video/*" }; + String[] mimeTypes = new String[]{"image/*", "video/*"}; intent.setType("*/*"); intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes); } @@ -986,7 +937,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag } private void removeAllMediaFromQueue() { - for (Iterator it = mediaQueued.iterator(); it.hasNext();) { + for (Iterator it = mediaQueued.iterator(); it.hasNext(); ) { QueuedMedia item = it.next(); it.remove(); removeMediaFromQueue(item); @@ -1008,7 +959,7 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag public void onFailure() { onMediaDownsizeFailure(item); } - }).execute(item.uri); + }).execute(item.uri); } private void onMediaDownsizeFailure(QueuedMedia item) { @@ -1016,32 +967,6 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag removeMediaFromQueue(item); } - private static String randomAlphanumericString(int count) { - char[] chars = new char[count]; - Random random = new Random(); - final String POSSIBLE_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - for (int i = 0; i < count; i++) { - chars[i] = POSSIBLE_CHARS.charAt(random.nextInt(POSSIBLE_CHARS.length())); - } - return new String(chars); - } - - @Nullable - private static byte[] inputStreamGetBytes(InputStream stream) { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int read; - byte[] data = new byte[16384]; - try { - while ((read = stream.read(data, 0, data.length)) != -1) { - buffer.write(data, 0, read); - } - buffer.flush(); - } catch (IOException e) { - return null; - } - return buffer.toByteArray(); - } - private void uploadMedia(final QueuedMedia item) { item.readyStage = QueuedMedia.ReadyStage.UPLOADING; @@ -1136,20 +1061,6 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag } } - private static long getMediaSize(ContentResolver contentResolver, Uri uri) { - long mediaSize; - Cursor cursor = contentResolver.query(uri, null, null, null, null); - if (cursor != null) { - int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE); - cursor.moveToFirst(); - mediaSize = cursor.getLong(sizeIndex); - cursor.close(); - } else { - mediaSize = MEDIA_SIZE_UNKNOWN; - } - return mediaSize; - } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); @@ -1228,12 +1139,12 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag void showMarkSensitive(boolean show) { showMarkSensitive = show; - if(!showMarkSensitive) { + if (!showMarkSensitive) { statusMarkSensitive = false; nsfwBtn.setTextColor(ThemeUtils.getColor(this, R.attr.compose_nsfw_button_color)); } - if(show) { + if (show) { nsfwBtn.setVisibility(View.VISIBLE); } else { nsfwBtn.setVisibility(View.GONE); @@ -1260,4 +1171,121 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFrag return super.onOptionsItemSelected(item); } + + @Override + public void onReceiveHeaderInfo(ParserUtils.HeaderInfo headerInfo) { + if (!TextUtils.isEmpty(headerInfo.title)) { + cleanBaseUrl(headerInfo); + textEditor.append(headerInfo.title); + textEditor.append(carriageReturn); + textEditor.append(headerInfo.baseUrl); + } + if (!TextUtils.isEmpty(headerInfo.image)) { + Picasso.with(this).load(headerInfo.image).into(MediaUtils.picassoImageTarget(getApplicationContext(), new MediaUtils.MediaListener() { + @Override + public void onCallback(final Uri headerInfo) { + if (headerInfo != null) { + runOnUiThread(new Runnable() { + @Override + public void run() { + long mediaSize = getMediaSize(getContentResolver(), headerInfo); + pickMedia(headerInfo, mediaSize); + } + }); + } + } + })); + } + } + + // remove the precedent paste from the edit text + private void cleanBaseUrl(ParserUtils.HeaderInfo headerInfo) { + int lengthBaseUrl = headerInfo.baseUrl.length(); + int total = textEditor.getText().length(); + int indexSubString = total - lengthBaseUrl; + String text = textEditor.getText().toString(); + text = text.substring(0, indexSubString); + textEditor.setText(text); + } + + @Override + public void onErrorHeaderInfo() { + displayTransientError(R.string.error_generic); + } + + private static class QueuedMedia { + Type type; + ImageView preview; + Uri uri; + String id; + Call uploadRequest; + URLSpan uploadUrl; + ReadyStage readyStage; + byte[] content; + long mediaSize; + + QueuedMedia(Type type, Uri uri, ImageView preview, long mediaSize) { + this.type = type; + this.uri = uri; + this.preview = preview; + this.mediaSize = mediaSize; + } + + enum Type { + IMAGE, + VIDEO + } + + enum ReadyStage { + DOWNSIZING, + UPLOADING + } + } + + /** + * This saves enough information to re-enqueue an attachment when restoring the activity. + */ + private static class SavedQueuedMedia implements Parcelable { + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public SavedQueuedMedia createFromParcel(Parcel in) { + return new SavedQueuedMedia(in); + } + + public SavedQueuedMedia[] newArray(int size) { + return new SavedQueuedMedia[size]; + } + }; + QueuedMedia.Type type; + Uri uri; + Bitmap preview; + long mediaSize; + + SavedQueuedMedia(QueuedMedia.Type type, Uri uri, ImageView view, long mediaSize) { + this.type = type; + this.uri = uri; + this.preview = ((BitmapDrawable) view.getDrawable()).getBitmap(); + this.mediaSize = mediaSize; + } + + SavedQueuedMedia(Parcel parcel) { + type = (QueuedMedia.Type) parcel.readSerializable(); + uri = parcel.readParcelable(Uri.class.getClassLoader()); + preview = parcel.readParcelable(Bitmap.class.getClassLoader()); + mediaSize = parcel.readLong(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeSerializable(type); + dest.writeParcelable(uri, flags); + dest.writeParcelable(preview, flags); + dest.writeLong(mediaSize); + } + } } From 418fbd3b5c0d36b4a3231e41bff78decd7cab9b1 Mon Sep 17 00:00:00 2001 From: torrentcome Date: Tue, 16 May 2017 17:56:35 +0200 Subject: [PATCH 09/11] (share) add share functionality - get the text shared and put it on the Clipboard - pass by the same way that past for Download the information --- .../main/java/com/keylesspalace/tusky/ComposeActivity.java | 3 +++ .../main/java/com/keylesspalace/tusky/util/ParserUtils.java | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java index 7f7a31b96..29ff64b09 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java @@ -390,6 +390,9 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm int left = Math.min(start, end); int right = Math.max(start, end); textEditor.getText().replace(left, right, text, 0, text.length()); + + parser.putInClipboardManager(this, text); + textEditor.onPaste(); } } } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java index 215765261..9c1eed333 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java @@ -43,6 +43,12 @@ public class ParserUtils { return null; } + public void putInClipboardManager(Context context, String string) { + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("", string); + clipboard.setPrimaryClip(clip); + } + // parse the HTML page private HeaderInfo parsePageHeaderInfo(String urlStr) throws Exception { Connection con = Jsoup.connect(urlStr); From 7cc06d3ad008d68e7a295a8b28f9f9576f5176be Mon Sep 17 00:00:00 2001 From: torrentcome Date: Wed, 17 May 2017 16:06:37 +0200 Subject: [PATCH 10/11] (bug fixing) When we share by an app : the text shared is not just an URL but a small text with the URL inside. So we parse the text until find an url. Take the first one and send it to the parse --- .../keylesspalace/tusky/util/ParserUtils.java | 16 ++++++++++------ .../keylesspalace/tusky/util/StringUtils.java | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java index 9c1eed333..80a932f65 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/ParserUtils.java @@ -13,6 +13,8 @@ import org.jsoup.helper.HttpConnection; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; +import java.util.List; + import static com.keylesspalace.tusky.util.StringUtils.QUOTE; /** @@ -35,9 +37,13 @@ public class ParserUtils { ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0); pasteData = item.getText().toString(); - // we have to find an url for start it - if (URLUtil.isValidUrl(pasteData)) { - new ThreadHeaderInfo().execute(pasteData); + // If we share with an app, it's not only an url + List strings = StringUtils.extractUrl(pasteData); + String url = strings.get(0); // we assume that the first url is the good one + if (strings.size() > 0) { + if (URLUtil.isValidUrl(url)) { + new ThreadHeaderInfo().execute(url); + } } } return null; @@ -77,9 +83,7 @@ public class ParserUtils { headerInfo.title = QUOTE + text.toUpperCase() + QUOTE; } if (!TextUtils.isEmpty(imageUrl)) { - if (URLUtil.isValidUrl(imageUrl)) { - headerInfo.image = (imageUrl); - } + headerInfo.image = (imageUrl); } return headerInfo; } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.java index ff050f2c7..1d9097515 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.java @@ -1,6 +1,11 @@ package com.keylesspalace.tusky.util; +import android.util.Patterns; + +import java.util.ArrayList; +import java.util.List; import java.util.Random; +import java.util.regex.Matcher; public class StringUtils { @@ -16,4 +21,14 @@ public class StringUtils { } return new String(chars); } + + static List extractUrl(String text) { + List links = new ArrayList<>(); + Matcher m = Patterns.WEB_URL.matcher(text); + while (m.find()) { + String url = m.group(); + links.add(url); + } + return links; + } } From b9d460e71275d819cd5b4e9a6513512fdb385030 Mon Sep 17 00:00:00 2001 From: torrentcome Date: Wed, 17 May 2017 16:08:43 +0200 Subject: [PATCH 11/11] (bug of picasso) the Target wasn't load at the first time forget to read the documentation so , record the target in field change the way that works. Now work fine. --- .../keylesspalace/tusky/ComposeActivity.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java index 29ff64b09..6a5cb8b33 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java @@ -80,6 +80,7 @@ import com.keylesspalace.tusky.util.SpanUtils; import com.keylesspalace.tusky.util.ThemeUtils; import com.keylesspalace.tusky.view.EditTextTyped; import com.squareup.picasso.Picasso; +import com.squareup.picasso.Target; import java.io.File; import java.io.FileNotFoundException; @@ -153,6 +154,11 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm // this only exists when a status is trying to be sent, but uploads are still occurring private ProgressDialog finishingUploadDialog; + /** + * The Target object must be stored as a member field or method and cannot be an anonymous class otherwise this won't work as expected. The reason is that Picasso accepts this parameter as a weak memory reference. Because anonymous classes are eligible for garbage collection when there are no more references, the network request to fetch the image may finish after this anonymous class has already been reclaimed. See this Stack Overflow discussion for more details. + */ + @SuppressWarnings("FieldCanBeLocal") + private Target target; @Override public void onCreate(Bundle savedInstanceState) { @@ -1184,7 +1190,15 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm textEditor.append(headerInfo.baseUrl); } if (!TextUtils.isEmpty(headerInfo.image)) { - Picasso.with(this).load(headerInfo.image).into(MediaUtils.picassoImageTarget(getApplicationContext(), new MediaUtils.MediaListener() { + Picasso.Builder builder = new Picasso.Builder(getApplicationContext()); + builder.listener(new Picasso.Listener() { + @Override + public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) { + exception.printStackTrace(); + } + }); + + target = MediaUtils.picassoImageTarget(ComposeActivity.this, new MediaUtils.MediaListener() { @Override public void onCallback(final Uri headerInfo) { if (headerInfo != null) { @@ -1197,10 +1211,12 @@ public class ComposeActivity extends BaseActivity implements ComposeOptionsFragm }); } } - })); + }); + Picasso.with(this).load(headerInfo.image).into(target); } } + // remove the precedent paste from the edit text private void cleanBaseUrl(ParserUtils.HeaderInfo headerInfo) { int lengthBaseUrl = headerInfo.baseUrl.length();