From a44f7ead58d242713da821d21ab61d69d6403bcb Mon Sep 17 00:00:00 2001 From: Sanjay Developer Date: Wed, 6 Jan 2021 16:40:39 +0530 Subject: [PATCH] Migrated to Kotlin * Upgraded java to 1.8 * Added support for Fragments * Made InstaImage.kt as functional Interface --- app/build.gradle | 4 ++ .../sanjaydevtech/instarepost/MainActivity.kt | 1 - .../instarepost/SecondActivity.java | 45 ++++++-------- instautils/build.gradle | 8 +-- .../instautils/InstaDownloader.kt | 60 ++++++++++++------- .../sanjaydevtech/instautils/InstaImage.kt | 5 +- .../com/sanjaydevtech/instautils/InstaPost.kt | 12 ++++ .../sanjaydevtech/instautils/InstaScraper.kt | 30 ++++++---- 8 files changed, 99 insertions(+), 66 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8a2953c..3b0c315 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,6 +22,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { diff --git a/app/src/main/java/com/sanjaydevtech/instarepost/MainActivity.kt b/app/src/main/java/com/sanjaydevtech/instarepost/MainActivity.kt index 3570d83..1f22dda 100644 --- a/app/src/main/java/com/sanjaydevtech/instarepost/MainActivity.kt +++ b/app/src/main/java/com/sanjaydevtech/instarepost/MainActivity.kt @@ -9,7 +9,6 @@ import android.widget.ImageView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.sanjaydevtech.instautils.InstaDownloader -import com.sanjaydevtech.instautils.InstaResponse import com.sanjaydevtech.instautils.InstaScraper import com.sanjaydevtech.instautils.InstaTask import java.util.regex.Pattern diff --git a/app/src/main/java/com/sanjaydevtech/instarepost/SecondActivity.java b/app/src/main/java/com/sanjaydevtech/instarepost/SecondActivity.java index 514933a..f28ddab 100644 --- a/app/src/main/java/com/sanjaydevtech/instarepost/SecondActivity.java +++ b/app/src/main/java/com/sanjaydevtech/instarepost/SecondActivity.java @@ -1,15 +1,14 @@ package com.sanjaydevtech.instarepost; -import androidx.appcompat.app.AppCompatActivity; - import android.os.Bundle; import android.util.Log; -import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.Toast; +import androidx.appcompat.app.AppCompatActivity; + import com.sanjaydevtech.instautils.InstaDownloader; import com.sanjaydevtech.instautils.InstaPost; import com.sanjaydevtech.instautils.InstaResponse; @@ -34,39 +33,31 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); - downloader = new InstaDownloader(this, new InstaResponse() { - @Override - public void onResponse(@NotNull InstaTask instaTask) { - onResponseMethod(instaTask); - } - }); + downloader = new InstaDownloader(this, instaTask -> + onResponseMethod(instaTask) + ); final EditText urlTxt = findViewById(R.id.urlTxt); final Button doneBtn = findViewById(R.id.doneBtn); img = findViewById(R.id.imageView); - doneBtn.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Pattern pattern = Pattern.compile(URL_PATTERN); - Matcher matcher = pattern.matcher(urlTxt.getText().toString()); + doneBtn.setOnClickListener(view -> { + Pattern pattern = Pattern.compile(URL_PATTERN); + Matcher matcher = pattern.matcher(urlTxt.getText().toString()); + if (matcher.find()) { + downloader.get(urlTxt.getText().toString()); // Request the post data + } else { + pattern = Pattern.compile(DP_URL_PATTERN); + matcher = pattern.matcher(urlTxt.getText().toString()); if (matcher.find()) { - downloader.get(urlTxt.getText().toString()); // Request the post data + InstaScraper.getDP(SecondActivity.this, urlTxt.getText().toString(), instaTask -> + onResponseMethod(instaTask) + ); } else { - pattern = Pattern.compile(DP_URL_PATTERN); - matcher = pattern.matcher(urlTxt.getText().toString()); - if(matcher.find()) { - InstaScraper.getDP(SecondActivity.this, urlTxt.getText().toString(), new InstaResponse() { - @Override - public void onResponse(@NotNull InstaTask instaTask) { - onResponseMethod(instaTask); - } - }); - } else { - Toast.makeText(SecondActivity.this, "Invalid insta url", Toast.LENGTH_SHORT).show(); - } + Toast.makeText(SecondActivity.this, "Invalid insta url", Toast.LENGTH_SHORT).show(); } } + }); } diff --git a/instautils/build.gradle b/instautils/build.gradle index 26c8b39..a00bacd 100644 --- a/instautils/build.gradle +++ b/instautils/build.gradle @@ -53,13 +53,13 @@ android { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.3.2' def coroutines_version = "1.4.2" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" + api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" + api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" def lifecycle_version = "2.2.0" - implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" + api "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" implementation fileTree(dir: "libs", include: ["*.jar"]) implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' diff --git a/instautils/src/main/java/com/sanjaydevtech/instautils/InstaDownloader.kt b/instautils/src/main/java/com/sanjaydevtech/instautils/InstaDownloader.kt index 34c8136..f007ef8 100644 --- a/instautils/src/main/java/com/sanjaydevtech/instautils/InstaDownloader.kt +++ b/instautils/src/main/java/com/sanjaydevtech/instautils/InstaDownloader.kt @@ -1,13 +1,17 @@ package com.sanjaydevtech.instautils +import android.content.Context import android.graphics.Bitmap import android.graphics.drawable.Drawable +import android.util.Log import android.widget.ImageView +import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.lifecycle.lifecycleScope import com.bumptech.glide.Glide import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.transition.Transition +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -18,15 +22,12 @@ import java.io.IOException * Downloader Class to download insta posts * * @author Sanjay Developer - * @version 1.0.2 + * @version 1.1.0 */ -class InstaDownloader(private val activity: FragmentActivity, private val response: InstaResponse) { +class InstaDownloader(private val context: Context?, private val scope: CoroutineScope, private val response: InstaResponse) { - constructor(activity: FragmentActivity, response: (InstaTask) -> Unit) : this(activity, object : InstaResponse { - override fun onResponse(instaTask: InstaTask) { - response(instaTask) - } - }) + constructor(activity: FragmentActivity, response: InstaResponse) : this(activity, activity.lifecycleScope, response) + constructor(fragment: Fragment, response: InstaResponse) : this(fragment.context, fragment.viewLifecycleOwner.lifecycleScope, response) /** * Get the url of the post @@ -34,7 +35,7 @@ class InstaDownloader(private val activity: FragmentActivity, private val respon * @param url URL of that post */ fun get(url: String) { - activity.lifecycleScope.launch(Dispatchers.IO) { + scope.launch(Dispatchers.IO) { try { val document = Jsoup.connect(url).userAgent("Mozilla/5.0").get() val metas = document.getElementsByTag("meta") @@ -78,6 +79,15 @@ class InstaDownloader(private val activity: FragmentActivity, private val respon } } + /** + * A Kotlin Extension function to set image + * + * @param post InstaPost instance + */ + fun ImageView.setImage(post: InstaPost) { + setImage(post, this) + } + /** * Retrieve the bitmap of the image post or thumbnail of video post * @@ -86,16 +96,20 @@ class InstaDownloader(private val activity: FragmentActivity, private val respon */ fun getBitmap(post: InstaPost, instaImage: InstaImage) { val imgUrl = post.thumbnailUrl - Glide.with(activity) - .asBitmap() - .load(imgUrl) - .into(object : CustomTarget() { - override fun onResourceReady(resource: Bitmap, transition: Transition?) { - instaImage.onBitmapLoaded(resource) - } + context?.let { + Glide.with(it) + .asBitmap() + .load(imgUrl) + .into(object : CustomTarget() { + override fun onResourceReady(resource: Bitmap, transition: Transition?) { + instaImage.onBitmapLoaded(resource) + } - override fun onLoadCleared(placeholder: Drawable?) {} - }) + override fun onLoadCleared(placeholder: Drawable?) {} + }) + } ?: run { + Log.e(TAG, "method: getBitmap can't set image.. [REASON] Context is null") + } } /** @@ -106,12 +120,16 @@ class InstaDownloader(private val activity: FragmentActivity, private val respon */ fun setImage(post: InstaPost, imageView: ImageView) { val imgUrl = post.thumbnailUrl - Glide.with(activity) - .load(imgUrl) - .into(imageView) + context?.let { + Glide.with(it) + .load(imgUrl) + .into(imageView) + } ?: run { + Log.e(TAG, "method: setImage can't set image.. [REASON] Context is null") + } } companion object { - private val TAG = InstaDownloader::class.java.simpleName + private val TAG = InstaDownloader::class.simpleName } } \ No newline at end of file diff --git a/instautils/src/main/java/com/sanjaydevtech/instautils/InstaImage.kt b/instautils/src/main/java/com/sanjaydevtech/instautils/InstaImage.kt index 64316ef..b022423 100644 --- a/instautils/src/main/java/com/sanjaydevtech/instautils/InstaImage.kt +++ b/instautils/src/main/java/com/sanjaydevtech/instautils/InstaImage.kt @@ -2,10 +2,9 @@ package com.sanjaydevtech.instautils import android.graphics.Bitmap -/** - * InstaImage +/** InstaImage */ -interface InstaImage { +fun interface InstaImage { /** * OnBitmap loaded * diff --git a/instautils/src/main/java/com/sanjaydevtech/instautils/InstaPost.kt b/instautils/src/main/java/com/sanjaydevtech/instautils/InstaPost.kt index f5101ea..6ce74d3 100644 --- a/instautils/src/main/java/com/sanjaydevtech/instautils/InstaPost.kt +++ b/instautils/src/main/java/com/sanjaydevtech/instautils/InstaPost.kt @@ -2,6 +2,13 @@ package com.sanjaydevtech.instautils /** * InstaPost Object + * + * [url] holds the actual image or video url + * + * [type] may be constants [INSTA_IMAGE] or [INSTA_VIDEO] or [INSTA_PROFILE] + * + * [thumbnailUrl] is the same as url for type [INSTA_IMAGE], + * but a low res image for [INSTA_VIDEO] and [INSTA_PROFILE] */ data class InstaPost internal constructor( val url: String, @@ -9,8 +16,13 @@ data class InstaPost internal constructor( val thumbnailUrl: String) { companion object { + /** InstaPost object is from a Image */ const val INSTA_IMAGE = 0 + + /** InstaPost object is from a Video */ const val INSTA_VIDEO = 1 + + /** InstaPost object is from a Instagram Profile */ const val INSTA_PROFILE = 2 } } \ No newline at end of file diff --git a/instautils/src/main/java/com/sanjaydevtech/instautils/InstaScraper.kt b/instautils/src/main/java/com/sanjaydevtech/instautils/InstaScraper.kt index 77f7cbb..b93d8f6 100644 --- a/instautils/src/main/java/com/sanjaydevtech/instautils/InstaScraper.kt +++ b/instautils/src/main/java/com/sanjaydevtech/instautils/InstaScraper.kt @@ -1,7 +1,9 @@ package com.sanjaydevtech.instautils +import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -18,26 +20,34 @@ object InstaScraper { private const val PROFILE_HD_PATTERN = "\"profile_pic_url_hd\":\"([^\"]*)\"" private const val PROFILE_PATTERN = "\"profile_pic_url\":\"([^\"]*)\"" + /** + * To retrieve Instagram profile + * + * @param activity Activity + * @param url Url of the instagram profile + * @param response InstaResponse instance + */ @JvmStatic - fun getDP(activity: FragmentActivity, url: String, response: (InstaTask) -> Unit) { - getDP(activity, url, object : InstaResponse { - override fun onResponse(instaTask: InstaTask) { - response(instaTask) - } - }) + fun getDP(activity: FragmentActivity, url: String, response: InstaResponse) { + getDP(activity.lifecycleScope, url, response) } /** * To retrieve Instagram profile * - * @param activity Current activity + * @param fragment Fragment * @param url Url of the instagram profile * @param response InstaResponse instance - * @throws IllegalArgumentException Throws if no InstaResponse is attached */ @JvmStatic - fun getDP(activity: FragmentActivity, url: String, response: InstaResponse) { - activity.lifecycleScope.launch(Dispatchers.IO) { + fun getDP(fragment: Fragment, url: String, response: InstaResponse) { + getDP(fragment.viewLifecycleOwner.lifecycleScope, url, response) + } + + + @JvmStatic + private fun getDP(scope: CoroutineScope, url: String, response: InstaResponse) { + scope.launch(Dispatchers.IO) { try { val document = Jsoup.connect(url).userAgent("Mozilla/5.0").get() val scripts = document.getElementsByTag("script")