[UI] Refactor Grades, Notifications, Homework fragments to better match unified templates.

This commit is contained in:
Kuba Szczodrzyński 2020-03-30 18:55:28 +02:00
parent b9f83875a0
commit b004ec048e
36 changed files with 871 additions and 421 deletions

View File

@ -40,6 +40,9 @@ import androidx.core.util.forEach
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.viewpager.widget.ViewPager
import com.google.android.gms.security.ProviderInstaller
import com.google.gson.JsonArray
import com.google.gson.JsonElement
@ -141,6 +144,10 @@ fun CharSequence?.isNotNullNorEmpty(): Boolean {
return this != null && this.isNotEmpty()
}
fun <T> Collection<T>?.isNotNullNorEmpty(): Boolean {
return this != null && this.isNotEmpty()
}
fun CharSequence?.isNotNullNorBlank(): Boolean {
return this != null && this.isNotBlank()
}
@ -1167,3 +1174,19 @@ fun TextView.getTextPosition(range: IntRange): Rect {
return parentTextViewRect
}
inline fun ViewPager.addOnPageSelectedListener(crossinline block: (position: Int) -> Unit) = addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) { block(position) }
})
val SwipeRefreshLayout.onScrollListener: RecyclerView.OnScrollListener
get() = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (recyclerView.canScrollVertically(-1))
this@onScrollListener.isEnabled = false
if (!recyclerView.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE)
this@onScrollListener.isEnabled = true
}
}

View File

@ -61,7 +61,7 @@ import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesListFragment
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
@ -70,7 +70,7 @@ import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeFragment
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesListFragment
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsFragment
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
import pl.szczodrzynski.edziennik.ui.modules.template.TemplateFragment
@ -155,7 +155,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
.withBadgeTypeId(TYPE_EVENT)
.isInDrawer(true)
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesFragment::class)
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesListFragment::class)
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline)
.withBadgeTypeId(TYPE_GRADE)
.isInDrawer(true)
@ -187,7 +187,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// static drawer items
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsFragment::class)
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsListFragment::class)
.withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
.isInDrawer(true)
.isStatic(true)
@ -1077,6 +1077,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
.also { if (target.icon != null) it.withIcon(target.icon!!) }
.also { if (target.title != null) it.withAppTitle(getString(target.title!!)) }
.also { if (target.badgeTypeId != null) it.withBadgeStyle(drawer.badgeStyle)}
.withSelectedBackgroundAnimated(false)
if (target.badgeTypeId != null)
drawer.addUnreadCounterType(target.badgeTypeId!!, target.id)

View File

@ -65,7 +65,7 @@ abstract class EventDao : BaseDao<Event, EventFull> {
fun getAllByDate(profileId: Int, date: Date) =
getRaw("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND eventDate = '${date.stringY_m_d}' $ORDER_BY")
fun getAllByDateTime(profileId: Int, date: Date, time: Time) =
getRaw("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND eventDate = '${date.stringY_m_d}' AND eventTime = ${time.stringValue}")
getRaw("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND eventDate = '${date.stringY_m_d}' AND eventTime = '${time.stringValue}'")
fun getNearestNotDone(profileId: Int, today: Date, limit: Int) =
getRaw("$QUERY WHERE $NOT_BLACKLISTED AND $NOT_DONE AND events.profileId = $profileId AND eventDate >= '${today.stringY_m_d}' $ORDER_BY LIMIT $limit")

View File

@ -146,6 +146,11 @@ class DayDialog(
adapter = EventListAdapter(
activity,
showWeekDay = false,
showDate = false,
showType = true,
showTime = true,
showSubject = true,
onItemClick = {
EventDetailsDialog(
activity,

View File

@ -9,6 +9,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.full.EventFull
@ -19,8 +20,11 @@ import pl.szczodrzynski.edziennik.utils.models.Week
class EventListAdapter(
val context: Context,
val simpleMode: Boolean = false,
val showDate: Boolean = false,
val showWeekDay: Boolean = false,
val showDate: Boolean = false,
val showType: Boolean = true,
val showTime: Boolean = true,
val showSubject: Boolean = true,
val onItemClick: ((event: EventFull) -> Unit)? = null,
val onEventEditClick: ((event: EventFull) -> Unit)? = null
) : RecyclerView.Adapter<EventListAdapter.ViewHolder>() {
@ -52,9 +56,9 @@ class EventListAdapter(
b.details.text = mutableListOf<CharSequence?>(
if (showWeekDay) Week.getFullDayName(event.date.weekDay) else null,
if (showDate) event.date.getRelativeString(context, 7) ?: event.date.formattedStringShort else null,
event.typeName,
if (simpleMode) null else event.time?.stringHM ?: app.getString(R.string.event_all_day),
if (simpleMode) null else event.subjectLongName
if (showType) event.typeName else null,
if (showTime) event.time?.stringHM ?: app.getString(R.string.event_all_day) else null,
if (showSubject) event.subjectLongName else null
).concat(bullet)
b.addedBy.setText(
@ -73,6 +77,7 @@ class EventListAdapter(
)
b.typeColor.background?.setTintColor(event.eventColor)
b.typeColor.isVisible = showType
b.editButton.visibility = if (event.addedManually && !simpleMode) View.VISIBLE else View.GONE
b.editButton.onClick {

View File

@ -170,6 +170,11 @@ class LessonDetailsDialog(
adapter = EventListAdapter(
activity,
showWeekDay = false,
showDate = false,
showType = true,
showTime = true,
showSubject = true,
onItemClick = {
EventDetailsDialog(
activity,

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
*/
package pl.szczodrzynski.edziennik.ui.modules.base.lazypager
import androidx.fragment.app.FragmentManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
class FragmentLazyPagerAdapter(
fragmentManager: FragmentManager,
swipeRefreshLayout: SwipeRefreshLayout,
private val fragments: List<Pair<LazyFragment, CharSequence>>
) : LazyPagerAdapter(fragmentManager, swipeRefreshLayout) {
override fun getPage(position: Int) = fragments[position].first
override fun getPageTitle(position: Int) = fragments[position].second
override fun getCount() = fragments.size
}

View File

@ -5,6 +5,7 @@
package pl.szczodrzynski.edziennik.ui.modules.base.lazypager
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.RecyclerView
abstract class LazyFragment : Fragment() {
private var isPageCreated = false
@ -25,12 +26,27 @@ abstract class LazyFragment : Fragment() {
fun disableSwipeToRefresh() = swipeRefreshLayoutCallback?.invoke(position, false)
fun setSwipeToRefresh(enabled: Boolean) = swipeRefreshLayoutCallback?.invoke(position, enabled)
val onScrollListener: RecyclerView.OnScrollListener
get() = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (recyclerView.canScrollVertically(-1))
disableSwipeToRefresh()
if (!recyclerView.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE)
enableSwipeToRefresh()
}
}
internal fun createPage() {
if (!isPageCreated && isAdded) {
isPageCreated = onPageCreated()
}
}
override fun onDestroyView() {
isPageCreated = false
super.onDestroyView()
}
override fun onResume() {
createPage()
super.onResume()

View File

@ -12,7 +12,7 @@ class LazyViewPager @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : ViewPager(context, attrs) {
var pageSelection = -1
private var pageSelection = -1
init {
addOnPageChangeListener(object : OnPageChangeListener {

View File

@ -10,11 +10,10 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2
import kotlinx.coroutines.*
@ -23,7 +22,7 @@ import pl.szczodrzynski.edziennik.MainActivity.Companion.TARGET_GRADES_EDITOR
import pl.szczodrzynski.edziennik.data.db.entity.Grade
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_GRADE
import pl.szczodrzynski.edziennik.data.db.full.GradeFull
import pl.szczodrzynski.edziennik.databinding.GradesFragmentBinding
import pl.szczodrzynski.edziennik.databinding.GradesListFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradeDetailsDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesAverages
@ -36,24 +35,20 @@ import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
import kotlin.coroutines.CoroutineContext
import kotlin.math.max
class GradesFragment : Fragment(), CoroutineScope {
class GradesListFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "GradesFragment"
}
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: GradesFragmentBinding
private lateinit var b: GradesListFragmentBinding
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
private val adapter by lazy {
GradesAdapter(activity)
}
private val manager by lazy { app.gradesManager }
private val dontCountEnabled by lazy { manager.dontCountEnabled }
private val dontCountGrades by lazy { manager.dontCountGrades }
@ -63,51 +58,49 @@ class GradesFragment : Fragment(), CoroutineScope {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
b = GradesFragmentBinding.inflate(inflater)
b = GradesListFragmentBinding.inflate(inflater)
b.refreshLayout.setParent(activity.swipeRefreshLayout)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (!isAdded)
return
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { startCoroutineTimer(100L) {
if (!isAdded) return@startCoroutineTimer
expandSubjectId = arguments?.getLong("gradesSubjectId") ?: 0L
app.db.gradeDao()
.getAllOrderBy(App.profileId, app.gradesManager.getOrderByString())
.observe(this, Observer { grades ->
if (b.gradesRecyclerView.adapter == null) {
b.gradesRecyclerView.adapter = adapter
b.gradesRecyclerView.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
//addItemDecoration(SimpleDividerItemDecoration(context))
addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (recyclerView.canScrollVertically(-1)) {
b.refreshLayout.isEnabled = false
}
if (!recyclerView.canScrollVertically(-1) && newState == SCROLL_STATE_IDLE) {
b.refreshLayout.isEnabled = true
}
}
})
}
}
val adapter = GradesAdapter(activity)
var firstRun = true
launch(Dispatchers.Default) {
processGrades(grades)
}
app.db.gradeDao().getAllOrderBy(App.profileId, app.gradesManager.getOrderByString()).observe(this, Observer { items -> launch {
if (!isAdded) return@launch
if (grades != null && grades.isNotEmpty()) {
b.gradesRecyclerView.visibility = View.VISIBLE
b.gradesNoData.visibility = View.GONE
} else {
b.gradesRecyclerView.visibility = View.GONE
b.gradesNoData.visibility = View.VISIBLE
}
})
// load & configure the adapter
adapter.items = withContext(Dispatchers.Default) { processGrades(items) }
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
b.list.adapter = adapter
b.list.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addOnScrollListener(b.refreshLayout.onScrollListener)
}
}
adapter.notifyDataSetChanged()
if (firstRun) {
expandSubject(adapter)
firstRun = false
}
// show/hide relevant views
b.progressBar.isVisible = false
if (items.isNullOrEmpty()) {
b.list.isVisible = false
b.noData.isVisible = true
} else {
b.list.isVisible = true
b.noData.isVisible = false
}
}})
adapter.onGradeClick = {
GradeDetailsDialog(activity, it)
@ -153,10 +146,30 @@ class GradesFragment : Fragment(), CoroutineScope {
})
)
activity.gainAttention()
}}
private fun expandSubject(adapter: GradesAdapter) {
var expandSubjectModel: GradesSubject? = null
if (expandSubjectId != 0L) {
expandSubjectModel = adapter.items.firstOrNull { it is GradesSubject && it.subjectId == expandSubjectId } as? GradesSubject
adapter.expandModel(
model = expandSubjectModel,
view = null,
notifyAdapter = false
)
}
startCoroutineTimer(500L) {
if (expandSubjectModel != null) {
b.list.smoothScrollToPosition(
adapter.items.indexOf(expandSubjectModel) + expandSubjectModel.semesters.size + (expandSubjectModel.semesters.firstOrNull()?.grades?.size ?: 0)
)
}
}
}
@Suppress("SuspendFunctionOnCoroutineScope")
private suspend fun processGrades(grades: List<GradeFull>) {
private fun processGrades(grades: List<GradeFull>): MutableList<Any> {
val items = mutableListOf<GradesSubject>()
var subjectId = -1L
@ -284,30 +297,7 @@ class GradesFragment : Fragment(), CoroutineScope {
GradesManager.ORDER_BY_DATE_ASC -> items.sortBy { it.lastAddedDate }
}
adapter.items = items.toMutableList()
adapter.items.add(stats)
var expandSubjectModel: GradesSubject? = null
if (expandSubjectId != 0L) {
expandSubjectModel = items.firstOrNull { it.subjectId == expandSubjectId }
adapter.expandModel(
model = expandSubjectModel,
view = null,
notifyAdapter = false
)
}
withContext(Dispatchers.Main) {
adapter.notifyDataSetChanged()
}
startCoroutineTimer(500L, 0L) {
if (expandSubjectModel != null) {
b.gradesRecyclerView.smoothScrollToPosition(
items.indexOf(expandSubjectModel) + expandSubjectModel.semesters.size + (expandSubjectModel.semesters.firstOrNull()?.grades?.size ?: 0)
)
}
}
return (items + stats).toMutableList()
}
private fun countGrade(grade: Grade, averages: GradesAverages) {

View File

@ -60,8 +60,11 @@ class HomeEventsCard(
adapter = EventListAdapter(
activity,
simpleMode = true,
showDate = true,
showWeekDay = true,
showDate = true,
showType = true,
showTime = false,
showSubject = false,
onItemClick = {
EventDetailsDialog(
activity,

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
*/
package pl.szczodrzynski.edziennik.ui.modules.homework
import android.os.AsyncTask
@ -7,46 +11,48 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.databinding.FragmentHomeworkBinding
import pl.szczodrzynski.edziennik.databinding.HomeworkFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.FragmentLazyPagerAdapter
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
import kotlin.coroutines.CoroutineContext
class HomeworkFragment : Fragment() {
class HomeworkFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "HomeworkFragment"
var pageSelection = 0
}
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: FragmentHomeworkBinding
private lateinit var b: HomeworkFragmentBinding
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null
if (context == null)
return null
context ?: return null
app = activity.application as App
context!!.theme.applyStyle(Themes.appTheme, true)
// activity, context and profile is valid
b = FragmentHomeworkBinding.inflate(inflater)
b = HomeworkFragmentBinding.inflate(inflater)
b.refreshLayout.setParent(activity.swipeRefreshLayout)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// TODO check if app, activity, b can be null
if (app.profile == null || !isAdded)
return
if (!isAdded) return
activity.bottomSheet.prependItems(
BottomSheetPrimaryItem(true)
@ -67,31 +73,28 @@ class HomeworkFragment : Fragment() {
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show()
}))
b.viewPager.adapter = MessagesFragment.Adapter(childFragmentManager, b.refreshLayout).also { adapter ->
val pagerAdapter = FragmentLazyPagerAdapter(
fragmentManager ?: return,
b.refreshLayout,
listOf(
HomeworkListFragment().apply {
arguments = Bundle("homeworkDate" to HomeworkDate.CURRENT)
} to getString(R.string.homework_tab_current),
adapter.addFragment(HomeworkListFragment().also { fragment ->
fragment.arguments = Bundle().also { args ->
args.putInt("homeworkDate", HomeworkDate.CURRENT)
}
}, getString(R.string.homework_tab_current))
adapter.addFragment(HomeworkListFragment().also { fragment ->
fragment.arguments = Bundle().also { args ->
args.putInt("homeworkDate", HomeworkDate.PAST)
}
}, getString(R.string.homework_tab_past))
}
b.viewPager.currentItem = pageSelection
b.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {
pageSelection = position
HomeworkListFragment().apply {
arguments = Bundle("homeworkDate" to HomeworkDate.PAST)
} to getString(R.string.homework_tab_past)
)
)
b.viewPager.apply {
offscreenPageLimit = 1
adapter = pagerAdapter
currentItem = pageSelection
addOnPageSelectedListener {
pageSelection = it
}
})
b.tabLayout.setupWithViewPager(b.viewPager)
b.tabLayout.setupWithViewPager(this)
}
activity.navView.apply {
bottomBar.apply {

View File

@ -4,75 +4,105 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.databinding.HomeworkListBinding
import pl.szczodrzynski.edziennik.getInt
import pl.szczodrzynski.edziennik.databinding.HomeworkListFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventDetailsDialog
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListAdapter
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.coroutines.CoroutineContext
class HomeworkListFragment : LazyFragment() {
class HomeworkListFragment : LazyFragment(), CoroutineScope {
companion object {
private const val TAG = "HomeworkListFragment"
}
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: HomeworkListBinding
private lateinit var b: HomeworkListFragmentBinding
private var homeworkDate = HomeworkDate.CURRENT
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
b = HomeworkListBinding.inflate(inflater)
b = HomeworkListFragmentBinding.inflate(inflater)
return b.root
}
override fun onPageCreated(): Boolean {
if (arguments != null) {
homeworkDate = arguments.getInt("homeworkDate", HomeworkDate.CURRENT)
override fun onPageCreated(): Boolean { startCoroutineTimer(100L) {
val homeworkDate = arguments.getInt("homeworkDate", HomeworkDate.CURRENT)
val today = Date.getToday()
val filter = when(homeworkDate) {
HomeworkDate.CURRENT -> "eventDate >= '${today.stringY_m_d}'"
else -> "eventDate < '${today.stringY_m_d}'"
}
val layoutManager = LinearLayoutManager(context)
layoutManager.reverseLayout = homeworkDate == HomeworkDate.PAST
layoutManager.stackFromEnd = homeworkDate == HomeworkDate.PAST
b.homeworkView.setHasFixedSize(true)
b.homeworkView.layoutManager = layoutManager
b.homeworkView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (recyclerView.canScrollVertically(-1)) {
setSwipeToRefresh(false)
val adapter = EventListAdapter(
activity,
showWeekDay = true,
showDate = true,
showType = false,
showTime = true,
showSubject = true,
onItemClick = {
EventDetailsDialog(
activity,
it
)
},
onEventEditClick = {
EventManualDialog(
activity,
it.profileId,
editingEvent = it
)
}
if (!recyclerView.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE) {
setSwipeToRefresh(true)
)
app.db.eventDao().getAllByType(App.profileId, Event.TYPE_HOMEWORK, filter).observe(this@HomeworkListFragment, Observer { items ->
if (!isAdded) return@Observer
// load & configure the adapter
adapter.items = items
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
b.list.adapter = adapter
b.list.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context).apply {
reverseLayout = homeworkDate == HomeworkDate.PAST
stackFromEnd = homeworkDate == HomeworkDate.PAST
}
addItemDecoration(SimpleDividerItemDecoration(context))
addOnScrollListener(onScrollListener)
}
}
adapter.notifyDataSetChanged()
// show/hide relevant views
b.progressBar.isVisible = false
if (items.isNullOrEmpty()) {
b.list.isVisible = false
b.noData.isVisible = true
} else {
b.list.isVisible = true
b.noData.isVisible = false
}
})
val filter = when(homeworkDate) {
HomeworkDate.CURRENT -> "eventDate >= '" + Date.getToday().stringY_m_d + "'"
else -> "eventDate < '" + Date.getToday().stringY_m_d + "'"
}
app.db.eventDao()
.getAllByType(App.profileId, Event.TYPE_HOMEWORK, filter)
.observe(this, Observer { homeworkList ->
if (!isAdded) return@Observer
if (homeworkList != null && homeworkList.size > 0) {
val adapter = HomeworkAdapter(context, homeworkList)
b.homeworkView.adapter = adapter
b.homeworkView.visibility = View.VISIBLE
b.homeworkNoData.visibility = View.GONE
} else {
b.homeworkView.visibility = View.GONE
b.homeworkNoData.visibility = View.VISIBLE
}
})
return true
}
}; return true }
}

View File

@ -1,71 +1,62 @@
package pl.szczodrzynski.edziennik.ui.modules.notifications
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Notification
import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.databinding.NotificationsListItemBinding
import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.coroutines.CoroutineContext
class NotificationsAdapter(
private val context: Context
) : RecyclerView.Adapter<NotificationsAdapter.ViewHolder>() {
private val activity: AppCompatActivity,
val onItemClick: ((item: Notification) -> Unit)? = null
) : RecyclerView.Adapter<NotificationsAdapter.ViewHolder>(), CoroutineScope {
companion object {
private const val TAG = "NotificationsAdapter"
}
private val app = activity.applicationContext as App
// optional: place the manager here
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
var items = listOf<Notification>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.row_notifications_item, parent, false)
val inflater = LayoutInflater.from(activity)
val view = NotificationsListItemBinding.inflate(inflater, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val app = context.applicationContext as App
val item = items[position]
val b = holder.b
val notification = items[position]
val date = Date.fromMillis(item.addedDate).formattedString
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
val date = Date.fromMillis(notification.addedDate).formattedString
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(context)
holder.title.text = notification.text
holder.profileDate.text = listOf(
notification.profileName ?: "",
b.title.text = item.text
b.profileDate.text = listOf(
item.profileName ?: "",
"",
date.asColoredSpannable(colorSecondary)
).concat()
holder.type.text = context.getNotificationTitle(notification.type)
date
).concat().asColoredSpannable(colorSecondary)
b.type.text = activity.getNotificationTitle(item.type)
holder.root.onClick {
val intent = Intent("android.intent.action.MAIN")
notification.fillIntent(intent)
d(TAG, "notification with item " + notification.viewId + " extras " + if (intent.extras == null) "null" else intent.extras!!.toString())
//Log.d(TAG, "Got date "+intent.getLongExtra("timetableDate", 0));
if (notification.profileId != null && notification.profileId != -1 && notification.profileId != app.profile.id && context is Activity) {
Toast.makeText(app, app.getString(R.string.toast_changing_profile), Toast.LENGTH_LONG).show()
}
app.sendBroadcast(intent)
onItemClick?.let { listener ->
b.root.onClick { listener(item) }
}
}
override fun getItemCount() = items.size
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var root = itemView
var title: TextView = itemView.findViewById(R.id.title)
var profileDate: TextView = itemView.findViewById(R.id.profileDate)
var type: TextView = itemView.findViewById(R.id.type)
}
class ViewHolder(val b: NotificationsListItemBinding) : RecyclerView.ViewHolder(b.root)
}

View File

@ -1,87 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-22.
*/
package pl.szczodrzynski.edziennik.ui.modules.notifications
import android.os.AsyncTask
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.FragmentNotificationsBinding
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
class NotificationsFragment : Fragment() {
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: FragmentNotificationsBinding
private val adapter by lazy {
NotificationsAdapter(activity)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
context!!.theme.applyStyle(Themes.appTheme, true)
if (app.profile == null)
return inflater.inflate(R.layout.fragment_loading, container, false)
// activity, context and profile is valid
b = FragmentNotificationsBinding.inflate(inflater)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// TODO check if app, activity, b can be null
if (app.profile == null || !isAdded)
return
activity.bottomSheet.prependItems(
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_remove_notifications)
.withIcon(CommunityMaterial.Icon.cmd_delete_sweep_outline)
.withOnClickListener(View.OnClickListener {
activity.bottomSheet.close()
AsyncTask.execute { app.db.notificationDao().clearAll() }
Toast.makeText(activity, R.string.menu_remove_notifications_success, Toast.LENGTH_SHORT).show()
}))
app.db.notificationDao()
.getAll()
.observe(this, Observer { notifications ->
if (app.profile == null || !isAdded) return@Observer
adapter.items = notifications
if (b.notificationsView.adapter == null) {
b.notificationsView.adapter = adapter
b.notificationsView.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context))
}
}
adapter.notifyDataSetChanged()
if (notifications != null && notifications.isNotEmpty()) {
b.notificationsView.visibility = View.VISIBLE
b.notificationsNoData.visibility = View.GONE
} else {
b.notificationsView.visibility = View.GONE
b.notificationsNoData.visibility = View.VISIBLE
}
})
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-22.
*/
package pl.szczodrzynski.edziennik.ui.modules.notifications
import android.app.Activity
import android.content.Intent
import android.os.AsyncTask
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.databinding.NotificationsListFragmentBinding
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import kotlin.coroutines.CoroutineContext
class NotificationsListFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "NotificationsListFragment"
}
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: NotificationsListFragmentBinding
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
b = NotificationsListFragmentBinding.inflate(inflater)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { startCoroutineTimer(100L) {
if (!isAdded) return@startCoroutineTimer
activity.bottomSheet.prependItems(
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_remove_notifications)
.withIcon(CommunityMaterial.Icon.cmd_delete_sweep_outline)
.withOnClickListener(View.OnClickListener {
activity.bottomSheet.close()
AsyncTask.execute { app.db.notificationDao().clearAll() }
Toast.makeText(activity, R.string.menu_remove_notifications_success, Toast.LENGTH_SHORT).show()
}))
val adapter = NotificationsAdapter(activity) { notification ->
val intent = Intent("android.intent.action.MAIN")
notification.fillIntent(intent)
Utils.d(TAG, "notification with item " + notification.viewId + " extras " + if (intent.extras == null) "null" else intent.extras!!.toString())
if (notification.profileId != null && notification.profileId != -1 && notification.profileId != app.profile.id && context is Activity) {
Toast.makeText(app, app.getString(R.string.toast_changing_profile), Toast.LENGTH_LONG).show()
}
app.sendBroadcast(intent)
}
app.db.notificationDao().getAll().observe(this, Observer { items ->
if (!isAdded) return@Observer
// load & configure the adapter
adapter.items = items
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
b.list.adapter = adapter
b.list.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context))
}
}
adapter.notifyDataSetChanged()
// show/hide relevant views
b.progressBar.isVisible = false
if (items.isNullOrEmpty()) {
b.list.isVisible = false
b.noData.isVisible = true
} else {
b.list.isVisible = true
b.noData.isVisible = false
}
})
}}
}

View File

@ -11,16 +11,19 @@ import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Notification
import pl.szczodrzynski.edziennik.databinding.TemplateListItemBinding
import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.coroutines.CoroutineContext
class TemplateAdapter(
val activity: AppCompatActivity,
val onItemClick: ((item: TemplateItem) -> Unit)? = null,
val onItemButtonClick: ((item: TemplateItem) -> Unit)? = null
val onItemClick: ((item: Notification) -> Unit)? = null
) : RecyclerView.Adapter<TemplateAdapter.ViewHolder>(), CoroutineScope {
companion object {
private const val TAG = "TemplateAdapter"
}
private val app = activity.applicationContext as App
// optional: place the manager here
@ -29,7 +32,7 @@ class TemplateAdapter(
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
var items = listOf<TemplateItem>()
var items = listOf<Notification>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
@ -41,19 +44,23 @@ class TemplateAdapter(
val item = items[position]
val b = holder.b
val date = Date.fromMillis(item.addedDate).formattedString
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
b.title.text = item.text
b.profileDate.text = listOf(
item.profileName ?: "",
"",
date
).concat().asColoredSpannable(colorSecondary)
b.type.text = activity.getNotificationTitle(item.type)
onItemClick?.let { listener ->
b.root.onClick { listener(item) }
}
/*b.someButton.visibility = if (buttonVisible) View.VISIBLE else View.GONE
onItemButtonClick?.let { listener ->
b.someButton.onClick { listener(item) }
}*/
}
override fun getItemCount() = items.size
class ViewHolder(val b: TemplateListItemBinding) : RecyclerView.ViewHolder(b.root)
data class TemplateItem(val text: String)
}

View File

@ -14,12 +14,16 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.addOnPageSelectedListener
import pl.szczodrzynski.edziennik.databinding.TemplateFragmentBinding
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.FragmentLazyPagerAdapter
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
import kotlin.coroutines.CoroutineContext
class TemplateFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "TemplateFragment"
var pageSelection = 0
}
private lateinit var app: App
@ -42,17 +46,29 @@ class TemplateFragment : Fragment(), CoroutineScope {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (!isAdded)
return
if (!isAdded) return
val pagerAdapter = TemplatePagerAdapter(
val pagerAdapter = FragmentLazyPagerAdapter(
fragmentManager ?: return,
b.refreshLayout
b.refreshLayout,
listOf(
TemplatePageFragment() to "Pager 0",
TemplatePageFragment() to "Pager 1",
TemplatePageFragment() to "Pager 2",
TemplatePageFragment() to "Pager 3",
TemplateListPageFragment() to "Pager 4",
TemplateListPageFragment() to "Pager 5",
TemplateListPageFragment() to "Pager 6",
TemplateListPageFragment() to "Pager 7"
)
)
b.viewPager.apply {
offscreenPageLimit = 1
adapter = pagerAdapter
currentItem = 4
currentItem = pageSelection
addOnPageSelectedListener {
HomeworkFragment.pageSelection = it
}
b.tabLayout.setupWithViewPager(this)
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
*/
package pl.szczodrzynski.edziennik.ui.modules.template
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.databinding.TemplateListFragmentBinding
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import kotlin.coroutines.CoroutineContext
class TemplateListFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "TemplateListFragment"
}
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: TemplateListFragmentBinding
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
b = TemplateListFragmentBinding.inflate(inflater)
b.refreshLayout.setParent(activity.swipeRefreshLayout)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { startCoroutineTimer(100L) {
if (!isAdded) return@startCoroutineTimer
val adapter = TemplateAdapter(activity)
app.db.notificationDao().getAll().observe(this, Observer { items ->
if (!isAdded) return@Observer
// load & configure the adapter
adapter.items = items
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
b.list.adapter = adapter
b.list.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context))
addOnScrollListener(b.refreshLayout.onScrollListener)
}
}
adapter.notifyDataSetChanged()
// show/hide relevant views
b.progressBar.isVisible = false
if (items.isNullOrEmpty()) {
b.list.isVisible = false
b.noData.isVisible = true
} else {
b.list.isVisible = true
b.noData.isVisible = false
}
})
}}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-3-30.
*/
package pl.szczodrzynski.edziennik.ui.modules.template
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.databinding.TemplateListPageFragmentBinding
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
import pl.szczodrzynski.edziennik.startCoroutineTimer
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import kotlin.coroutines.CoroutineContext
class TemplateListPageFragment : LazyFragment(), CoroutineScope {
companion object {
private const val TAG = "TemplateListPagerFragment"
}
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: TemplateListPageFragmentBinding
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
b = TemplateListPageFragmentBinding.inflate(inflater)
return b.root
}
override fun onPageCreated(): Boolean { startCoroutineTimer(100L) {
val adapter = TemplateAdapter(activity)
app.db.notificationDao().getAll().observe(this, Observer { items ->
if (!isAdded) return@Observer
// load & configure the adapter
adapter.items = items
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
b.list.adapter = adapter
b.list.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context))
addOnScrollListener(onScrollListener)
}
}
adapter.notifyDataSetChanged()
// show/hide relevant views
b.progressBar.isVisible = false
if (items.isNullOrEmpty()) {
b.list.isVisible = false
b.noData.isVisible = true
} else {
b.list.isVisible = true
b.noData.isVisible = false
}
})
}; return true }
}

View File

@ -13,18 +13,18 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.databinding.TemplatePagerFragmentBinding
import pl.szczodrzynski.edziennik.databinding.TemplatePageFragmentBinding
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
import kotlin.coroutines.CoroutineContext
class TemplatePagerFragment : LazyFragment(), CoroutineScope {
class TemplatePageFragment : LazyFragment(), CoroutineScope {
companion object {
private const val TAG = "TemplatePagerFragment"
}
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: TemplatePagerFragmentBinding
private lateinit var b: TemplatePageFragmentBinding
private val job: Job = Job()
override val coroutineContext: CoroutineContext
@ -36,7 +36,7 @@ class TemplatePagerFragment : LazyFragment(), CoroutineScope {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
b = TemplatePagerFragmentBinding.inflate(inflater)
b = TemplatePageFragmentBinding.inflate(inflater)
return b.root
}

View File

@ -9,7 +9,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyPagerAdapter
class TemplatePagerAdapter(fragmentManager: FragmentManager, swipeRefreshLayout: SwipeRefreshLayout) : LazyPagerAdapter(fragmentManager, swipeRefreshLayout) {
override fun getPage(position: Int) = TemplatePagerFragment()
override fun getPage(position: Int) = TemplatePageFragment()
override fun getPageTitle(position: Int) = "Page $position"
override fun getCount() = 10
}

View File

@ -137,7 +137,7 @@ public class Date implements Comparable<Date> {
}
public static int diffDays(Date d1, Date d2) {
return (int) ((d1.getInMillis() - d2.getInMillis()) / (24 * 60 * 60 * 1000));
return Math.round((d1.getInMillis() - d2.getInMillis()) / (24 * 60 * 60 * 1000f));
}
public static boolean isToday(Date date) {

View File

@ -0,0 +1,34 @@
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-3-30.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:viewportWidth="128"
android:viewportHeight="128">
<path
android:pathData="m102,24h-74c-4.42,0 -8,3.58 -8,8v72c0,4.42 3.58,8 8,8h74c4.42,0 8,-3.58 8,-8v-72c0,-4.42 -3.58,-8 -8,-8z"
android:fillColor="#70d0f3"/>
<path
android:pathData="m20,32v8h90v-8c0,-4.42 -3.58,-8 -8,-8h-74c-4.42,0 -8,3.58 -8,8z"
android:fillColor="#3281e6"/>
<path
android:pathData="m88,92h-30c-2.21,0 -4,-1.79 -4,-4 0,-2.21 1.79,-4 4,-4h30c2.21,0 4,1.79 4,4 0,2.21 -1.79,4 -4,4zM92,74c0,-2.21 -1.79,-4 -4,-4h-30c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h30c2.21,0 4,-1.79 4,-4zM92,60c0,-2.21 -1.79,-4 -4,-4h-30c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h30c2.21,0 4,-1.79 4,-4zM48,88c0,-2.21 -1.79,-4 -4,-4h-2c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h2c2.21,0 4,-1.79 4,-4zM48,74c0,-2.21 -1.79,-4 -4,-4h-2c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h2c2.21,0 4,-1.79 4,-4zM48,60c0,-2.21 -1.79,-4 -4,-4h-2c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4h2c2.21,0 4,-1.79 4,-4z"
android:fillColor="#2b83d5"/>
<path
android:pathData="m127,86.3 l-7.42,-7.42c-1.12,-1.13 -2.96,-1.13 -4.09,0l-3.5,3.49 11.5,11.5 3.49,-3.5c1.13,-1.13 1.13,-2.96 0,-4.09"
android:fillColor="#fc657c"/>
<path
android:pathData="m93.4,124 l-11.5,-11.5 24.5,-24.5 11.5,11.5z"
android:fillColor="#ffa859"/>
<path
android:pathData="m118,99.6 l-11.5,-11.5 5.75,-5.76 11.5,11.5z"
android:fillColor="#c8c8c8"/>
<path
android:pathData="m81.9,113 l-3.88,15.4 15.4,-3.88z"
android:fillColor="#ffcd98"/>
<path
android:pathData="m80,120 l-1.96,7.78 7.78,-1.96z"
android:fillColor="#818181"/>
</vector>

View File

@ -16,8 +16,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/gradesNoData"
android:id="@+id/noData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@ -25,13 +31,17 @@
android:fontFamily="sans-serif-light"
android:text="@string/grades_no_data"
android:textSize="24sp"
app:drawableTopCompat="@drawable/ic_no_grades" />
android:visibility="gone"
app:drawableTopCompat="@drawable/ic_no_grades"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gradesRecyclerView"
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/grades_item_subject" />
android:visibility="gone"
tools:listitem="@layout/grades_item_subject"
tools:visibility="visible" />
</FrameLayout>
</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator>
</layout>

View File

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-3-30.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
@ -27,7 +31,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator>
</layout>

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/homeworkView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
<LinearLayout
android:id="@+id/homeworkNoData"
android:layout_width="match_parent"
android:orientation="vertical"
android:gravity="center"
android:layout_height="match_parent"
android:visibility="gone"
tools:visibility="visible">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="match_parent"
android:layout_height="92dp"
app:iiv_color="?android:textColorPrimary"
app:iiv_icon="szf-file-document-edit"
app:iiv_size="92dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:text="@string/homework_no_data"
android:textSize="18sp"
android:textStyle="italic" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-3-30.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/noData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="16dp"
android:fontFamily="sans-serif-light"
android:text="@string/homework_no_data"
android:textSize="24sp"
android:visibility="gone"
app:drawableTopCompat="@drawable/ic_no_homework"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:listitem="@layout/event_list_item"
tools:visibility="visible" />
</FrameLayout>
</layout>

View File

@ -1,30 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2019-11-22.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/notificationsView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/row_notifications_item"
tools:visibility="gone" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/notificationsNoData"
android:id="@+id/noData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:drawableTopCompat="@drawable/ic_no_notifications"
android:drawablePadding="16dp"
android:fontFamily="sans-serif-light"
android:text="@string/notifications_no_data"
android:textSize="24sp"
android:visibility="gone"
app:drawableTopCompat="@drawable/ic_no_notifications"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:listitem="@layout/notifications_list_item"
tools:visibility="visible" />
</FrameLayout>
</layout>
</layout>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Dzisiaj 1 to szczęśliwy numerek" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/profileDate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:text="Władca Androida • 22 listopada" />
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Szczęśliwy numerek" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp"
android:background="?selectableItemBackground">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Dzisiaj 1 to szczęśliwy numerek" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/profileDate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:text="Władca Androida • 22 listopada" />
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Szczęśliwy numerek" />
</LinearLayout>
</LinearLayout>

View File

@ -13,7 +13,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-3-30.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/noData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="16dp"
android:fontFamily="sans-serif-light"
android:text="@string/grades_no_data"
android:textSize="24sp"
android:visibility="gone"
app:drawableTopCompat="@drawable/ic_no_grades"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:listitem="@layout/grades_item_subject"
tools:visibility="visible" />
</FrameLayout>
</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator>
</layout>

View File

@ -3,16 +3,39 @@
~ Copyright (c) Kuba Szczodrzyński 2019-12-19.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="?selectableItemBackground"
android:orientation="vertical"
android:background="?selectableItemBackground">
android:padding="8dp">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Dzisiaj 1 to szczęśliwy numerek" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/profileDate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:text="Władca Androida • 22 listopada" />
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Szczęśliwy numerek" />
</LinearLayout>
</LinearLayout>
</layout>
</layout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-3-30.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/noData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="16dp"
android:fontFamily="sans-serif-light"
android:text="@string/grades_no_data"
android:textSize="24sp"
android:visibility="gone"
app:drawableTopCompat="@drawable/ic_no_grades"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:listitem="@layout/grades_item_subject"
tools:visibility="visible" />
</FrameLayout>
</layout>