mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-01-17 20:36:44 -06:00
[UI] Enable colored app bars on scroll (#211)
* Extract fragment scroll listener to separate file * Replace canRefresh with isScrolled * Add empty helper class to animate app bar color * Implement AppBarColorAnimator * Rename getRefreshScrollingView() to getScrollingView() * Set isScrolled on drag start * Clear isScrolled on fling to top * Add getSyncParams() to fragments * Convert getAppBars() to property * Tint TabLayout background drawable
This commit is contained in:
parent
58d9dec33c
commit
37a94595c0
@ -19,6 +19,7 @@ import kotlinx.coroutines.withContext
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaCalendarBinding
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaDefaultBinding
|
||||
@ -45,6 +46,7 @@ class AgendaFragment : BaseFragment<ViewBinding, MainActivity>(
|
||||
|
||||
override fun getFab() = R.string.add to CommunityMaterial.Icon3.cmd_plus
|
||||
override fun getMarkAsReadType() = MetadataType.EVENT
|
||||
override fun getSyncParams() = FeatureType.AGENDA to null
|
||||
override fun getBottomSheetItems() = listOf(
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_add_event)
|
||||
@ -114,6 +116,7 @@ class AgendaFragment : BaseFragment<ViewBinding, MainActivity>(
|
||||
private suspend fun createDefaultAgendaView(b: FragmentAgendaDefaultBinding) {
|
||||
if (!isAdded)
|
||||
return
|
||||
canRefreshDisabled = true
|
||||
checkEventTypes()
|
||||
delay(500)
|
||||
|
||||
|
@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.ui.attendance
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.databinding.BasePagerFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ext.Bundle
|
||||
@ -32,6 +33,7 @@ class AttendanceFragment : PagerFragment<BasePagerFragmentBinding, MainActivity>
|
||||
}
|
||||
|
||||
override fun getMarkAsReadType() = MetadataType.ATTENDANCE
|
||||
override fun getSyncParams() = FeatureType.ATTENDANCE to null
|
||||
override fun getBottomSheetItems() = listOf(
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_attendance_config)
|
||||
|
@ -29,7 +29,7 @@ class AttendanceListFragment : BaseFragment<AttendanceListFragmentBinding, MainA
|
||||
inflater = AttendanceListFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getRefreshScrollingView() = b.list
|
||||
override fun getScrollingView() = b.list
|
||||
|
||||
private var viewType = AttendanceFragment.VIEW_DAYS
|
||||
private var expandSubjectId = 0L
|
||||
|
@ -43,7 +43,7 @@ class AttendanceSummaryFragment : BaseFragment<AttendanceSummaryFragmentBinding,
|
||||
private var periodSelection = 0
|
||||
}
|
||||
|
||||
override fun getRefreshScrollingView() = b.scrollView
|
||||
override fun getScrollingView() = b.scrollView
|
||||
|
||||
private val manager
|
||||
get() = app.attendanceManager
|
||||
|
@ -4,11 +4,7 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.base.fragment
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@ -18,49 +14,6 @@ import pl.szczodrzynski.edziennik.ui.login.LoginActivity
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
internal fun BaseFragment<*, *>.setupCanRefresh() {
|
||||
when (val view = getRefreshScrollingView()) {
|
||||
is RecyclerView -> {
|
||||
canRefresh = !view.canScrollVertically(-1)
|
||||
view.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
// disable refresh when scrolled down
|
||||
if (recyclerView.canScrollVertically(-1))
|
||||
canRefresh = false
|
||||
// enable refresh when scrolled to the top and not scrolling anymore
|
||||
else if (newState == RecyclerView.SCROLL_STATE_IDLE)
|
||||
canRefresh = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
is View -> {
|
||||
canRefresh = !view.canScrollVertically(-1)
|
||||
var isTouched = false
|
||||
view.setOnTouchListener { _, event ->
|
||||
// keep track of the touch state
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> isTouched = false
|
||||
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> isTouched = true
|
||||
}
|
||||
// disable refresh when scrolled down
|
||||
if (view.canScrollVertically(-1))
|
||||
canRefresh = false
|
||||
// enable refresh when scrolled to the top and not touching anymore
|
||||
else if (!isTouched)
|
||||
canRefresh = true
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
// dispatch the default value to the activity
|
||||
canRefresh = canRefresh
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseFragment<*, *>.setupMainActivity(activity: MainActivity) {
|
||||
val items = getBottomSheetItems().toMutableList()
|
||||
getMarkAsReadType()?.let { metadataType ->
|
||||
@ -97,6 +50,8 @@ internal fun BaseFragment<*, *>.setupMainActivity(activity: MainActivity) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appBars += activity.navView.toolbar
|
||||
}
|
||||
|
||||
internal fun BaseFragment<*, *>.setupLoginActivity(activity: LoginActivity) {}
|
||||
|
@ -12,6 +12,7 @@ import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.gson.JsonObject
|
||||
import com.mikepenz.iconics.typeface.IIcon
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -19,6 +20,7 @@ import kotlinx.coroutines.Job
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.data.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.ext.registerSafe
|
||||
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
|
||||
@ -38,31 +40,37 @@ abstract class BaseFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
|
||||
private var isViewReady: Boolean = false
|
||||
private var inState: Bundle? = null
|
||||
private var appBarAnimator: AppBarColorAnimator? = null
|
||||
|
||||
/**
|
||||
* Enables or disables the activity's SwipeRefreshLayout.
|
||||
* Use only if [getRefreshScrollingView] is not used.
|
||||
*
|
||||
* The [PagerFragment] manages its [canRefresh] state
|
||||
* based on the value of the currently selected page.
|
||||
* Whether the view is currently being scrolled
|
||||
* or is left scrolled away from the top.
|
||||
*/
|
||||
internal var canRefresh = false
|
||||
set(value) {
|
||||
internal var isScrolled = false
|
||||
set(value) { // cannot be private - PagerFragment onPageScrollStateChanged
|
||||
field = value
|
||||
(activity as? MainActivity)?.swipeRefreshLayout?.isEnabled =
|
||||
!canRefreshDisabled && value
|
||||
dispatchCanRefresh()
|
||||
appBarAnimator?.dispatchLiftOnScroll()
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcefully disables the activity's SwipeRefreshLayout
|
||||
* if [getRefreshScrollingView] is used.
|
||||
* Forcefully disables the activity's SwipeRefreshLayout.
|
||||
*
|
||||
* The [PagerFragment] manages its [canRefreshDisabled] state
|
||||
* based on the value of the currently selected page.
|
||||
*/
|
||||
internal var canRefreshDisabled = false
|
||||
set(value) {
|
||||
field = value
|
||||
canRefresh = canRefresh
|
||||
dispatchCanRefresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of views (usually app bars) that should have their
|
||||
* background color elevated when the fragment is scrolled.
|
||||
*/
|
||||
internal var appBars = mutableSetOf<View>()
|
||||
|
||||
private var job = Job()
|
||||
final override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
@ -83,6 +91,7 @@ abstract class BaseFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
?: return null
|
||||
isViewReady = false // reinitialize the view in onResume()
|
||||
inState = savedInstanceState // save the instance state for onResume()
|
||||
appBarAnimator = AppBarColorAnimator(activity, appBars)
|
||||
return b.root
|
||||
}
|
||||
|
||||
@ -92,9 +101,17 @@ abstract class BaseFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
if (!isAdded || isViewReady)
|
||||
return
|
||||
isViewReady = true
|
||||
setupCanRefresh()
|
||||
// setup the activity (bottom sheet, FAB, etc.)
|
||||
// run before setupScrollListener {} to populate appBars
|
||||
(activity as? MainActivity)?.let(::setupMainActivity)
|
||||
(activity as? LoginActivity)?.let(::setupLoginActivity)
|
||||
// listen to scroll state changes
|
||||
var first = true
|
||||
setupScrollListener {
|
||||
if (isScrolled != it || first)
|
||||
isScrolled = it
|
||||
first = false
|
||||
}
|
||||
// let the UI transition for a moment
|
||||
startCoroutineTimer(100L) {
|
||||
if (!isAdded)
|
||||
@ -141,9 +158,10 @@ abstract class BaseFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
|
||||
/**
|
||||
* Called to retrieve the scrolling view contained in the fragment.
|
||||
* The scrolling view is configured to act nicely with the SwipeRefreshLayout.
|
||||
* The scrolling view is configured to work nicely with the app bars
|
||||
* and the SwipeRefreshLayout.
|
||||
*/
|
||||
open fun getRefreshScrollingView(): View? = null
|
||||
open fun getScrollingView(): View? = null
|
||||
|
||||
/**
|
||||
* Called to retrieve the FAB label resource and the icon.
|
||||
@ -157,6 +175,22 @@ abstract class BaseFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
*/
|
||||
open fun getMarkAsReadType(): MetadataType? = null
|
||||
|
||||
/**
|
||||
* Called to retrieve the [FeatureType] this fragment is associated with.
|
||||
* May also return arguments for the sync task.
|
||||
*
|
||||
* If not provided, swipe-to-refresh is disabled and the manual sync dialog
|
||||
* selects all features by default.
|
||||
*
|
||||
* If [FeatureType] is null, all features are synced (and selected by the
|
||||
* manual sync dialog).
|
||||
*
|
||||
* It is important to return the desired [FeatureType] from the first
|
||||
* call of this method, which runs before [onViewReady]. Otherwise,
|
||||
* swipe-to-refresh will not be enabled unless the view is scrolled.
|
||||
*/
|
||||
open fun getSyncParams(): Pair<FeatureType?, JsonObject?>? = null
|
||||
|
||||
/**
|
||||
* Called to retrieve any extra bottom sheet items that should be displayed.
|
||||
*/
|
||||
|
@ -23,8 +23,8 @@ abstract class PagerFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
inflater: ((inflater: LayoutInflater, parent: ViewGroup?, attachToParent: Boolean) -> B)?,
|
||||
) : BaseFragment<B, A>(inflater) {
|
||||
|
||||
private lateinit var pages: List<Pair<Fragment, String>>
|
||||
private val fragmentCache = mutableMapOf<Int, Fragment>()
|
||||
private lateinit var pages: List<Pair<BaseFragment<*, *>, String>>
|
||||
private val fragmentCache = mutableMapOf<Int, BaseFragment<*, *>>()
|
||||
|
||||
/**
|
||||
* Stores the default page index that is activated when
|
||||
@ -37,6 +37,18 @@ abstract class PagerFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
*/
|
||||
protected open var savedPageSelection = -1
|
||||
|
||||
protected val currentFragment: BaseFragment<*, *>?
|
||||
get() = fragmentCache[getViewPager().currentItem]
|
||||
|
||||
final override fun getScrollingView() = null
|
||||
override fun getSyncParams() = currentFragment?.getSyncParams()
|
||||
|
||||
override fun onResume() {
|
||||
// add TabLayout before super's setupScrollListener {}
|
||||
appBars += getTabLayout()
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override suspend fun onViewReady(savedInstanceState: Bundle?) {
|
||||
if (savedPageSelection == -1)
|
||||
savedPageSelection = savedInstanceState?.getInt("pageSelection") ?: 0
|
||||
@ -47,6 +59,7 @@ abstract class PagerFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
override fun getItemCount() = getPageCount()
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
val fragment = getPageFragment(position)
|
||||
fragment.appBars += getTabLayout()
|
||||
fragmentCache[position] = fragment
|
||||
return fragment
|
||||
}
|
||||
@ -58,15 +71,15 @@ abstract class PagerFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
it.setCurrentItem(savedPageSelection, false)
|
||||
it.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
canRefresh = when (state) {
|
||||
ViewPager2.SCROLL_STATE_IDLE -> {
|
||||
val fragment =
|
||||
fragmentCache[it.currentItem] as? BaseFragment<*, *>
|
||||
fragment != null && !fragment.canRefreshDisabled && fragment.canRefresh
|
||||
}
|
||||
|
||||
else -> false
|
||||
if (state != ViewPager2.SCROLL_STATE_IDLE) {
|
||||
// disable swipe-to-refresh during scrolling
|
||||
canRefreshDisabled = true
|
||||
return
|
||||
}
|
||||
// take child fragment's values
|
||||
val fragment = currentFragment
|
||||
canRefreshDisabled = fragment?.canRefreshDisabled == true
|
||||
isScrolled = fragment?.isScrolled == true
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
@ -125,7 +138,7 @@ abstract class PagerFragment<B : ViewBinding, A : AppCompatActivity>(
|
||||
* Only used with the default implementation of [getPageCount], [getPageFragment]
|
||||
* and [getPageTitle].
|
||||
*/
|
||||
open suspend fun onCreatePages() = listOf<Pair<Fragment, String>>()
|
||||
open suspend fun onCreatePages() = listOf<Pair<BaseFragment<*, *>, String>>()
|
||||
|
||||
open fun getPageCount() = pages.size
|
||||
open fun getPageFragment(position: Int) = pages[position].first
|
||||
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2024-7-9.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.base.fragment
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.animation.LinearInterpolator
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.motion.MotionUtils
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.ext.resolveAttr
|
||||
import pl.szczodrzynski.edziennik.ext.setTintColor
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
internal fun BaseFragment<*, *>.setupScrollListener(setIsScrolled: (Boolean) -> Unit) {
|
||||
when (val view = getScrollingView()) {
|
||||
is RecyclerView -> {
|
||||
setIsScrolled(view.canScrollVertically(-1))
|
||||
view.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
if (view.canScrollVertically(-1))
|
||||
setIsScrolled(true)
|
||||
else if (newState == RecyclerView.SCROLL_STATE_IDLE)
|
||||
setIsScrolled(false)
|
||||
}
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
if (view.canScrollVertically(-1))
|
||||
setIsScrolled(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
is View -> {
|
||||
setIsScrolled(view.canScrollVertically(-1))
|
||||
var isTouched = false
|
||||
view.setOnTouchListener { _, event ->
|
||||
// keep track of the touch state
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> isTouched = false
|
||||
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> isTouched = true
|
||||
}
|
||||
if (view.canScrollVertically(-1))
|
||||
setIsScrolled(true)
|
||||
else if (!isTouched)
|
||||
setIsScrolled(false)
|
||||
false
|
||||
}
|
||||
(view as? NestedScrollView)?.setOnScrollChangeListener(
|
||||
NestedScrollView.OnScrollChangeListener { _, _, _, _, _ ->
|
||||
if (!isTouched && !view.canScrollVertically(-1))
|
||||
setIsScrolled(false)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
else -> { // null
|
||||
// dispatch the default value to the activity
|
||||
setIsScrolled(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseFragment<*, *>.dispatchCanRefresh() {
|
||||
(activity as? MainActivity)?.swipeRefreshLayout?.isEnabled =
|
||||
!canRefreshDisabled && !isScrolled && getSyncParams() != null
|
||||
}
|
||||
|
||||
internal class AppBarColorAnimator(
|
||||
context: Context,
|
||||
private val bars: Set<View>,
|
||||
) : ValueAnimator.AnimatorUpdateListener {
|
||||
companion object {
|
||||
// keep track of the current animation value applied globally to the view
|
||||
private var currentValue = 0.0f
|
||||
}
|
||||
|
||||
private lateinit var animator: ValueAnimator
|
||||
|
||||
private val barColor = R.attr.colorSurface.resolveAttr(context)
|
||||
private val liftColor = R.attr.colorSurfaceContainer.resolveAttr(context)
|
||||
|
||||
context(BaseFragment<*, *>)
|
||||
fun dispatchLiftOnScroll() {
|
||||
if (::animator.isInitialized)
|
||||
animator.cancel()
|
||||
animator = ValueAnimator.ofFloat(
|
||||
currentValue,
|
||||
if (isScrolled) 1.0f else 0.0f,
|
||||
)
|
||||
animator.duration = MotionUtils.resolveThemeDuration(
|
||||
activity,
|
||||
R.attr.motionDurationMedium2,
|
||||
resources.getInteger(R.integer.app_bar_elevation_anim_duration),
|
||||
).toLong()
|
||||
animator.interpolator = MotionUtils.resolveThemeInterpolator(
|
||||
activity,
|
||||
R.attr.motionEasingStandardInterpolator,
|
||||
LinearInterpolator(),
|
||||
)
|
||||
animator.addUpdateListener(this)
|
||||
animator.start()
|
||||
}
|
||||
|
||||
override fun onAnimationUpdate(animation: ValueAnimator) {
|
||||
currentValue = animation.animatedValue as Float
|
||||
val mixedColor = MaterialColors.layer(
|
||||
barColor,
|
||||
liftColor,
|
||||
currentValue,
|
||||
)
|
||||
for (bar in bars) {
|
||||
when (val drawable = bar.background) {
|
||||
is MaterialShapeDrawable -> drawable.fillColor = ColorStateList.valueOf(mixedColor)
|
||||
is LayerDrawable -> drawable.getDrawable(0).setTintColor(mixedColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.full.NoticeFull
|
||||
import pl.szczodrzynski.edziennik.data.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentBehaviourBinding
|
||||
import pl.szczodrzynski.edziennik.ext.resolveAttr
|
||||
@ -20,8 +21,9 @@ class BehaviourFragment : BaseFragment<FragmentBehaviourBinding, MainActivity>(
|
||||
inflater = FragmentBehaviourBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getRefreshScrollingView() = b.noticesView
|
||||
override fun getScrollingView() = b.noticesView
|
||||
override fun getMarkAsReadType() = MetadataType.NOTICE
|
||||
override fun getSyncParams() = FeatureType.BEHAVIOUR to null
|
||||
|
||||
private var displayMode = MODE_YEAR
|
||||
private var noticeList: List<NoticeFull>? = null
|
||||
|
@ -39,7 +39,7 @@ class LabPageFragment : BaseFragment<LabFragmentBinding, AppCompatActivity>(
|
||||
inflater = LabFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getRefreshScrollingView() = b.scrollView
|
||||
override fun getScrollingView() = b.scrollView
|
||||
|
||||
override suspend fun onViewReady(savedInstanceState: Bundle?) {
|
||||
b.app = app
|
||||
|
@ -17,7 +17,7 @@ class LabPlaygroundFragment : BaseFragment<LabPlaygroundBinding, AppCompatActivi
|
||||
inflater = LabPlaygroundBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getRefreshScrollingView() = b.root
|
||||
override fun getScrollingView() = b.root
|
||||
|
||||
override suspend fun onViewReady(savedInstanceState: Bundle?) {
|
||||
Timber.d("textColorSecondary: ${android.R.attr.textColorSecondary.resolveAttr(activity)}")
|
||||
|
@ -29,7 +29,7 @@ class LabProfileFragment : BaseFragment<TemplateListPageFragmentBinding, AppComp
|
||||
private const val TAG = "LabProfileFragment"
|
||||
}
|
||||
|
||||
override fun getRefreshScrollingView() = b.list
|
||||
override fun getScrollingView() = b.list
|
||||
|
||||
private lateinit var adapter: LabJsonAdapter
|
||||
private val loginStore by lazy {
|
||||
|
@ -18,6 +18,7 @@ import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.core.manager.GradesManager
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.full.GradeFull
|
||||
import pl.szczodrzynski.edziennik.data.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.data.enums.NavTarget
|
||||
import pl.szczodrzynski.edziennik.databinding.GradesListFragmentBinding
|
||||
@ -38,8 +39,9 @@ class GradesListFragment : BaseFragment<GradesListFragmentBinding, MainActivity>
|
||||
inflater = GradesListFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getRefreshScrollingView() = b.list
|
||||
override fun getScrollingView() = b.list
|
||||
override fun getMarkAsReadType() = MetadataType.GRADE
|
||||
override fun getSyncParams() = FeatureType.GRADES to null
|
||||
override fun getBottomSheetItems() = listOf(
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_grades_config)
|
||||
|
@ -78,7 +78,8 @@ class HomeFragment : BaseFragment<FragmentHomeBinding, MainActivity>(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRefreshScrollingView() = b.scrollView
|
||||
override fun getScrollingView() = b.scrollView
|
||||
override fun getSyncParams() = null to null
|
||||
override fun getBottomSheetItems() = listOf(
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_add_remove_cards)
|
||||
|
@ -7,6 +7,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.databinding.HomeworkListFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ext.getInt
|
||||
import pl.szczodrzynski.edziennik.ui.base.fragment.BaseFragment
|
||||
@ -20,7 +21,8 @@ class HomeworkListFragment : BaseFragment<HomeworkListFragmentBinding, MainActiv
|
||||
inflater = HomeworkListFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getRefreshScrollingView() = b.list
|
||||
override fun getScrollingView() = b.list
|
||||
override fun getSyncParams() = FeatureType.HOMEWORK to null
|
||||
|
||||
override suspend fun onViewReady(savedInstanceState: Bundle?) {
|
||||
val homeworkDate = arguments.getInt("homeworkDate", HomeworkDate.CURRENT)
|
||||
|
@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.enums.NavTarget
|
||||
import pl.szczodrzynski.edziennik.databinding.MessagesListFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ext.Bundle
|
||||
@ -27,16 +28,24 @@ class MessagesListFragment : BaseFragment<MessagesListFragmentBinding, MainActiv
|
||||
inflater = MessagesListFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getRefreshScrollingView() = b.list
|
||||
override fun getScrollingView() = b.list
|
||||
override fun getSyncParams() = when (messageType) {
|
||||
Message.TYPE_RECEIVED -> FeatureType.MESSAGES_INBOX to null
|
||||
Message.TYPE_SENT -> FeatureType.MESSAGES_SENT to null
|
||||
else -> null
|
||||
}
|
||||
|
||||
private lateinit var adapter: MessagesAdapter
|
||||
private val manager
|
||||
get() = app.messageManager
|
||||
var teachers = listOf<Teacher>()
|
||||
|
||||
private val messageType by lazy {
|
||||
arguments.getInt("messageType", Message.TYPE_RECEIVED)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override suspend fun onViewReady(savedInstanceState: Bundle?) {
|
||||
val messageType = arguments.getInt("messageType", Message.TYPE_RECEIVED)
|
||||
var recyclerViewState =
|
||||
savedInstanceState?.getParcelable<LinearLayoutManager.SavedState>("recyclerViewState")
|
||||
val searchText = savedInstanceState?.getString("searchText")
|
||||
@ -75,9 +84,6 @@ class MessagesListFragment : BaseFragment<MessagesListFragmentBinding, MainActiv
|
||||
}
|
||||
}
|
||||
|
||||
if (messageType != Message.TYPE_RECEIVED && messageType != Message.TYPE_SENT)
|
||||
canRefreshDisabled = true
|
||||
|
||||
// show/hide relevant views
|
||||
b.progressBar.isVisible = false
|
||||
b.list.isVisible = messages.isNotEmpty()
|
||||
|
@ -24,6 +24,7 @@ class NotesFragment : BaseFragment<NotesFragmentBinding, MainActivity>(
|
||||
inflater = NotesFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getScrollingView() = b.list
|
||||
override fun getFab() =
|
||||
R.string.notes_action_add to CommunityMaterial.Icon3.cmd_text_box_plus_outline
|
||||
|
||||
|
@ -27,6 +27,7 @@ class NotificationsListFragment : BaseFragment<NotificationsListFragmentBinding,
|
||||
inflater = NotificationsListFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getScrollingView() = b.list
|
||||
override fun getBottomSheetItems() = listOf(
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_remove_notifications)
|
||||
|
@ -22,6 +22,8 @@ class TeachersListFragment : BaseFragment<TeachersListFragmentBinding, MainActiv
|
||||
inflater = TeachersListFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getScrollingView() = b.list
|
||||
|
||||
override suspend fun onViewReady(savedInstanceState: Bundle?) {
|
||||
val adapter = TeachersAdapter(activity)
|
||||
|
||||
|
@ -18,7 +18,7 @@ class TemplateListFragment : BaseFragment<TemplateListFragmentBinding, MainActiv
|
||||
inflater = TemplateListFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getRefreshScrollingView() = b.list
|
||||
override fun getScrollingView() = b.list
|
||||
|
||||
override suspend fun onViewReady(savedInstanceState: Bundle?) {
|
||||
val adapter = TemplateAdapter(activity)
|
||||
|
@ -18,7 +18,7 @@ class TemplateListPageFragment : BaseFragment<TemplateListPageFragmentBinding, M
|
||||
inflater = TemplateListPageFragmentBinding::inflate,
|
||||
) {
|
||||
|
||||
override fun getRefreshScrollingView() = b.list
|
||||
override fun getScrollingView() = b.list
|
||||
|
||||
override suspend fun onViewReady(savedInstanceState: Bundle?) {
|
||||
val adapter = TemplateAdapter(activity)
|
||||
|
@ -18,11 +18,11 @@ class TemplatePageFragment : BaseFragment<TemplatePageFragmentBinding, MainActiv
|
||||
b.text.text = "Fragment VIEW READY"
|
||||
b.editText.setText(savedInstanceState.getString("editText", "default"))
|
||||
|
||||
canRefresh = true
|
||||
canRefreshDisabled = false
|
||||
b.button.addOnCheckedChangeListener { button, isChecked ->
|
||||
canRefresh = isChecked
|
||||
canRefreshDisabled = !isChecked
|
||||
}
|
||||
b.button.isChecked = canRefresh
|
||||
b.button.isChecked = !canRefreshDisabled
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
|
@ -74,6 +74,7 @@ class TimetableDayFragment : BaseFragment<TimetableDayFragmentBinding, MainActiv
|
||||
private var endHour = DEFAULT_END_HOUR
|
||||
private var firstEventMinute = 24 * 60
|
||||
private var paddingTop = 0
|
||||
private var syncArgs = JsonObject()
|
||||
|
||||
private var viewsRemoved = false
|
||||
|
||||
@ -101,7 +102,8 @@ class TimetableDayFragment : BaseFragment<TimetableDayFragmentBinding, MainActiv
|
||||
}
|
||||
private val dayView by dayViewDelegate
|
||||
|
||||
override fun getRefreshScrollingView() = b.scrollView
|
||||
override fun getScrollingView() = b.scrollView
|
||||
override fun getSyncParams() = FeatureType.TIMETABLE to syncArgs
|
||||
|
||||
override suspend fun onViewReady(savedInstanceState: Bundle?) {
|
||||
this.inflater = AsyncLayoutInflater(requireContext())
|
||||
@ -110,6 +112,10 @@ class TimetableDayFragment : BaseFragment<TimetableDayFragmentBinding, MainActiv
|
||||
startHour = arguments?.getInt("startHour") ?: DEFAULT_START_HOUR
|
||||
endHour = arguments?.getInt("endHour") ?: DEFAULT_END_HOUR
|
||||
|
||||
syncArgs = JsonObject(
|
||||
"weekStart" to date.weekStart.stringY_m_d
|
||||
)
|
||||
|
||||
// observe lesson database
|
||||
app.db.timetableDao().getAllForDate(App.profileId, date).observe(this) { lessons ->
|
||||
launch {
|
||||
|
@ -92,16 +92,10 @@
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="?colorSurfaceContainerLow"
|
||||
android:foreground="@color/colorSurface_2dp"
|
||||
android:minHeight="?actionBarSize"
|
||||
android:visibility="gone"
|
||||
app:tabIndicatorColor="?colorPrimary"
|
||||
app:tabMode="auto"
|
||||
app:tabSelectedTextColor="?colorPrimary"
|
||||
app:tabTextColor="?android:textColorPrimary"
|
||||
tools:visibility="visible" />
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
Loading…
x
Reference in New Issue
Block a user