From 1bf8a578bca744d1dcff3b520686ea0384a54682 Mon Sep 17 00:00:00 2001 From: Amine Bou Date: Sun, 3 Dec 2017 22:09:58 +0100 Subject: [PATCH] Simple view pager. Closes #50. --- app/build.gradle | 5 +- .../bou/readerforselfoss/ReaderActivity.kt | 206 ++------------- .../adapters/ItemCardAdapter.kt | 6 +- .../adapters/ItemListAdapter.kt | 12 +- .../fragments/ArticleFragment.kt | 241 ++++++++++++++++++ .../bou/readerforselfoss/utils/LinksUtils.kt | 33 +-- app/src/main/res/layout/activity_reader.xml | 152 ++--------- app/src/main/res/layout/fragment_article.xml | 146 +++++++++++ 8 files changed, 439 insertions(+), 362 deletions(-) create mode 100644 app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt create mode 100644 app/src/main/res/layout/fragment_article.xml diff --git a/app/build.gradle b/app/build.gradle index 940fcc0..b7a57e2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -122,7 +122,7 @@ dependencies { compile 'com.google.firebase:firebase-core:11.4.2' compile 'com.google.firebase:firebase-config:11.4.2' compile 'com.google.firebase:firebase-invites:11.4.2' - compile('com.crashlytics.sdk.android:crashlytics:2.7.1@aar') { + compile('com.crashlytics.sdk.android:crashlytics:2.8.0@aar') { transitive = true; } @@ -170,6 +170,9 @@ dependencies { compile 'com.heinrichreimersoftware:android-issue-reporter:1.3.1' compile 'com.github.rubensousa:floatingtoolbar:1.5.1' + + // Pager + compile 'me.relex:circleindicator:1.2.2@aar' } apply plugin: 'com.google.gms.google-services' diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt index ebb2d57..b00b196 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt @@ -1,209 +1,39 @@ package apps.amine.bou.readerforselfoss -import android.content.SharedPreferences import android.os.Bundle -import android.preference.PreferenceManager -import android.support.customtabs.CustomTabsIntent -import android.support.design.widget.FloatingActionButton -import android.support.v4.widget.NestedScrollView +import android.support.v4.app.FragmentManager +import android.support.v4.app.FragmentStatePagerAdapter import android.support.v7.app.AppCompatActivity -import android.text.Html -import android.text.method.LinkMovementMethod -import android.view.MenuItem -import android.view.View -import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi -import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent -import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent -import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper -import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString -import apps.amine.bou.readerforselfoss.utils.openItemUrl -import apps.amine.bou.readerforselfoss.utils.shareLink -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.crashlytics.android.Crashlytics -import com.ftinc.scoop.Scoop -import com.github.rubensousa.floatingtoolbar.FloatingToolbar +import apps.amine.bou.readerforselfoss.api.selfoss.Item +import apps.amine.bou.readerforselfoss.fragments.ArticleFragment import kotlinx.android.synthetic.main.activity_reader.* -import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import me.relex.circleindicator.CircleIndicator class ReaderActivity : AppCompatActivity() { - private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper - //private lateinit var content: HtmlTextView - private lateinit var url: String - private lateinit var contentText: String - private lateinit var contentSource: String - private lateinit var contentImage: String - private lateinit var contentTitle: String - private lateinit var fab: FloatingActionButton - override fun onStop() { - super.onStop() - mCustomTabActivityHelper.unbindCustomTabsService(this) - } + private lateinit var allItems: ArrayList override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - Scoop.getInstance().apply(this) setContentView(R.layout.activity_reader) - url = intent.getStringExtra("url") - contentText = intent.getStringExtra("content") - contentTitle = intent.getStringExtra("title") - contentImage = intent.getStringExtra("image") - contentSource = intent.getStringExtra("source") + allItems = intent.getParcelableArrayListExtra("allItems") + val currentItem = intent.getIntExtra("currentItem", 0) - fab = findViewById(R.id.fab) - val mFloatingToolbar: FloatingToolbar = findViewById(R.id.floatingToolbar) - mFloatingToolbar.attachFab(fab) + var adapter = ScreenSlidePagerAdapter(supportFragmentManager) + pager.adapter = adapter + pager.currentItem = currentItem - val customTabsIntent = this@ReaderActivity.buildCustomTabsIntent() - mCustomTabActivityHelper = CustomTabActivityHelper() - mCustomTabActivityHelper.bindCustomTabsService(this) + (indicator as CircleIndicator).setViewPager(pager) + } - val prefs = PreferenceManager.getDefaultSharedPreferences(this) - - mFloatingToolbar.setClickListener(object : FloatingToolbar.ItemClickListener { - override fun onItemClick(item: MenuItem) { - when (item.itemId) { - R.id.more_action -> getContentFromMercury(customTabsIntent, prefs) - R.id.share_action -> this@ReaderActivity.shareLink(url) - R.id.open_action -> this@ReaderActivity.openItemUrl( - url, - contentText, - contentImage, - contentTitle, - contentSource, - customTabsIntent, - false, - false, - this@ReaderActivity - ) - else -> Unit - } - } - - override fun onItemLongClick(item: MenuItem?) { - } - }) - - - if (contentText.isEmptyOrNullOrNullString()) { - getContentFromMercury(customTabsIntent, prefs) - } else { - source.text = contentSource - titleView.text = contentTitle - tryToHandleHtml(contentText, customTabsIntent, prefs) - - if (!contentImage.isEmptyOrNullOrNullString()) { - imageView.visibility = View.VISIBLE - Glide - .with(baseContext) - .asBitmap() - .load(contentImage) - .apply(RequestOptions.fitCenterTransform()) - .into(imageView) - } else { - imageView.visibility = View.GONE - } + private inner class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { + override fun getCount(): Int { + return allItems.size } - nestedScrollView.setOnScrollChangeListener( - NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY -> - if (scrollY > oldScrollY) { - fab.hide() - } else { - if (mFloatingToolbar.isShowing) mFloatingToolbar.hide() else fab.show() - } - } - ) - - content.movementMethod = LinkMovementMethod.getInstance() - } - - private fun getContentFromMercury( - customTabsIntent: CustomTabsIntent, - prefs: SharedPreferences - ) { - progressBar.visibility = View.VISIBLE - val parser = MercuryApi( - BuildConfig.MERCURY_KEY, - prefs.getBoolean("should_log_everything", false) - ) - - parser.parseUrl(url).enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.body() != null && response.body()!!.content != null && response.body()!!.content.isNotEmpty()) { - source.text = response.body()!!.domain - titleView.text = response.body()!!.title - this@ReaderActivity.url = response.body()!!.url - - if (response.body()!!.content != null && !response.body()!!.content.isEmpty()) { - tryToHandleHtml(response.body()!!.content, customTabsIntent, prefs) - } - - if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isEmpty()) { - imageView.visibility = View.VISIBLE - Glide - .with(baseContext) - .asBitmap() - .load(response.body()!!.lead_image_url) - .apply(RequestOptions.fitCenterTransform()) - .into(imageView) - } else { - imageView.visibility = View.GONE - } - - nestedScrollView.scrollTo(0, 0) - - progressBar.visibility = View.GONE - } else { - openInBrowserAfterFailing(customTabsIntent) - } - } - - override fun onFailure( - call: Call, - t: Throwable - ) = openInBrowserAfterFailing(customTabsIntent) - }) - } - - private fun tryToHandleHtml( - c: String, - customTabsIntent: CustomTabsIntent, - prefs: SharedPreferences - ) { - try { - content.text = Html.fromHtml(c, HtmlHttpImageGetter(content, null, true), null) - - //content.setHtml(response.body()!!.content, HtmlHttpImageGetter(content, null, true)) - } catch (e: Exception) { - Crashlytics.setUserIdentifier(prefs.getString("unique_id", "")) - Crashlytics.log(100, "CANT_TRANSFORM_TO_HTML", e.message) - Crashlytics.logException(e) - openInBrowserAfterFailing(customTabsIntent) + override fun getItem(position: Int): ArticleFragment { + return ArticleFragment.newInstance(position, allItems) } } - - private fun openInBrowserAfterFailing(customTabsIntent: CustomTabsIntent) { - progressBar.visibility = View.GONE - this@ReaderActivity.openItemUrl( - url, - contentText, - contentImage, - contentTitle, - contentSource, - customTabsIntent, - true, - false, - this@ReaderActivity - ) - finish() - } } diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemCardAdapter.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemCardAdapter.kt index ecfe7c7..c46f73c 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemCardAdapter.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemCardAdapter.kt @@ -255,11 +255,9 @@ class ItemCardAdapter( mView.setOnClickListener { c.openItemUrl( + items, + adapterPosition, items[adapterPosition].getLinkDecoded(), - items[adapterPosition].content, - items[adapterPosition].getThumbnail(c), - items[adapterPosition].title, - items[adapterPosition].sourceAndDateText(), customTabsIntent, internalBrowser, articleViewer, diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemListAdapter.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemListAdapter.kt index 8815d5e..8aff5b6 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemListAdapter.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemListAdapter.kt @@ -273,11 +273,9 @@ class ItemListAdapter( if (!clickBehavior) { mView.setOnClickListener { c.openItemUrl( + items, + adapterPosition, items[adapterPosition].getLinkDecoded(), - items[adapterPosition].content, - items[adapterPosition].getThumbnail(c), - items[adapterPosition].title, - items[adapterPosition].sourceAndDateText(), customTabsIntent, internalBrowser, articleViewer, @@ -292,11 +290,9 @@ class ItemListAdapter( mView.setOnClickListener { actionBarShowHide() } mView.setOnLongClickListener { c.openItemUrl( + items, + adapterPosition, items[adapterPosition].getLinkDecoded(), - items[adapterPosition].content, - items[adapterPosition].getThumbnail(c), - items[adapterPosition].title, - items[adapterPosition].sourceAndDateText(), customTabsIntent, internalBrowser, articleViewer, diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt new file mode 100644 index 0000000..3f6cd77 --- /dev/null +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt @@ -0,0 +1,241 @@ +package apps.amine.bou.readerforselfoss.fragments + +import android.content.SharedPreferences +import android.os.Bundle +import android.preference.PreferenceManager +import android.support.customtabs.CustomTabsIntent +import android.support.design.widget.FloatingActionButton +import android.support.v4.app.Fragment +import android.support.v4.widget.NestedScrollView +import android.text.Html +import android.text.method.LinkMovementMethod +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import apps.amine.bou.readerforselfoss.BuildConfig +import apps.amine.bou.readerforselfoss.R +import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi +import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent +import apps.amine.bou.readerforselfoss.api.selfoss.Item +import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent +import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper +import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString +import apps.amine.bou.readerforselfoss.utils.openItemUrl +import apps.amine.bou.readerforselfoss.utils.shareLink +import apps.amine.bou.readerforselfoss.utils.sourceAndDateText +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.crashlytics.android.Crashlytics +import com.github.rubensousa.floatingtoolbar.FloatingToolbar +import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + + +import kotlinx.android.synthetic.main.fragment_article.view.* + +class ArticleFragment : Fragment() { + private lateinit var pageNumber: Number + private lateinit var allItems: ArrayList + private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper + //private lateinit var content: HtmlTextView + private lateinit var url: String + private lateinit var contentText: String + private lateinit var contentSource: String + private lateinit var contentImage: String + private lateinit var contentTitle: String + private lateinit var fab: FloatingActionButton + + override fun onStop() { + super.onStop() + mCustomTabActivityHelper.unbindCustomTabsService(activity) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + pageNumber = arguments!!.getInt(ARG_POSITION) + allItems = arguments!!.getParcelableArrayList(ARG_ITEMS) + } + + private lateinit var rootView: ViewGroup + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + rootView = inflater + .inflate(R.layout.fragment_article, container, false) as ViewGroup + + url = allItems[pageNumber.toInt()].getLinkDecoded() + contentText = allItems[pageNumber.toInt()].content + contentTitle = allItems[pageNumber.toInt()].title + contentImage = allItems[pageNumber.toInt()].getThumbnail(activity!!) + contentSource = allItems[pageNumber.toInt()].sourceAndDateText() + + fab = rootView.fab + val mFloatingToolbar: FloatingToolbar = rootView.floatingToolbar + mFloatingToolbar.attachFab(fab) + + val customTabsIntent = activity!!.buildCustomTabsIntent() + mCustomTabActivityHelper = CustomTabActivityHelper() + mCustomTabActivityHelper.bindCustomTabsService(activity) + + val prefs = PreferenceManager.getDefaultSharedPreferences(activity) + + mFloatingToolbar.setClickListener(object : FloatingToolbar.ItemClickListener { + override fun onItemClick(item: MenuItem) { + when (item.itemId) { + R.id.more_action -> getContentFromMercury(customTabsIntent, prefs) + R.id.share_action -> activity!!.shareLink(url) + R.id.open_action -> activity!!.openItemUrl( + allItems, + pageNumber.toInt(), + url, + customTabsIntent, + false, + false, + activity!! + ) + else -> Unit + } + } + + override fun onItemLongClick(item: MenuItem?) { + } + }) + + + if (contentText.isEmptyOrNullOrNullString()) { + getContentFromMercury(customTabsIntent, prefs) + } else { + rootView.source.text = contentSource + rootView.titleView.text = contentTitle + tryToHandleHtml(contentText, customTabsIntent, prefs) + + if (!contentImage.isEmptyOrNullOrNullString()) { + rootView.imageView.visibility = View.VISIBLE + Glide + .with(activity!!.baseContext) + .asBitmap() + .load(contentImage) + .apply(RequestOptions.fitCenterTransform()) + .into(rootView.imageView) + } else { + rootView.imageView.visibility = View.GONE + } + } + + rootView.nestedScrollView.setOnScrollChangeListener( + NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY -> + if (scrollY > oldScrollY) { + fab.hide() + } else { + if (mFloatingToolbar.isShowing) mFloatingToolbar.hide() else fab.show() + } + } + ) + + rootView.content.movementMethod = LinkMovementMethod.getInstance() + + return rootView + } + + private fun getContentFromMercury( + customTabsIntent: CustomTabsIntent, + prefs: SharedPreferences + ) { + rootView.progressBar.visibility = View.VISIBLE + val parser = MercuryApi( + BuildConfig.MERCURY_KEY, + prefs.getBoolean("should_log_everything", false) + ) + + parser.parseUrl(url).enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.body() != null && response.body()!!.content != null && response.body()!!.content.isNotEmpty()) { + rootView.source.text = response.body()!!.domain + rootView.titleView.text = response.body()!!.title + url = response.body()!!.url + + if (response.body()!!.content != null && !response.body()!!.content.isEmpty()) { + tryToHandleHtml(response.body()!!.content, customTabsIntent, prefs) + } + + if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isEmpty()) { + rootView.imageView.visibility = View.VISIBLE + Glide + .with(activity!!.baseContext) + .asBitmap() + .load(response.body()!!.lead_image_url) + .apply(RequestOptions.fitCenterTransform()) + .into(rootView.imageView) + } else { + rootView.imageView.visibility = View.GONE + } + + rootView.nestedScrollView.scrollTo(0, 0) + + rootView.progressBar.visibility = View.GONE + } else { + openInBrowserAfterFailing(customTabsIntent) + } + } + + override fun onFailure( + call: Call, + t: Throwable + ) = openInBrowserAfterFailing(customTabsIntent) + }) + } + + private fun tryToHandleHtml( + c: String, + customTabsIntent: CustomTabsIntent, + prefs: SharedPreferences + ) { + try { + rootView.content.text = Html.fromHtml(c, HtmlHttpImageGetter(rootView.content, null, true), null) + + //content.setHtml(response.body()!!.content, HtmlHttpImageGetter(content, null, true)) + } catch (e: Exception) { + Crashlytics.setUserIdentifier(prefs.getString("unique_id", "")) + Crashlytics.log(100, "CANT_TRANSFORM_TO_HTML", e.message) + Crashlytics.logException(e) + openInBrowserAfterFailing(customTabsIntent) + } + } + + private fun openInBrowserAfterFailing(customTabsIntent: CustomTabsIntent) { + rootView.progressBar.visibility = View.GONE + activity!!.openItemUrl( + allItems, + pageNumber.toInt(), + url, + customTabsIntent, + true, + false, + activity!! + ) + } + + + companion object { + private val ARG_POSITION = "position" + private val ARG_ITEMS = "items" + + fun newInstance(position: Int, allItems: ArrayList): ArticleFragment { + val fragment = ArticleFragment() + val args = Bundle() + args.putInt(ARG_POSITION, position) + args.putParcelableArrayList(ARG_ITEMS, allItems) + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/LinksUtils.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/LinksUtils.kt index 216ca00..ae990a9 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/LinksUtils.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/LinksUtils.kt @@ -59,30 +59,17 @@ fun Context.buildCustomTabsIntent(): CustomTabsIntent { } fun Context.openItemUrlInternally( + allItems: ArrayList, + currentItem: Int, linkDecoded: String, - content: String, - image: String, - title: String, - source: String, customTabsIntent: CustomTabsIntent, articleViewer: Boolean, app: Activity ) { if (articleViewer) { val intent = Intent(this, ReaderActivity::class.java) - - /*DragDismissIntentBuilder(this) - .setFullscreenOnTablets(true) // defaults to false, tablets will have padding on each side - .setDragElasticity(DragDismissIntentBuilder.DragElasticity.NORMAL) // Larger elasticities will make it easier to dismiss. - .setDrawUnderStatusBar(true) - .build(intent)*/ - - - intent.putExtra("url", linkDecoded) - intent.putExtra("content", content) - intent.putExtra("title", title) - intent.putExtra("image", image) - intent.putExtra("source", source) + intent.putParcelableArrayListExtra("allItems", allItems) + intent.putExtra("currentItem", currentItem) app.startActivity(intent) } else { try { @@ -102,11 +89,9 @@ fun Context.openItemUrlInternally( } fun Context.openItemUrl( + allItems: ArrayList, + currentItem: Int, linkDecoded: String, - content: String, - image: String, - title: String, - source: String, customTabsIntent: CustomTabsIntent, internalBrowser: Boolean, articleViewer: Boolean, @@ -124,11 +109,9 @@ fun Context.openItemUrl( openInBrowser(linkDecoded, app) } else { this.openItemUrlInternally( + allItems, + currentItem, linkDecoded, - content, - image, - title, - source, customTabsIntent, articleViewer, app diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml index 83ceea3..6829641 100644 --- a/app/src/main/res/layout/activity_reader.xml +++ b/app/src/main/res/layout/activity_reader.xml @@ -1,148 +1,28 @@ - - - - - - - - - - - - - - - - - - - - + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - - - - - - - - - - - + android:layout_height="20dp" + android:background="#55000000" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" /> + diff --git a/app/src/main/res/layout/fragment_article.xml b/app/src/main/res/layout/fragment_article.xml new file mode 100644 index 0000000..908bf4d --- /dev/null +++ b/app/src/main/res/layout/fragment_article.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file