Migrate to Viewpager2 (#387)

* Migrate ReaderActivity to ViewPager2

* Use tint on icons in place of filters

* Prevent crash when opening the first article

* Add the correct background color to the article reader

* Use consistent colors in the article reader

* Migrate ImageActivity to ViewPager2
This commit is contained in:
davidoskky 2021-12-13 20:29:38 +01:00 committed by GitHub
parent 000b346529
commit 7592ab512b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 53 additions and 152 deletions

View File

@ -155,6 +155,7 @@ dependencies {
// Pager // Pager
implementation 'me.relex:circleindicator:2.1.6' implementation 'me.relex:circleindicator:2.1.6'
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
//PhotoView //PhotoView
implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0'

View File

@ -3,8 +3,9 @@ package apps.amine.bou.readerforselfoss
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentManager import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentStatePagerAdapter import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import apps.amine.bou.readerforselfoss.databinding.ActivityImageBinding import apps.amine.bou.readerforselfoss.databinding.ActivityImageBinding
import apps.amine.bou.readerforselfoss.fragments.ImageFragment import apps.amine.bou.readerforselfoss.fragments.ImageFragment
@ -28,8 +29,8 @@ class ImageActivity : AppCompatActivity() {
allImages = intent.getStringArrayListExtra("allImages") as ArrayList<String> allImages = intent.getStringArrayListExtra("allImages") as ArrayList<String>
position = intent.getIntExtra("position", 0) position = intent.getIntExtra("position", 0)
binding.pager.adapter = ScreenSlidePagerAdapter(supportFragmentManager) binding.pager.adapter = ScreenSlidePagerAdapter(this)
binding.pager.currentItem = position binding.pager.setCurrentItem(position, false)
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -43,14 +44,10 @@ class ImageActivity : AppCompatActivity() {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private inner class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm, FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
override fun getCount(): Int { override fun getItemCount(): Int = allImages.size
return allImages.size
}
override fun getItem(position: Int): ImageFragment { override fun createFragment(position: Int): Fragment = ImageFragment.newInstance(allImages[position])
return ImageFragment.newInstance(allImages[position])
}
} }
} }

View File

@ -3,21 +3,16 @@ package apps.amine.bou.readerforselfoss
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.Color import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.core.content.ContextCompat
import androidx.viewpager.widget.ViewPager
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.ViewGroup import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.room.Room import androidx.room.Room
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.databinding.ActivityReaderBinding import apps.amine.bou.readerforselfoss.databinding.ActivityReaderBinding
@ -26,14 +21,11 @@ import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_1_2 import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_1_2
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_2_3 import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_2_3
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_3_4 import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_3_4
import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.themes.Toppings import apps.amine.bou.readerforselfoss.themes.Toppings
import apps.amine.bou.readerforselfoss.transformers.DepthPageTransformer
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.SharedItems import apps.amine.bou.readerforselfoss.utils.SharedItems
import apps.amine.bou.readerforselfoss.utils.toggleStar import apps.amine.bou.readerforselfoss.utils.toggleStar
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import me.relex.circleindicator.CircleIndicator
class ReaderActivity : AppCompatActivity() { class ReaderActivity : AppCompatActivity() {
@ -50,14 +42,14 @@ class ReaderActivity : AppCompatActivity() {
private lateinit var binding: ActivityReaderBinding private lateinit var binding: ActivityReaderBinding
private var activeAlignment: Int = 1 private var activeAlignment: Int = 1
val JUSTIFY = 1 private val JUSTIFY = 1
val ALIGN_LEFT = 2 private val ALIGN_LEFT = 2
private fun showMenuItem(willAddToFavorite: Boolean) { private fun showMenuItem(willAddToFavorite: Boolean) {
if (willAddToFavorite) { if (willAddToFavorite) {
toolbarMenu.findItem(R.id.star).icon.colorFilter = PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP) toolbarMenu.findItem(R.id.star).icon.setTint(Color.WHITE)
} else { } else {
toolbarMenu.findItem(R.id.star).icon.colorFilter = PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP) toolbarMenu.findItem(R.id.star).icon.setTint(Color.RED)
} }
} }
@ -116,33 +108,14 @@ class ReaderActivity : AppCompatActivity() {
readItem(allItems[currentItem]) readItem(allItems[currentItem])
binding.pager.adapter = binding.pager.adapter = ScreenSlidePagerAdapter(this)
ScreenSlidePagerAdapter(supportFragmentManager, AppColors(this@ReaderActivity)) binding.pager.setCurrentItem(currentItem, false)
binding.pager.currentItem = currentItem
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
notifyAdapter()
binding.pager.setPageTransformer(true, DepthPageTransformer())
binding.indicator.setViewPager(binding.pager) binding.indicator.setViewPager(binding.pager)
binding.pager.addOnPageChangeListener(
object : ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
if (allItems[position].starred) {
canRemoveFromFavorite()
} else {
canFavorite()
}
readItem(allItems[position])
}
}
)
} }
private fun readItem(item: Item) { private fun readItem(item: Item) {
@ -151,46 +124,22 @@ class ReaderActivity : AppCompatActivity() {
} }
} }
private fun notifyAdapter() {
(binding.pager.adapter as ScreenSlidePagerAdapter).notifyDataSetChanged()
}
override fun onPause() {
super.onPause()
if (markOnScroll) {
binding.pager.clearOnPageChangeListeners()
}
}
override fun onSaveInstanceState(oldInstanceState: Bundle) { override fun onSaveInstanceState(oldInstanceState: Bundle) {
super.onSaveInstanceState(oldInstanceState) super.onSaveInstanceState(oldInstanceState)
oldInstanceState.clear() oldInstanceState.clear()
} }
private inner class ScreenSlidePagerAdapter(fm: FragmentManager, val appColors: AppColors) : private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) :
FragmentStatePagerAdapter(fm) { FragmentStateAdapter(fa) {
override fun getCount(): Int {
return allItems.size
}
override fun getItem(position: Int): ArticleFragment { override fun getItemCount(): Int = allItems.size
return ArticleFragment.newInstance(position, allItems)
}
override fun startUpdate(container: ViewGroup) { override fun createFragment(position: Int): Fragment = ArticleFragment.newInstance(position, allItems)
super.startUpdate(container)
container.background = ColorDrawable(
ContextCompat.getColor(
this@ReaderActivity,
appColors.colorBackground
)
)
}
} }
fun alignmentMenu(showJustify: Boolean) { private fun alignmentMenu(showJustify: Boolean) {
toolbarMenu.findItem(R.id.align_left).isVisible = !showJustify toolbarMenu.findItem(R.id.align_left).isVisible = !showJustify
toolbarMenu.findItem(R.id.align_justify).isVisible = showJustify toolbarMenu.findItem(R.id.align_justify).isVisible = showJustify
} }
@ -200,7 +149,7 @@ class ReaderActivity : AppCompatActivity() {
inflater.inflate(R.menu.reader_menu, menu) inflater.inflate(R.menu.reader_menu, menu)
toolbarMenu = menu toolbarMenu = menu
if (!allItems.isEmpty() && allItems[currentItem].starred) { if (allItems.isNotEmpty() && allItems[currentItem].starred) {
canRemoveFromFavorite() canRemoveFromFavorite()
} else { } else {
canFavorite() canFavorite()
@ -211,6 +160,22 @@ class ReaderActivity : AppCompatActivity() {
alignmentMenu(true) alignmentMenu(true)
} }
binding.pager.registerOnPageChangeCallback(
object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (allItems[position].starred) {
canRemoveFromFavorite()
} else {
canFavorite()
}
readItem(allItems[position])
}
}
)
return true return true
} }
@ -218,13 +183,11 @@ class ReaderActivity : AppCompatActivity() {
fun afterSave() { fun afterSave() {
allItems[binding.pager.currentItem] = allItems[binding.pager.currentItem] =
allItems[binding.pager.currentItem].toggleStar() allItems[binding.pager.currentItem].toggleStar()
notifyAdapter()
canRemoveFromFavorite() canRemoveFromFavorite()
} }
fun afterUnsave() { fun afterUnsave() {
allItems[binding.pager.currentItem] = allItems[binding.pager.currentItem].toggleStar() allItems[binding.pager.currentItem] = allItems[binding.pager.currentItem].toggleStar()
notifyAdapter()
canFavorite() canFavorite()
} }

View File

@ -17,7 +17,6 @@ import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.core.content.ContextCompat
import androidx.core.widget.NestedScrollView import androidx.core.widget.NestedScrollView
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
@ -93,6 +92,7 @@ class ArticleFragment : Fragment() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
pageNumber = requireArguments().getInt(ARG_POSITION) pageNumber = requireArguments().getInt(ARG_POSITION)
// TODO: The full list of items is not required, only the item used should be passed
allItems = requireArguments().getParcelableArrayList<Item>(ARG_ITEMS) as ArrayList<Item> allItems = requireArguments().getParcelableArrayList<Item>(ARG_ITEMS) as ArrayList<Item>
db = Room.databaseBuilder( db = Room.databaseBuilder(
@ -391,30 +391,12 @@ class ArticleFragment : Fragment() {
binding.webcontent.settings.standardFontFamily = a.getString(0) binding.webcontent.settings.standardFontFamily = a.getString(0)
binding.webcontent.visibility = View.VISIBLE binding.webcontent.visibility = View.VISIBLE
val (textColor, backgroundColor) = if (appColors.isDarkTheme) {
if (context != null) {
Pair(ContextCompat.getColor(requireContext(), R.color.dark_webview_text), ContextCompat.getColor(requireContext(), R.color.dark_webview))
} else {
Pair(null, null)
}
} else {
if (context != null) {
Pair(ContextCompat.getColor(requireContext(), R.color.light_webview_text), ContextCompat.getColor(requireContext(), R.color.light_webview))
} else {
Pair(null, null)
}
}
val stringTextColor: String = if (textColor != null) { // TODO: Set the color strings programmatically
String.format("#%06X", 0xFFFFFF and textColor) val (stringTextColor, stringBackgroundColor) = if (appColors.isDarkTheme) {
Pair("#FFFFFF", "#303030")
} else { } else {
"#000000" Pair("#212121", "#FAFAFA")
}
val stringBackgroundColor = if (backgroundColor != null) {
String.format("#%06X", 0xFFFFFF and backgroundColor)
} else {
"#FFFFFF"
} }
binding.webcontent.settings.useWideViewPort = true binding.webcontent.settings.useWideViewPort = true

View File

@ -49,7 +49,7 @@ class AppColors(a: Activity) {
R.color.darkBackground R.color.darkBackground
} else { } else {
a.setTheme(R.style.NoBar) a.setTheme(R.style.NoBar)
android.R.color.background_light R.color.grey_50
} }
textColor = if (isDarkTheme) { textColor = if (isDarkTheme) {

View File

@ -1,43 +0,0 @@
package apps.amine.bou.readerforselfoss.transformers
import androidx.viewpager.widget.ViewPager
import android.view.View
class DepthPageTransformer : ViewPager.PageTransformer {
override fun transformPage(view: View, position: Float) {
val pageWidth = view.width
when {
position < -1 -> // [-Infinity,-1)
// This page is way off-screen to the left.
view.alpha = 0F
position <= 0 -> { // [-1,0]
// Use the default slide transition when moving to the left page
view.alpha = 1F
view.translationX = 0F
view.scaleX = 1F
view.scaleY = 1F
}
position <= 1 -> { // (0,1]
// Fade the page out.
view.alpha = 1 - position
// Counteract the default slide transition
view.translationX = pageWidth * -position
// Scale the page down (between MIN_SCALE and 1)
val scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position))
view.scaleX = scaleFactor
view.scaleY = scaleFactor
}
else -> // (1,+Infinity]
// This page is way off-screen to the right.
view.alpha = 0F
}
}
companion object {
private val MIN_SCALE = 0.75f
}
}

View File

@ -21,7 +21,7 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager <androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager" android:id="@+id/pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"

View File

@ -22,7 +22,7 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager <androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager" android:id="@+id/pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
@ -33,7 +33,7 @@
app:layout_constraintTop_toBottomOf="@+id/appBarLayout" /> app:layout_constraintTop_toBottomOf="@+id/appBarLayout" />
<me.relex.circleindicator.CircleIndicator <me.relex.circleindicator.CircleIndicator3
android:id="@+id/indicator" android:id="@+id/indicator"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="20dp" android:layout_height="20dp"

View File

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?android:colorBackground"
android:descendantFocusability="blocksDescendants"> android:descendantFocusability="blocksDescendants">
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView

View File

@ -5,7 +5,7 @@
<color name="colorAccent">#FFff5722</color> <color name="colorAccent">#FFff5722</color>
<color name="colorAccentDark">#FFbf360c</color> <color name="colorAccentDark">#FFbf360c</color>
<color name="pink">#FFe91e63</color> <color name="pink">#FFe91e63</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFF</color>
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
<color name="red">#FF0000</color> <color name="red">#FF0000</color>
<color name="refresh_progress_1">@color/colorAccentDark</color> <color name="refresh_progress_1">@color/colorAccentDark</color>
@ -20,5 +20,5 @@
<color name="cardBackgroundColor">#FFFFFFFF</color> <color name="cardBackgroundColor">#FFFFFFFF</color>
<color name="materialDrawerHeaderSelectionText">#212121</color> <color name="materialDrawerHeaderSelectionText">#212121</color>
<color name="darkBackground">#FF303030</color> <color name="darkBackground">#303030</color>
</resources> </resources>