From 4401df6203bb408e1aa8cb63cf0976fe4a6f2d01 Mon Sep 17 00:00:00 2001 From: Michael <5672750+mibac138@users.noreply.github.com> Date: Sat, 6 Nov 2021 19:07:26 +0100 Subject: [PATCH] Migrate from ViewPager to ViewPager2 (#1601) --- .../ui/base/BaseFragmentPagerAdapter.kt | 37 ++++++++-------- .../ui/modules/grade/GradeFragment.kt | 42 ++++++++++++------ .../ui/modules/grade/GradePresenter.kt | 1 - .../ui/modules/login/LoginActivity.kt | 42 +++++++++++------- .../ui/modules/message/MessageFragment.kt | 40 ++++++++++++----- .../ui/modules/message/MessagePresenter.kt | 1 - .../SchoolAndTeachersFragment.kt | 44 ++++++++++++++----- .../SchoolAndTeachersPresenter.kt | 1 - .../ui/widgets/SwipeDisabledViewPager.kt | 19 -------- .../wulkanowy/utils/ViewPagerExtension.kt | 8 ++-- app/src/main/res/layout/activity_login.xml | 2 +- app/src/main/res/layout/fragment_grade.xml | 2 +- app/src/main/res/layout/fragment_message.xml | 2 +- .../res/layout/fragment_schoolandteachers.xml | 2 +- 14 files changed, 142 insertions(+), 101 deletions(-) delete mode 100644 app/src/main/java/io/github/wulkanowy/ui/widgets/SwipeDisabledViewPager.kt diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt index bd735535..6bca87f1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragmentPagerAdapter.kt @@ -2,32 +2,33 @@ package io.github.wulkanowy.ui.base import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter +import androidx.lifecycle.Lifecycle +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator -//TODO Use ViewPager2 -class BaseFragmentPagerAdapter(private val fragmentManager: FragmentManager) : - FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { +class BaseFragmentPagerAdapter( + private val fragmentManager: FragmentManager, + private val pagesCount: Int, + lifecycle: Lifecycle, +) : FragmentStateAdapter(fragmentManager, lifecycle), TabLayoutMediator.TabConfigurationStrategy { - private val pages = mutableMapOf() + lateinit var itemFactory: (position: Int) -> Fragment + + var titleFactory: (position: Int) -> String? = { "" } var containerId = 0 fun getFragmentInstance(position: Int): Fragment? { require(containerId != 0) { "Container id is 0" } - return fragmentManager.findFragmentByTag("android:switcher:$containerId:$position") + return fragmentManager.findFragmentByTag("f$position") } - fun addFragments(fragments: List) { - fragments.forEach { pages[it] = null } + override fun createFragment(position: Int): Fragment = itemFactory(position) + + override fun getItemCount() = pagesCount + + override fun onConfigureTab(tab: TabLayout.Tab, position: Int) { + tab.text = titleFactory(position) } - - fun addFragmentsWithTitle(pages: Map) { - this.pages.putAll(pages) - } - - override fun getItem(position: Int) = pages.keys.elementAt(position) - - override fun getCount() = pages.size - - override fun getPageTitle(position: Int) = pages.values.elementAt(position) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt index b3ef3037..f9ecb681 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeFragment.kt @@ -8,6 +8,7 @@ import android.view.View import android.view.View.INVISIBLE import android.view.View.VISIBLE import androidx.appcompat.app.AlertDialog +import com.google.android.material.tabs.TabLayoutMediator import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Semester @@ -29,7 +30,13 @@ class GradeFragment : BaseFragment(R.layout.fragment_grade @Inject lateinit var presenter: GradePresenter - private val pagerAdapter by lazy { BaseFragmentPagerAdapter(childFragmentManager) } + private val pagerAdapter by lazy { + BaseFragmentPagerAdapter( + fragmentManager = childFragmentManager, + pagesCount = 3, + lifecycle = lifecycle, + ) + } private var semesterSwitchMenu: MenuItem? = null @@ -62,25 +69,34 @@ class GradeFragment : BaseFragment(R.layout.fragment_grade } override fun initView() { - with(pagerAdapter) { - containerId = binding.gradeViewPager.id - addFragmentsWithTitle( - mapOf( - GradeDetailsFragment.newInstance() to getString(R.string.all_details), - GradeSummaryFragment.newInstance() to getString(R.string.grade_menu_summary), - GradeStatisticsFragment.newInstance() to getString(R.string.grade_menu_statistics) - ) - ) - } - with(binding.gradeViewPager) { adapter = pagerAdapter offscreenPageLimit = 3 setOnSelectPageListener(presenter::onPageSelected) } + with(pagerAdapter) { + containerId = binding.gradeViewPager.id + titleFactory = { + when (it) { + 0 -> getString(R.string.all_details) + 1 -> getString(R.string.grade_menu_summary) + 2 -> getString(R.string.grade_menu_statistics) + else -> throw IllegalStateException() + } + } + itemFactory = { + when (it) { + 0 -> GradeDetailsFragment.newInstance() + 1 -> GradeSummaryFragment.newInstance() + 2 -> GradeStatisticsFragment.newInstance() + else -> throw IllegalStateException() + } + } + TabLayoutMediator(binding.gradeTabLayout, binding.gradeViewPager, this).attach() + } + with(binding.gradeTabLayout) { - setupWithViewPager(binding.gradeViewPager) setElevationCompat(context.dpToPx(4f)) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt index 504c730d..76e88bcd 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradePresenter.kt @@ -101,7 +101,6 @@ class GradePresenter @Inject constructor( private fun loadData() { flowWithResource { val student = studentRepository.getCurrentStudent() - delay(200) semesterRepository.getSemesters(student, refreshOnNoCurrent = true) }.onEach { when (it.status) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt index 10f6c073..f7bab526 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginActivity.kt @@ -24,7 +24,13 @@ class LoginActivity : BaseActivity(), Logi @Inject override lateinit var presenter: LoginPresenter - private val loginAdapter = BaseFragmentPagerAdapter(supportFragmentManager) + private val pagerAdapter by lazy { + BaseFragmentPagerAdapter( + fragmentManager = supportFragmentManager, + pagesCount = 5, + lifecycle = lifecycle, + ) + } @Inject lateinit var updateHelper: UpdateHelper @@ -65,24 +71,26 @@ class LoginActivity : BaseActivity(), Logi setDisplayShowTitleEnabled(false) } - with(loginAdapter) { - containerId = binding.loginViewpager.id - addFragments( - listOf( - LoginFormFragment.newInstance(), - LoginSymbolFragment.newInstance(), - LoginStudentSelectFragment.newInstance(), - LoginAdvancedFragment.newInstance(), - LoginRecoverFragment.newInstance() - ) - ) - } - with(binding.loginViewpager) { offscreenPageLimit = 2 - adapter = loginAdapter + adapter = pagerAdapter + isUserInputEnabled = false setOnSelectPageListener(presenter::onViewSelected) } + + with(pagerAdapter) { + containerId = binding.loginViewpager.id + itemFactory = { + when (it) { + 0 -> LoginFormFragment.newInstance() + 1 -> LoginSymbolFragment.newInstance() + 2 -> LoginStudentSelectFragment.newInstance() + 3 -> LoginAdvancedFragment.newInstance() + 4 -> LoginRecoverFragment.newInstance() + else -> throw IllegalStateException() + } + } + } } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -103,12 +111,12 @@ class LoginActivity : BaseActivity(), Logi } override fun notifyInitSymbolFragment(loginData: Triple) { - (loginAdapter.getFragmentInstance(1) as? LoginSymbolFragment) + (pagerAdapter.getFragmentInstance(1) as? LoginSymbolFragment) ?.onParentInitSymbolFragment(loginData) } override fun notifyInitStudentSelectFragment(studentsWithSemesters: List) { - (loginAdapter.getFragmentInstance(2) as? LoginStudentSelectFragment) + (pagerAdapter.getFragmentInstance(2) as? LoginStudentSelectFragment) ?.onParentInitStudentSelectFragment(studentsWithSemesters) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageFragment.kt index 72fc627f..51076c64 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.View import android.view.View.INVISIBLE import android.view.View.VISIBLE +import com.google.android.material.tabs.TabLayoutMediator import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED @@ -26,7 +27,13 @@ class MessageFragment : BaseFragment(R.layout.fragment_m @Inject lateinit var presenter: MessagePresenter - private val pagerAdapter by lazy { BaseFragmentPagerAdapter(childFragmentManager) } + private val pagerAdapter by lazy { + BaseFragmentPagerAdapter( + fragmentManager = childFragmentManager, + pagesCount = 3, + lifecycle = lifecycle, + ) + } companion object { fun newInstance() = MessageFragment() @@ -43,23 +50,34 @@ class MessageFragment : BaseFragment(R.layout.fragment_m } override fun initView() { - with(pagerAdapter) { - containerId = binding.messageViewPager.id - addFragmentsWithTitle(mapOf( - MessageTabFragment.newInstance(RECEIVED) to getString(R.string.message_inbox), - MessageTabFragment.newInstance(SENT) to getString(R.string.message_sent), - MessageTabFragment.newInstance(TRASHED) to getString(R.string.message_trash) - )) - } - with(binding.messageViewPager) { adapter = pagerAdapter offscreenPageLimit = 2 setOnSelectPageListener(presenter::onPageSelected) } + with(pagerAdapter) { + containerId = binding.messageViewPager.id + titleFactory = { + when (it) { + 0 -> getString(R.string.message_inbox) + 1 -> getString(R.string.message_sent) + 2 -> getString(R.string.message_trash) + else -> throw IllegalStateException() + } + } + itemFactory = { + when (it) { + 0 -> MessageTabFragment.newInstance(RECEIVED) + 1 -> MessageTabFragment.newInstance(SENT) + 2 -> MessageTabFragment.newInstance(TRASHED) + else -> throw IllegalStateException() + } + } + TabLayoutMediator(binding.messageTabLayout, binding.messageViewPager, this).attach() + } + with(binding.messageTabLayout) { - setupWithViewPager(binding.messageViewPager) setElevationCompat(context.dpToPx(4f)) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt index be694052..9e19517b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessagePresenter.kt @@ -16,7 +16,6 @@ class MessagePresenter @Inject constructor( override fun onAttachView(view: MessageView) { super.onAttachView(view) presenterScope.launch { - delay(150) view.initView() Timber.i("Message view was initialized") loadData() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/SchoolAndTeachersFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/SchoolAndTeachersFragment.kt index c1c56961..9892b77a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/SchoolAndTeachersFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/SchoolAndTeachersFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.View import android.view.View.INVISIBLE import android.view.View.VISIBLE +import com.google.android.material.tabs.TabLayoutMediator import dagger.hilt.android.AndroidEntryPoint import io.github.wulkanowy.R import io.github.wulkanowy.databinding.FragmentSchoolandteachersBinding @@ -24,7 +25,13 @@ class SchoolAndTeachersFragment : @Inject lateinit var presenter: SchoolAndTeachersPresenter - private val pagerAdapter by lazy { BaseFragmentPagerAdapter(childFragmentManager) } + private val pagerAdapter by lazy { + BaseFragmentPagerAdapter( + fragmentManager = childFragmentManager, + pagesCount = 2, + lifecycle = lifecycle, + ) + } companion object { fun newInstance() = SchoolAndTeachersFragment() @@ -41,22 +48,36 @@ class SchoolAndTeachersFragment : } override fun initView() { - with(pagerAdapter) { - containerId = binding.schoolandteachersViewPager.id - addFragmentsWithTitle(mapOf( - SchoolFragment.newInstance() to getString(R.string.school_title), - TeacherFragment.newInstance() to getString(R.string.teachers_title) - )) - } - with(binding.schoolandteachersViewPager) { adapter = pagerAdapter offscreenPageLimit = 2 setOnSelectPageListener(presenter::onPageSelected) } + with(pagerAdapter) { + containerId = binding.schoolandteachersViewPager.id + titleFactory = { + when (it) { + 0 -> getString(R.string.school_title) + 1 -> getString(R.string.teachers_title) + else -> throw IllegalStateException() + } + } + itemFactory = { + when (it) { + 0 -> SchoolFragment.newInstance() + 1 -> TeacherFragment.newInstance() + else -> throw IllegalStateException() + } + } + TabLayoutMediator( + binding.schoolandteachersTabLayout, + binding.schoolandteachersViewPager, + this + ).attach() + } + with(binding.schoolandteachersTabLayout) { - setupWithViewPager(binding.schoolandteachersViewPager) setElevationCompat(context.dpToPx(4f)) } } @@ -77,7 +98,8 @@ class SchoolAndTeachersFragment : } override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) { - (pagerAdapter.getFragmentInstance(index) as? SchoolAndTeachersChildView)?.onParentLoadData(forceRefresh) + (pagerAdapter.getFragmentInstance(index) as? SchoolAndTeachersChildView) + ?.onParentLoadData(forceRefresh) } override fun onDestroyView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/SchoolAndTeachersPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/SchoolAndTeachersPresenter.kt index c14272b9..43823d6b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/SchoolAndTeachersPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/SchoolAndTeachersPresenter.kt @@ -16,7 +16,6 @@ class SchoolAndTeachersPresenter @Inject constructor( override fun onAttachView(view: SchoolAndTeachersView) { super.onAttachView(view) presenterScope.launch { - delay(150) view.initView() Timber.i("Message view was initialized") loadData() diff --git a/app/src/main/java/io/github/wulkanowy/ui/widgets/SwipeDisabledViewPager.kt b/app/src/main/java/io/github/wulkanowy/ui/widgets/SwipeDisabledViewPager.kt deleted file mode 100644 index eb5cae4f..00000000 --- a/app/src/main/java/io/github/wulkanowy/ui/widgets/SwipeDisabledViewPager.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.wulkanowy.ui.widgets - -import android.annotation.SuppressLint -import android.content.Context -import android.util.AttributeSet -import android.view.MotionEvent -import androidx.viewpager.widget.ViewPager - -class SwipeDisabledViewPager : ViewPager { - - constructor(context: Context) : super(context) - - constructor(context: Context, attr: AttributeSet) : super(context, attr) - - @SuppressLint("ClickableViewAccessibility") - override fun onTouchEvent(ev: MotionEvent) = false - - override fun onInterceptTouchEvent(ev: MotionEvent) = false -} diff --git a/app/src/main/java/io/github/wulkanowy/utils/ViewPagerExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ViewPagerExtension.kt index 6a5ad880..700ac2f1 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/ViewPagerExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/ViewPagerExtension.kt @@ -1,13 +1,11 @@ package io.github.wulkanowy.utils -import androidx.viewpager.widget.ViewPager +import androidx.viewpager2.widget.ViewPager2 -inline fun ViewPager.setOnSelectPageListener(crossinline selectListener: (position: Int) -> Unit) { - addOnPageChangeListener(object : ViewPager.OnPageChangeListener { +inline fun ViewPager2.setOnSelectPageListener(crossinline selectListener: (position: Int) -> Unit) { + registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { selectListener(position) } - override fun onPageScrollStateChanged(state: Int) {} - override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {} }) } diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index e55ea8b9..1d5b5280 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -10,7 +10,7 @@ android:layout_height="wrap_content" android:background="@android:color/transparent" /> - diff --git a/app/src/main/res/layout/fragment_grade.xml b/app/src/main/res/layout/fragment_grade.xml index ed0447fb..989929d4 100644 --- a/app/src/main/res/layout/fragment_grade.xml +++ b/app/src/main/res/layout/fragment_grade.xml @@ -17,7 +17,7 @@ tools:ignore="UnusedAttribute" tools:visibility="visible" /> - - -