forked from github/wulkanowy-mirror
Add menu order settings (#1924)
This commit is contained in:
parent
6df3f22c7d
commit
32d6b4a7a6
@ -10,6 +10,7 @@ import io.github.wulkanowy.R
|
|||||||
import io.github.wulkanowy.data.enums.*
|
import io.github.wulkanowy.data.enums.*
|
||||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
||||||
|
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
@ -28,9 +29,6 @@ class PreferencesRepository @Inject constructor(
|
|||||||
private val json: Json,
|
private val json: Json,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val startMenuIndex: Int
|
|
||||||
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
|
|
||||||
|
|
||||||
val isShowPresent: Boolean
|
val isShowPresent: Boolean
|
||||||
get() = getBoolean(
|
get() = getBoolean(
|
||||||
R.string.pref_key_attendance_present,
|
R.string.pref_key_attendance_present,
|
||||||
@ -315,6 +313,20 @@ class PreferencesRepository @Inject constructor(
|
|||||||
putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
|
putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var appMenuItemOrder: List<AppMenuItem>
|
||||||
|
get() {
|
||||||
|
val value = sharedPref.getString(PREF_KEY_APP_MENU_ITEM_ORDER, null)
|
||||||
|
?: return AppMenuItem.defaultAppMenuItemList
|
||||||
|
|
||||||
|
return json.decodeFromString(value)
|
||||||
|
}
|
||||||
|
set(value) = sharedPref.edit {
|
||||||
|
putString(
|
||||||
|
PREF_KEY_APP_MENU_ITEM_ORDER,
|
||||||
|
json.encodeToString(value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
var installationId: String
|
var installationId: String
|
||||||
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
||||||
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
||||||
@ -341,6 +353,7 @@ class PreferencesRepository @Inject constructor(
|
|||||||
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
private const val PREF_KEY_APP_MENU_ITEM_ORDER = "app_menu_item_order"
|
||||||
private const val PREF_KEY_INSTALLATION_ID = "installation_id"
|
private const val PREF_KEY_INSTALLATION_ID = "installation_id"
|
||||||
private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position"
|
private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position"
|
||||||
private const val PREF_KEY_IN_APP_REVIEW_COUNT = "in_app_review_count"
|
private const val PREF_KEY_IN_APP_REVIEW_COUNT = "in_app_review_count"
|
||||||
|
@ -10,10 +10,12 @@ import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
|||||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||||
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment
|
||||||
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
||||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||||
import io.github.wulkanowy.ui.modules.schoolandteachers.school.SchoolFragment
|
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment
|
||||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@ -39,10 +41,12 @@ sealed class Destination {
|
|||||||
NOTE(Note),
|
NOTE(Note),
|
||||||
CONFERENCE(Conference),
|
CONFERENCE(Conference),
|
||||||
SCHOOL_ANNOUNCEMENT(SchoolAnnouncement),
|
SCHOOL_ANNOUNCEMENT(SchoolAnnouncement),
|
||||||
SCHOOL(School),
|
SCHOOL_AND_TEACHERS(SchoolAndTeachers),
|
||||||
LUCKY_NUMBER(More),
|
LUCKY_NUMBER(LuckyNumber),
|
||||||
MORE(More),
|
MORE(More),
|
||||||
MESSAGE(Message);
|
MESSAGE(Message),
|
||||||
|
MOBILE_DEVICE(MobileDevice),
|
||||||
|
SETTINGS(Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -103,9 +107,9 @@ sealed class Destination {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object School : Destination() {
|
object SchoolAndTeachers : Destination() {
|
||||||
override val destinationType get() = Type.SCHOOL
|
override val destinationType get() = Type.SCHOOL_AND_TEACHERS
|
||||||
override val destinationFragment get() = SchoolFragment.newInstance()
|
override val destinationFragment get() = SchoolAndTeachersFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -125,4 +129,16 @@ sealed class Destination {
|
|||||||
override val destinationType get() = Type.MESSAGE
|
override val destinationType get() = Type.MESSAGE
|
||||||
override val destinationFragment get() = MessageFragment.newInstance()
|
override val destinationFragment get() = MessageFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
object MobileDevice : Destination() {
|
||||||
|
override val destinationType get() = Type.MOBILE_DEVICE
|
||||||
|
override val destinationFragment get() = MobileDeviceFragment.newInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
object Settings : Destination() {
|
||||||
|
override val destinationType get() = Type.SETTINGS
|
||||||
|
override val destinationFragment get() = SettingsFragment.newInstance()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ConferenceFragment : BaseFragment<FragmentConferenceBinding>(R.layout.fragment_conference),
|
class ConferenceFragment : BaseFragment<FragmentConferenceBinding>(R.layout.fragment_conference),
|
||||||
ConferenceView, MainView.TitledView {
|
ConferenceView, MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: ConferencePresenter
|
lateinit var presenter: ConferencePresenter
|
||||||
@ -109,6 +109,14 @@ class ConferenceFragment : BaseFragment<FragmentConferenceBinding>(R.layout.frag
|
|||||||
(activity as? MainActivity)?.showDialogFragment(ConferenceDialog.newInstance(conference))
|
(activity as? MainActivity)?.showDialogFragment(ConferenceDialog.newInstance(conference))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onFragmentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.conferenceRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -96,4 +96,11 @@ class ConferencePresenter @Inject constructor(
|
|||||||
.onResourceError(errorHandler::dispatch)
|
.onResourceError(errorHandler::dispatch)
|
||||||
.launch()
|
.launch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onFragmentReselected() {
|
||||||
|
Timber.i("Conference is reselected")
|
||||||
|
if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,4 +28,6 @@ interface ConferenceView : BaseView {
|
|||||||
fun showContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
fun openConferenceDialog(conference: Conference)
|
fun openConferenceDialog(conference: Conference)
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,7 @@ package io.github.wulkanowy.ui.modules.exam
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.*
|
||||||
import android.view.View.INVISIBLE
|
|
||||||
import android.view.View.VISIBLE
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
@ -20,7 +18,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ExamFragment : BaseFragment<FragmentExamBinding>(R.layout.fragment_exam), ExamView,
|
class ExamFragment : BaseFragment<FragmentExamBinding>(R.layout.fragment_exam), ExamView,
|
||||||
MainView.TitledView {
|
MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: ExamPresenter
|
lateinit var presenter: ExamPresenter
|
||||||
@ -126,6 +124,14 @@ class ExamFragment : BaseFragment<FragmentExamBinding>(R.layout.fragment_exam),
|
|||||||
(activity as? MainActivity)?.showDialogFragment(ExamDialog.newInstance(exam))
|
(activity as? MainActivity)?.showDialogFragment(ExamDialog.newInstance(exam))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.examRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||||
|
@ -175,4 +175,17 @@ class ExamPresenter @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onViewReselected() {
|
||||||
|
Timber.i("Exam view is reselected")
|
||||||
|
|
||||||
|
baseDate = now().nextOrSameSchoolDay
|
||||||
|
|
||||||
|
if (currentDate != baseDate) {
|
||||||
|
reloadView(baseDate)
|
||||||
|
loadData()
|
||||||
|
} else if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,4 +34,6 @@ interface ExamView : BaseView {
|
|||||||
fun showPreButton(show: Boolean)
|
fun showPreButton(show: Boolean)
|
||||||
|
|
||||||
fun showExamDialog(exam: Exam)
|
fun showExamDialog(exam: Exam)
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class HomeworkFragment : BaseFragment<FragmentHomeworkBinding>(R.layout.fragment_homework),
|
class HomeworkFragment : BaseFragment<FragmentHomeworkBinding>(R.layout.fragment_homework),
|
||||||
HomeworkView, MainView.TitledView {
|
HomeworkView, MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: HomeworkPresenter
|
lateinit var presenter: HomeworkPresenter
|
||||||
@ -133,6 +133,14 @@ class HomeworkFragment : BaseFragment<FragmentHomeworkBinding>(R.layout.fragment
|
|||||||
(activity as? MainActivity)?.showDialogFragment(HomeworkAddDialog())
|
(activity as? MainActivity)?.showDialogFragment(HomeworkAddDialog())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.homeworkRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||||
|
@ -181,4 +181,17 @@ class HomeworkPresenter @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onViewReselected() {
|
||||||
|
Timber.i("Homework view is reselected")
|
||||||
|
|
||||||
|
baseDate = LocalDate.now().nextOrSameSchoolDay
|
||||||
|
|
||||||
|
if (currentDate != baseDate) {
|
||||||
|
reloadView(baseDate)
|
||||||
|
loadData()
|
||||||
|
} else if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,4 +36,6 @@ interface HomeworkView : BaseView {
|
|||||||
fun showHomeworkDialog(homework: Homework)
|
fun showHomeworkDialog(homework: Homework)
|
||||||
|
|
||||||
fun showAddHomeworkDialog()
|
fun showAddHomeworkDialog()
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import javax.inject.Inject
|
|||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class LuckyNumberFragment :
|
class LuckyNumberFragment :
|
||||||
BaseFragment<FragmentLuckyNumberBinding>(R.layout.fragment_lucky_number), LuckyNumberView,
|
BaseFragment<FragmentLuckyNumberBinding>(R.layout.fragment_lucky_number), LuckyNumberView,
|
||||||
MainView.TitledView {
|
MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: LuckyNumberPresenter
|
lateinit var presenter: LuckyNumberPresenter
|
||||||
@ -86,6 +86,14 @@ class LuckyNumberFragment :
|
|||||||
(activity as? MainActivity)?.pushView(LuckyNumberHistoryFragment.newInstance())
|
(activity as? MainActivity)?.pushView(LuckyNumberHistoryFragment.newInstance())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popView() {
|
||||||
|
(activity as? MainActivity)?.popView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -99,4 +99,9 @@ class LuckyNumberPresenter @Inject constructor(
|
|||||||
fun onDetailsClick() {
|
fun onDetailsClick() {
|
||||||
view?.showErrorDetailsDialog(lastError)
|
view?.showErrorDetailsDialog(lastError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onViewReselected() {
|
||||||
|
Timber.i("Luckynumber view is reselected")
|
||||||
|
view?.popView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,4 +26,6 @@ interface LuckyNumberView : BaseView {
|
|||||||
fun showContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
fun openLuckyNumberHistory()
|
fun openLuckyNumberHistory()
|
||||||
|
|
||||||
|
fun popView()
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import io.github.wulkanowy.databinding.DialogAdsConsentBinding
|
|||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||||
|
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.*
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -124,13 +125,20 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView(startMenuIndex: Int, rootDestinations: List<Destination>) {
|
override fun initView(
|
||||||
|
startMenuIndex: Int,
|
||||||
|
rootAppMenuItems: List<AppMenuItem>,
|
||||||
|
rootUpdatedDestinations: List<Destination>
|
||||||
|
) {
|
||||||
initializeToolbar()
|
initializeToolbar()
|
||||||
initializeBottomNavigation(startMenuIndex)
|
initializeBottomNavigation(startMenuIndex, rootAppMenuItems)
|
||||||
initializeNavController(startMenuIndex, rootDestinations)
|
initializeNavController(startMenuIndex, rootUpdatedDestinations)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeNavController(startMenuIndex: Int, rootDestinations: List<Destination>) {
|
private fun initializeNavController(
|
||||||
|
startMenuIndex: Int,
|
||||||
|
rootUpdatedDestinations: List<Destination>
|
||||||
|
) {
|
||||||
with(navController) {
|
with(navController) {
|
||||||
setOnViewChangeListener { destinationView ->
|
setOnViewChangeListener { destinationView ->
|
||||||
presenter.onViewChange(destinationView)
|
presenter.onViewChange(destinationView)
|
||||||
@ -140,7 +148,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
fragmentHideStrategy = HIDE
|
fragmentHideStrategy = HIDE
|
||||||
rootFragments = rootDestinations.map { it.destinationFragment }
|
rootFragments = rootUpdatedDestinations.map { it.destinationFragment }
|
||||||
|
|
||||||
initialize(startMenuIndex, savedInstanceState)
|
initialize(startMenuIndex, savedInstanceState)
|
||||||
}
|
}
|
||||||
@ -156,17 +164,16 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeBottomNavigation(startMenuIndex: Int) {
|
private fun initializeBottomNavigation(
|
||||||
|
startMenuIndex: Int,
|
||||||
|
rootAppMenuItems: List<AppMenuItem>
|
||||||
|
) {
|
||||||
with(binding.mainBottomNav) {
|
with(binding.mainBottomNav) {
|
||||||
with(menu) {
|
with(menu) {
|
||||||
add(Menu.NONE, 0, Menu.NONE, R.string.dashboard_title)
|
rootAppMenuItems.forEachIndexed { index, item ->
|
||||||
.setIcon(R.drawable.ic_main_dashboard)
|
add(Menu.NONE, index, Menu.NONE, item.title)
|
||||||
add(Menu.NONE, 1, Menu.NONE, R.string.grade_title)
|
.setIcon(item.icon)
|
||||||
.setIcon(R.drawable.ic_main_grade)
|
}
|
||||||
add(Menu.NONE, 2, Menu.NONE, R.string.attendance_title)
|
|
||||||
.setIcon(R.drawable.ic_main_attendance)
|
|
||||||
add(Menu.NONE, 3, Menu.NONE, R.string.timetable_title)
|
|
||||||
.setIcon(R.drawable.ic_main_timetable)
|
|
||||||
add(Menu.NONE, 4, Menu.NONE, R.string.more_title)
|
add(Menu.NONE, 4, Menu.NONE, R.string.more_title)
|
||||||
.setIcon(R.drawable.ic_main_more)
|
.setIcon(R.drawable.ic_main_more)
|
||||||
}
|
}
|
||||||
|
@ -42,17 +42,16 @@ class MainPresenter @Inject constructor(
|
|||||||
|
|
||||||
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
||||||
|
|
||||||
private val rootDestinationTypeList = listOf(
|
private val rootAppMenuItems = preferencesRepository.appMenuItemOrder
|
||||||
Destination.Type.DASHBOARD,
|
.sortedBy { it.order }
|
||||||
Destination.Type.GRADE,
|
.take(4)
|
||||||
Destination.Type.ATTENDANCE,
|
|
||||||
Destination.Type.TIMETABLE,
|
private val rootDestinationTypeList = rootAppMenuItems.map { it.destinationType }
|
||||||
Destination.Type.MORE
|
.plus(Destination.Type.MORE)
|
||||||
)
|
|
||||||
|
|
||||||
private val Destination?.startMenuIndex
|
private val Destination?.startMenuIndex
|
||||||
get() = when {
|
get() = when {
|
||||||
this == null -> preferencesRepository.startMenuIndex
|
this == null -> 0
|
||||||
destinationType in rootDestinationTypeList -> {
|
destinationType in rootDestinationTypeList -> {
|
||||||
rootDestinationTypeList.indexOf(destinationType)
|
rootDestinationTypeList.indexOf(destinationType)
|
||||||
}
|
}
|
||||||
@ -69,7 +68,7 @@ class MainPresenter @Inject constructor(
|
|||||||
if (it == initDestination?.destinationType) initDestination else it.defaultDestination
|
if (it == initDestination?.destinationType) initDestination else it.defaultDestination
|
||||||
}
|
}
|
||||||
|
|
||||||
view.initView(startMenuIndex, destinations)
|
view.initView(startMenuIndex, rootAppMenuItems, destinations)
|
||||||
if (initDestination != null && startMenuIndex == 4) {
|
if (initDestination != null && startMenuIndex == 4) {
|
||||||
view.openMoreDestination(initDestination)
|
view.openMoreDestination(initDestination)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
|
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
|
||||||
|
|
||||||
interface MainView : BaseView {
|
interface MainView : BaseView {
|
||||||
|
|
||||||
@ -15,7 +16,11 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
val currentStackSize: Int?
|
val currentStackSize: Int?
|
||||||
|
|
||||||
fun initView(startMenuIndex: Int, rootDestinations: List<Destination>)
|
fun initView(
|
||||||
|
startMenuIndex: Int,
|
||||||
|
rootAppMenuItems: List<AppMenuItem>,
|
||||||
|
rootUpdatedDestinations: List<Destination>
|
||||||
|
)
|
||||||
|
|
||||||
fun switchMenuView(position: Int)
|
fun switchMenuView(position: Int)
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import io.github.wulkanowy.data.enums.MessageFolder.*
|
|||||||
import io.github.wulkanowy.databinding.FragmentMessageBinding
|
import io.github.wulkanowy.databinding.FragmentMessageBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
|
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
||||||
import io.github.wulkanowy.ui.modules.message.tab.MessageTabFragment
|
import io.github.wulkanowy.ui.modules.message.tab.MessageTabFragment
|
||||||
@ -24,7 +25,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_message),
|
class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_message),
|
||||||
MessageView, MainView.TitledView {
|
MessageView, MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: MessagePresenter
|
lateinit var presenter: MessagePresenter
|
||||||
@ -123,8 +124,12 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
|
|||||||
presenter.onChildViewShowNewMessage(show)
|
presenter.onChildViewShowNewMessage(show)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onFragmentChanged() {
|
override fun onFragmentReselected() {
|
||||||
presenter.onFragmentChanged()
|
if (::presenter.isInitialized) presenter.onFragmentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentChanged() {
|
||||||
|
if (::presenter.isInitialized) presenter.onFragmentChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) {
|
override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) {
|
||||||
@ -139,10 +144,19 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun notifyChildParentReselected(index: Int) {
|
||||||
|
(pagerAdapter.getFragmentInstance(index) as? MessageTabFragment)
|
||||||
|
?.onParentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
override fun openSendMessage() {
|
override fun openSendMessage() {
|
||||||
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it)) }
|
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun popView() {
|
||||||
|
(activity as? MainActivity)?.popView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -39,6 +39,14 @@ class MessagePresenter @Inject constructor(
|
|||||||
view?.notifyChildrenFinishActionMode()
|
view?.notifyChildrenFinishActionMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onFragmentReselected() {
|
||||||
|
Timber.i("Message view is reselected")
|
||||||
|
view?.run {
|
||||||
|
popView()
|
||||||
|
notifyChildParentReselected(currentPageIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onChildViewLoaded() {
|
fun onChildViewLoaded() {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showContent(true)
|
showContent(true)
|
||||||
|
@ -20,5 +20,9 @@ interface MessageView : BaseView {
|
|||||||
|
|
||||||
fun notifyChildrenFinishActionMode()
|
fun notifyChildrenFinishActionMode()
|
||||||
|
|
||||||
|
fun notifyChildParentReselected(index: Int)
|
||||||
|
|
||||||
fun openSendMessage()
|
fun openSendMessage()
|
||||||
|
|
||||||
|
fun popView()
|
||||||
}
|
}
|
||||||
|
@ -235,6 +235,10 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
presenter.onParentFinishActionMode()
|
presenter.onParentFinishActionMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onParentReselected() {
|
||||||
|
presenter.onParentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
private fun onChipChecked(chip: CompoundButton, isChecked: Boolean) {
|
private fun onChipChecked(chip: CompoundButton, isChecked: Boolean) {
|
||||||
when (chip.id) {
|
when (chip.id) {
|
||||||
R.id.chip_unread -> presenter.onUnreadFilterSelected(isChecked)
|
R.id.chip_unread -> presenter.onUnreadFilterSelected(isChecked)
|
||||||
|
@ -83,6 +83,14 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
view?.showActionMode(false)
|
view?.showActionMode(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onParentReselected() {
|
||||||
|
view?.run {
|
||||||
|
if (!isViewEmpty) {
|
||||||
|
resetListPosition()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onDestroyActionMode() {
|
fun onDestroyActionMode() {
|
||||||
isActionMode = false
|
isActionMode = false
|
||||||
messagesToDelete.clear()
|
messagesToDelete.clear()
|
||||||
|
@ -22,7 +22,7 @@ import javax.inject.Inject
|
|||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MobileDeviceFragment :
|
class MobileDeviceFragment :
|
||||||
BaseFragment<FragmentMobileDeviceBinding>(R.layout.fragment_mobile_device), MobileDeviceView,
|
BaseFragment<FragmentMobileDeviceBinding>(R.layout.fragment_mobile_device), MobileDeviceView,
|
||||||
MainView.TitledView {
|
MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: MobileDevicePresenter
|
lateinit var presenter: MobileDevicePresenter
|
||||||
@ -135,6 +135,14 @@ class MobileDeviceFragment :
|
|||||||
(activity as? MainActivity)?.showDialogFragment(MobileDeviceTokenDialog.newInstance())
|
(activity as? MainActivity)?.showDialogFragment(MobileDeviceTokenDialog.newInstance())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onFragmentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.mobileDevicesRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -129,4 +129,10 @@ class MobileDevicePresenter @Inject constructor(
|
|||||||
.onResourceError(errorHandler::dispatch)
|
.onResourceError(errorHandler::dispatch)
|
||||||
.launch("unregister")
|
.launch("unregister")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onFragmentReselected() {
|
||||||
|
if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,4 +32,6 @@ interface MobileDeviceView : BaseView {
|
|||||||
fun setErrorDetails(message: String)
|
fun setErrorDetails(message: String)
|
||||||
|
|
||||||
fun showTokenDialog()
|
fun showTokenDialog()
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.more
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -9,9 +8,9 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class MoreAdapter @Inject constructor() : RecyclerView.Adapter<MoreAdapter.ItemViewHolder>() {
|
class MoreAdapter @Inject constructor() : RecyclerView.Adapter<MoreAdapter.ItemViewHolder>() {
|
||||||
|
|
||||||
var items = emptyList<Pair<String, Drawable?>>()
|
var items = emptyList<MoreItem>()
|
||||||
|
|
||||||
var onClickListener: (name: String) -> Unit = {}
|
var onClickListener: (moreItem: MoreItem) -> Unit = {}
|
||||||
|
|
||||||
override fun getItemCount() = items.size
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
@ -20,13 +19,14 @@ class MoreAdapter @Inject constructor() : RecyclerView.Adapter<MoreAdapter.ItemV
|
|||||||
)
|
)
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
||||||
val (title, drawable) = items[position]
|
val item = items[position]
|
||||||
|
val context = holder.binding.root.context
|
||||||
|
|
||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
moreItemTitle.text = title
|
moreItemTitle.text = context.getString(item.title)
|
||||||
moreItemImage.setImageDrawable(drawable)
|
moreItemImage.setImageResource(item.icon)
|
||||||
|
|
||||||
root.setOnClickListener { onClickListener(title) }
|
root.setOnClickListener { onClickListener(item) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.more
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
@ -8,19 +7,10 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.databinding.FragmentMoreBinding
|
import io.github.wulkanowy.databinding.FragmentMoreBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
|
||||||
import io.github.wulkanowy.utils.getCompatDrawable
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
@ -40,36 +30,6 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
|||||||
override val titleStringId: Int
|
override val titleStringId: Int
|
||||||
get() = R.string.more_title
|
get() = R.string.more_title
|
||||||
|
|
||||||
override val messagesRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.message_title) to getCompatDrawable(R.drawable.ic_more_messages) }
|
|
||||||
|
|
||||||
override val homeworkRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.homework_title) to getCompatDrawable(R.drawable.ic_more_homework) }
|
|
||||||
|
|
||||||
override val noteRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.note_title) to getCompatDrawable(R.drawable.ic_more_note) }
|
|
||||||
|
|
||||||
override val conferencesRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.conferences_title) to getCompatDrawable(R.drawable.ic_more_conferences) }
|
|
||||||
|
|
||||||
override val schoolAnnouncementRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.school_announcement_title) to getCompatDrawable(R.drawable.ic_all_about) }
|
|
||||||
|
|
||||||
override val schoolAndTeachersRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.schoolandteachers_title) to getCompatDrawable((R.drawable.ic_more_schoolandteachers)) }
|
|
||||||
|
|
||||||
override val mobileDevicesRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.mobile_devices_title) to getCompatDrawable(R.drawable.ic_more_mobile_devices) }
|
|
||||||
|
|
||||||
override val settingsRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.settings_title) to getCompatDrawable(R.drawable.ic_more_settings) }
|
|
||||||
|
|
||||||
override val examRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.exam_title) to getCompatDrawable(R.drawable.ic_main_exam) }
|
|
||||||
|
|
||||||
override val luckyNumberRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.lucky_number_title) to getCompatDrawable(R.drawable.ic_more_lucky_number) }
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding = FragmentMoreBinding.bind(view)
|
binding = FragmentMoreBinding.bind(view)
|
||||||
@ -94,57 +54,21 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
|||||||
?.onFragmentChanged()
|
?.onFragmentChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateData(data: List<Pair<String, Drawable?>>) {
|
override fun updateData(data: List<MoreItem>) {
|
||||||
with(moreAdapter) {
|
with(moreAdapter) {
|
||||||
items = data
|
items = data
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openMessagesView() {
|
|
||||||
(activity as? MainActivity)?.pushView(MessageFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openHomeworkView() {
|
|
||||||
(activity as? MainActivity)?.pushView(HomeworkFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openNoteView() {
|
|
||||||
(activity as? MainActivity)?.pushView(NoteFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openSchoolAnnouncementView() {
|
|
||||||
(activity as? MainActivity)?.pushView(SchoolAnnouncementFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openConferencesView() {
|
|
||||||
(activity as? MainActivity)?.pushView(ConferenceFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openSchoolAndTeachersView() {
|
|
||||||
(activity as? MainActivity)?.pushView(SchoolAndTeachersFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openMobileDevicesView() {
|
|
||||||
(activity as? MainActivity)?.pushView(MobileDeviceFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openSettingsView() {
|
|
||||||
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openExamView() {
|
|
||||||
(activity as? MainActivity)?.pushView(ExamFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openLuckyNumberView() {
|
|
||||||
(activity as? MainActivity)?.pushView(LuckyNumberFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popView(depth: Int) {
|
override fun popView(depth: Int) {
|
||||||
(activity as? MainActivity)?.popView(depth)
|
(activity as? MainActivity)?.popView(depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openView(destination: Destination) {
|
||||||
|
(activity as? MainActivity)?.pushView(destination.destinationFragment)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
|
|
||||||
|
data class MoreItem(
|
||||||
|
|
||||||
|
val icon: Int,
|
||||||
|
|
||||||
|
val title: Int,
|
||||||
|
|
||||||
|
val destination: Destination
|
||||||
|
)
|
@ -1,16 +1,24 @@
|
|||||||
package io.github.wulkanowy.ui.modules.more
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MorePresenter @Inject constructor(
|
class MorePresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository
|
studentRepository: StudentRepository,
|
||||||
|
preferencesRepository: PreferencesRepository
|
||||||
) : BasePresenter<MoreView>(errorHandler, studentRepository) {
|
) : BasePresenter<MoreView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
private val moreAppMenuItem = preferencesRepository.appMenuItemOrder
|
||||||
|
.sortedBy { it.order }
|
||||||
|
.drop(4)
|
||||||
|
|
||||||
override fun onAttachView(view: MoreView) {
|
override fun onAttachView(view: MoreView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
@ -18,22 +26,10 @@ class MorePresenter @Inject constructor(
|
|||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onItemSelected(title: String) {
|
fun onItemSelected(moreItem: MoreItem) {
|
||||||
Timber.i("Select more item \"${title}\"")
|
Timber.i("Select more item \"${moreItem.destination.destinationType}\"")
|
||||||
view?.run {
|
|
||||||
when (title) {
|
view?.openView(moreItem.destination)
|
||||||
messagesRes?.first -> openMessagesView()
|
|
||||||
examRes?.first -> openExamView()
|
|
||||||
homeworkRes?.first -> openHomeworkView()
|
|
||||||
noteRes?.first -> openNoteView()
|
|
||||||
conferencesRes?.first -> openConferencesView()
|
|
||||||
schoolAnnouncementRes?.first -> openSchoolAnnouncementView()
|
|
||||||
schoolAndTeachersRes?.first -> openSchoolAndTeachersView()
|
|
||||||
mobileDevicesRes?.first -> openMobileDevicesView()
|
|
||||||
settingsRes?.first -> openSettingsView()
|
|
||||||
luckyNumberRes?.first -> openLuckyNumberView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onViewReselected() {
|
fun onViewReselected() {
|
||||||
@ -43,19 +39,21 @@ class MorePresenter @Inject constructor(
|
|||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
Timber.i("Load items for more view")
|
Timber.i("Load items for more view")
|
||||||
view?.run {
|
val moreItems = moreAppMenuItem.map {
|
||||||
updateData(listOfNotNull(
|
MoreItem(
|
||||||
messagesRes,
|
icon = it.icon,
|
||||||
examRes,
|
title = it.title,
|
||||||
homeworkRes,
|
destination = it.destinationType.defaultDestination
|
||||||
noteRes,
|
)
|
||||||
luckyNumberRes,
|
}
|
||||||
conferencesRes,
|
.plus(
|
||||||
schoolAnnouncementRes,
|
MoreItem(
|
||||||
schoolAndTeachersRes,
|
icon = R.drawable.ic_more_settings,
|
||||||
mobileDevicesRes,
|
title = R.string.settings_title,
|
||||||
settingsRes
|
destination = Destination.Settings
|
||||||
))
|
)
|
||||||
}
|
)
|
||||||
|
|
||||||
|
view?.updateData(moreItems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,15 @@
|
|||||||
package io.github.wulkanowy.ui.modules.more
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
|
|
||||||
interface MoreView : BaseView {
|
interface MoreView : BaseView {
|
||||||
|
|
||||||
val messagesRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val homeworkRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val noteRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val conferencesRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val schoolAnnouncementRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val schoolAndTeachersRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val mobileDevicesRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val settingsRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val examRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val luckyNumberRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateData(data: List<Pair<String, Drawable?>>)
|
fun updateData(data: List<MoreItem>)
|
||||||
|
|
||||||
fun openSettingsView()
|
|
||||||
|
|
||||||
fun popView(depth: Int)
|
fun popView(depth: Int)
|
||||||
|
|
||||||
fun openMessagesView()
|
fun openView(destination: Destination)
|
||||||
|
|
||||||
fun openHomeworkView()
|
|
||||||
|
|
||||||
fun openNoteView()
|
|
||||||
|
|
||||||
fun openSchoolAnnouncementView()
|
|
||||||
|
|
||||||
fun openConferencesView()
|
|
||||||
|
|
||||||
fun openSchoolAndTeachersView()
|
|
||||||
|
|
||||||
fun openMobileDevicesView()
|
|
||||||
|
|
||||||
fun openExamView()
|
|
||||||
|
|
||||||
fun openLuckyNumberView()
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class NoteFragment : BaseFragment<FragmentNoteBinding>(R.layout.fragment_note), NoteView,
|
class NoteFragment : BaseFragment<FragmentNoteBinding>(R.layout.fragment_note), NoteView,
|
||||||
MainView.TitledView {
|
MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: NotePresenter
|
lateinit var presenter: NotePresenter
|
||||||
@ -112,6 +112,14 @@ class NoteFragment : BaseFragment<FragmentNoteBinding>(R.layout.fragment_note),
|
|||||||
binding.noteSwipe.isRefreshing = show
|
binding.noteSwipe.isRefreshing = show
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onFragmentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.noteRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -121,4 +121,10 @@ class NotePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
.launch("update_note")
|
.launch("update_note")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onFragmentReselected() {
|
||||||
|
if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,4 +30,6 @@ interface NoteView : BaseView {
|
|||||||
fun showRefresh(show: Boolean)
|
fun showRefresh(show: Boolean)
|
||||||
|
|
||||||
fun showNoteDialog(note: Note)
|
fun showNoteDialog(note: Note)
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,206 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance.menuorder
|
||||||
|
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.Transient
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed class AppMenuItem {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val defaultAppMenuItemList = setOf(
|
||||||
|
DashboardAppMenuItem(),
|
||||||
|
GradeAppMenuItem(),
|
||||||
|
TimetableAppMenuItem(),
|
||||||
|
AttendanceAppMenuItem(),
|
||||||
|
ExamsAppMenuItem(),
|
||||||
|
HomeworkAppMenuItem(),
|
||||||
|
NoteAppMenuItem(),
|
||||||
|
LuckyNumberAppMenuItem(),
|
||||||
|
SchoolAnnouncementsAppMenuItem(),
|
||||||
|
SchoolAndTeachersAppMenuItem(),
|
||||||
|
MobileDevicesAppMenuItem(),
|
||||||
|
ConferenceAppMenuItem(),
|
||||||
|
MessageAppMenuItem()
|
||||||
|
).sortedBy { it.order }
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://youtrack.jetbrains.com/issue/KT-38958
|
||||||
|
abstract var order: Int
|
||||||
|
|
||||||
|
abstract val icon: Int
|
||||||
|
|
||||||
|
abstract val title: Int
|
||||||
|
|
||||||
|
abstract val destinationType: Destination.Type
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DashboardAppMenuItem(override var order: Int = 0) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_main_dashboard
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.dashboard_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.DASHBOARD
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GradeAppMenuItem(override var order: Int = 1) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_main_grade
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.grade_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.GRADE
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AttendanceAppMenuItem(override var order: Int = 2) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_main_attendance
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.attendance_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.ATTENDANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class TimetableAppMenuItem(override var order: Int = 3) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_main_timetable
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.timetable_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.TIMETABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class MessageAppMenuItem(override var order: Int = 4) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_more_messages
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.message_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.MESSAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ExamsAppMenuItem(override var order: Int = 5) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_main_exam
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.exam_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.EXAM
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class HomeworkAppMenuItem(override var order: Int = 6) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_more_homework
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.homework_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.HOMEWORK
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class NoteAppMenuItem(override var order: Int = 7) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_more_note
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.note_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.NOTE
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LuckyNumberAppMenuItem(override var order: Int = 8) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_more_lucky_number
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.lucky_number_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.LUCKY_NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ConferenceAppMenuItem(override var order: Int = 9) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_more_conferences
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.conferences_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.CONFERENCE
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SchoolAnnouncementsAppMenuItem(override var order: Int = 10) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_all_about
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.school_announcement_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.SCHOOL_ANNOUNCEMENT
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SchoolAndTeachersAppMenuItem(override var order: Int = 11) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_more_schoolandteachers
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.schoolandteachers_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.SCHOOL_AND_TEACHERS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class MobileDevicesAppMenuItem(override var order: Int = 12) : AppMenuItem() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val icon = R.drawable.ic_more_mobile_devices
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val title = R.string.mobile_devices_title
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
override val destinationType = Destination.Type.MOBILE_DEVICE
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance.menuorder
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class MenuItemMoveCallback(
|
||||||
|
private val menuOrderAdapter: MenuOrderAdapter,
|
||||||
|
private var onUserInteractionEndListener: (List<MenuOrderItem>) -> Unit = {}
|
||||||
|
) : ItemTouchHelper.Callback() {
|
||||||
|
|
||||||
|
override fun isLongPressDragEnabled() = true
|
||||||
|
|
||||||
|
override fun isItemViewSwipeEnabled() = false
|
||||||
|
|
||||||
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||||
|
//Not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMovementFlags(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder
|
||||||
|
) = makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0)
|
||||||
|
|
||||||
|
override fun onMove(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
target: RecyclerView.ViewHolder
|
||||||
|
): Boolean {
|
||||||
|
val list = menuOrderAdapter.items.toMutableList()
|
||||||
|
|
||||||
|
Collections.swap(list, viewHolder.bindingAdapterPosition, target.bindingAdapterPosition)
|
||||||
|
|
||||||
|
menuOrderAdapter.submitList(list)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||||
|
super.clearView(recyclerView, viewHolder)
|
||||||
|
|
||||||
|
onUserInteractionEndListener(menuOrderAdapter.items.toList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance.menuorder
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.github.wulkanowy.databinding.ItemMenuOrderBinding
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MenuOrderAdapter @Inject constructor() :
|
||||||
|
RecyclerView.Adapter<MenuOrderAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
val items = mutableListOf<MenuOrderItem>()
|
||||||
|
|
||||||
|
fun submitList(newItems: List<MenuOrderItem>) {
|
||||||
|
val diffResult = DiffUtil.calculateDiff(DiffCallback(newItems, items.toMutableList()))
|
||||||
|
|
||||||
|
with(items) {
|
||||||
|
clear()
|
||||||
|
addAll(newItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
diffResult.dispatchUpdatesTo(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
ItemMenuOrderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val item = items[position].appMenuItem
|
||||||
|
|
||||||
|
with(holder.binding) {
|
||||||
|
menuOrderItemTitle.setText(item.title)
|
||||||
|
menuOrderItemIcon.setImageResource(item.icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(val binding: ItemMenuOrderBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
|
private class DiffCallback(
|
||||||
|
private val oldList: List<MenuOrderItem>,
|
||||||
|
private val newList: List<MenuOrderItem>
|
||||||
|
) : DiffUtil.Callback() {
|
||||||
|
|
||||||
|
override fun getNewListSize() = newList.size
|
||||||
|
|
||||||
|
override fun getOldListSize() = oldList.size
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
||||||
|
oldList[oldItemPosition] == newList[newItemPosition]
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
||||||
|
oldList[oldItemPosition].appMenuItem.destinationType == newList[newItemPosition].appMenuItem.destinationType
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance.menuorder
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.graphics.drawable.ShapeDrawable
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
|
import androidx.core.view.forEach
|
||||||
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
|
|
||||||
|
class MenuOrderDividerItemDecoration(private val context: Context) :
|
||||||
|
DividerItemDecoration(context, VERTICAL) {
|
||||||
|
|
||||||
|
private val dividerDrawable = ShapeDrawable()
|
||||||
|
.apply {
|
||||||
|
DrawableCompat.setTint(this, context.getThemeAttrColor(R.attr.colorDivider))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
||||||
|
canvas.save()
|
||||||
|
val dividerLeft = parent.paddingLeft
|
||||||
|
val dividerRight = parent.width - parent.paddingRight
|
||||||
|
|
||||||
|
parent.forEach {
|
||||||
|
if (parent.getChildAdapterPosition(it) == 3) {
|
||||||
|
val params = it.layoutParams as RecyclerView.LayoutParams
|
||||||
|
val dividerTop = it.bottom + params.bottomMargin
|
||||||
|
val dividerBottom = dividerTop + dividerDrawable.intrinsicHeight
|
||||||
|
|
||||||
|
dividerDrawable.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom + 30)
|
||||||
|
dividerDrawable.draw(canvas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect, view: View, parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
if (parent.getChildAdapterPosition(view) == 3) {
|
||||||
|
outRect.bottom = dividerDrawable.intrinsicHeight + 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance.menuorder
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import androidx.activity.addCallback
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.databinding.FragmentMenuOrderBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class MenuOrderFragment : BaseFragment<FragmentMenuOrderBinding>(R.layout.fragment_menu_order),
|
||||||
|
MenuOrderView, MainView.TitledView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: MenuOrderPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var menuOrderAdapter: MenuOrderAdapter
|
||||||
|
|
||||||
|
override val titleStringId = R.string.menu_order_title
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding = FragmentMenuOrderBinding.bind(view)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
val itemTouchHelper = ItemTouchHelper(
|
||||||
|
MenuItemMoveCallback(menuOrderAdapter, presenter::onDragAndDropEnd)
|
||||||
|
)
|
||||||
|
|
||||||
|
itemTouchHelper.attachToRecyclerView(binding.menuOrderRecycler)
|
||||||
|
|
||||||
|
with(binding.menuOrderRecycler) {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = menuOrderAdapter
|
||||||
|
addItemDecoration(MenuOrderDividerItemDecoration(context))
|
||||||
|
addItemDecoration(DividerItemDecoration(context))
|
||||||
|
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||||
|
}
|
||||||
|
|
||||||
|
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
|
||||||
|
presenter.onBackSelected()
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeToolbar()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeToolbar() {
|
||||||
|
requireActivity().addMenuProvider(object : MenuProvider {
|
||||||
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||||
|
if (menuItem.itemId == android.R.id.home) {
|
||||||
|
presenter.onBackSelected()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
}, viewLifecycleOwner)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<MenuOrderItem>) {
|
||||||
|
menuOrderAdapter.submitList(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun restartApp() {
|
||||||
|
startActivity(MainActivity.getStartIntent(requireContext()))
|
||||||
|
requireActivity().finishAffinity()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popView() {
|
||||||
|
(activity as? MainActivity?)?.popView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showRestartConfirmationDialog() {
|
||||||
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setTitle(R.string.menu_order_confirm_title)
|
||||||
|
.setMessage(R.string.menu_order_confirm_content)
|
||||||
|
.setPositiveButton(R.string.menu_order_confirm_restart) { _, _ -> presenter.onConfirmRestart() }
|
||||||
|
.setNegativeButton(R.string.all_cancel) { _, _ -> presenter.onCancelRestart() }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance.menuorder
|
||||||
|
|
||||||
|
data class MenuOrderItem(
|
||||||
|
val appMenuItem: AppMenuItem,
|
||||||
|
val order: Int
|
||||||
|
)
|
@ -0,0 +1,64 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance.menuorder
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MenuOrderPresenter @Inject constructor(
|
||||||
|
studentRepository: StudentRepository,
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
private val preferencesRepository: PreferencesRepository
|
||||||
|
) : BasePresenter<MenuOrderView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
private var updatedMenuOrderItems = emptyList<MenuOrderItem>()
|
||||||
|
|
||||||
|
override fun onAttachView(view: MenuOrderView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
view.initView()
|
||||||
|
Timber.i("Menu order view was initialized")
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData() {
|
||||||
|
val savedMenuItemList = (preferencesRepository.appMenuItemOrder)
|
||||||
|
.sortedBy { it.order }
|
||||||
|
.map { MenuOrderItem(it, it.order) }
|
||||||
|
|
||||||
|
view?.updateData(savedMenuItemList)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDragAndDropEnd(list: List<MenuOrderItem>) {
|
||||||
|
val updatedList = list.mapIndexed { index, menuOrderItem ->
|
||||||
|
menuOrderItem.copy(order = index)
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedMenuOrderItems = updatedList
|
||||||
|
view?.updateData(updatedList)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onBackSelected() {
|
||||||
|
if (updatedMenuOrderItems.isNotEmpty()) {
|
||||||
|
view?.showRestartConfirmationDialog()
|
||||||
|
} else {
|
||||||
|
view?.popView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onConfirmRestart() {
|
||||||
|
updatedMenuOrderItems.forEach {
|
||||||
|
it.appMenuItem.apply {
|
||||||
|
order = it.order
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preferencesRepository.appMenuItemOrder = updatedMenuOrderItems.map { it.appMenuItem }
|
||||||
|
view?.restartApp()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onCancelRestart() {
|
||||||
|
view?.popView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings.appearance.menuorder
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface MenuOrderView : BaseView {
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateData(data: List<MenuOrderItem>)
|
||||||
|
|
||||||
|
fun restartApp()
|
||||||
|
|
||||||
|
fun showRestartConfirmationDialog()
|
||||||
|
|
||||||
|
fun popView()
|
||||||
|
}
|
10
app/src/main/res/drawable/ic_menu_order_drag.xml
Normal file
10
app/src/main/res/drawable/ic_menu_order_drag.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector android:height="24dp"
|
||||||
|
android:tint="#000000"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:width="24dp"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M20,9H4v2h16V9zM4,15h16v-2H4v2z" />
|
||||||
|
</vector>
|
12
app/src/main/res/layout/fragment_menu_order.xml
Normal file
12
app/src/main/res/layout/fragment_menu_order.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/menu_order_recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:listitem="@layout/item_menu_order" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
46
app/src/main/res/layout/item_menu_order.xml
Normal file
46
app/src/main/res/layout/item_menu_order.xml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout 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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?colorSurface"
|
||||||
|
android:minHeight="56dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/menu_order_item_icon"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:tint="?colorOnSurface"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/menu_order_item_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/menu_order_item_drag_icon"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/menu_order_item_icon"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@tools:sample/lorem" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/menu_order_item_drag_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:src="@drawable/ic_menu_order_drag"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:tint="?colorOnSurface"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -40,4 +40,5 @@
|
|||||||
<string name="pref_key_ads_privacy_policy">ads_privacy_policy</string>
|
<string name="pref_key_ads_privacy_policy">ads_privacy_policy</string>
|
||||||
<string name="pref_key_ads_consent_data_processing">ads_consent_data_processing</string>
|
<string name="pref_key_ads_consent_data_processing">ads_consent_data_processing</string>
|
||||||
<string name="pref_key_ads_over_eighteen">ads_over_eighteen</string>
|
<string name="pref_key_ads_over_eighteen">ads_over_eighteen</string>
|
||||||
|
<string name="pref_key_menu_order">appearance_menu_order</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
<string name="student_info_title">Student info</string>
|
<string name="student_info_title">Student info</string>
|
||||||
<string name="dashboard_title">Dashboard</string>
|
<string name="dashboard_title">Dashboard</string>
|
||||||
<string name="notifications_center_title">Notifications center</string>
|
<string name="notifications_center_title">Notifications center</string>
|
||||||
|
<string name="menu_order_title">Menu configuartion</string>
|
||||||
<!--Subtitles-->
|
<!--Subtitles-->
|
||||||
<string name="grade_subtitle">Semester %1$d, %2$d/%3$d</string>
|
<string name="grade_subtitle">Semester %1$d, %2$d/%3$d</string>
|
||||||
<!--Login-->
|
<!--Login-->
|
||||||
@ -595,6 +596,7 @@
|
|||||||
<string name="all_undo">Undo</string>
|
<string name="all_undo">Undo</string>
|
||||||
<string name="all_change">Change</string>
|
<string name="all_change">Change</string>
|
||||||
<string name="all_add_to_calendar">Add to calendar</string>
|
<string name="all_add_to_calendar">Add to calendar</string>
|
||||||
|
<string name="all_cancel">Cancel</string>
|
||||||
<!--Timetable Widget-->
|
<!--Timetable Widget-->
|
||||||
<string name="widget_timetable_no_items">No lessons</string>
|
<string name="widget_timetable_no_items">No lessons</string>
|
||||||
<string name="widget_timetable_theme_title">Choose theme</string>
|
<string name="widget_timetable_theme_title">Choose theme</string>
|
||||||
@ -616,6 +618,8 @@
|
|||||||
<string name="pref_view_grade_color_scheme">Grades color scheme</string>
|
<string name="pref_view_grade_color_scheme">Grades color scheme</string>
|
||||||
<string name="pref_view_grade_sorting_mode">Subjects sorting</string>
|
<string name="pref_view_grade_sorting_mode">Subjects sorting</string>
|
||||||
<string name="pref_view_app_language">Language</string>
|
<string name="pref_view_app_language">Language</string>
|
||||||
|
<string name="pref_view_menu_order_title">Menu configuration</string>
|
||||||
|
<string name="pref_view_menu_order_summary">Set the order of functions in the menu</string>
|
||||||
<string name="pref_notify_header">Notifications</string>
|
<string name="pref_notify_header">Notifications</string>
|
||||||
<string name="pref_notify_header_other">Other</string>
|
<string name="pref_notify_header_other">Other</string>
|
||||||
<string name="pref_notify_switch">Show notifications</string>
|
<string name="pref_notify_switch">Show notifications</string>
|
||||||
@ -717,6 +721,10 @@
|
|||||||
<string name="update_download_success">An update has just been downloaded.</string>
|
<string name="update_download_success">An update has just been downloaded.</string>
|
||||||
<string name="update_download_success_button">Restart</string>
|
<string name="update_download_success_button">Restart</string>
|
||||||
<string name="update_failed">Update failed! Wulkanowy may not function properly. Consider updating</string>
|
<string name="update_failed">Update failed! Wulkanowy may not function properly. Consider updating</string>
|
||||||
|
<!--Menu order-->
|
||||||
|
<string name="menu_order_confirm_title">Application restart</string>
|
||||||
|
<string name="menu_order_confirm_content">The application must restart for the changes to be saved</string>
|
||||||
|
<string name="menu_order_confirm_restart">Restart</string>
|
||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">No internet connection</string>
|
<string name="error_no_internet">No internet connection</string>
|
||||||
<string name="error_invalid_device_datetime">An error occurred. Check your device clock</string>
|
<string name="error_invalid_device_datetime">An error occurred. Check your device clock</string>
|
||||||
|
@ -20,23 +20,21 @@
|
|||||||
app:key="@string/pref_key_app_theme"
|
app:key="@string/pref_key_app_theme"
|
||||||
app:title="@string/pref_view_app_theme"
|
app:title="@string/pref_view_app_theme"
|
||||||
app:useSimpleSummaryProvider="true" />
|
app:useSimpleSummaryProvider="true" />
|
||||||
<ListPreference
|
<Preference
|
||||||
app:defaultValue="@string/pref_default_startup"
|
app:fragment="io.github.wulkanowy.ui.modules.settings.appearance.menuorder.MenuOrderFragment"
|
||||||
app:entries="@array/startup_tab_entries"
|
|
||||||
app:entryValues="@array/startup_tab_value"
|
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
app:key="@string/pref_key_start_menu"
|
app:key="@string/pref_key_menu_order"
|
||||||
app:title="@string/pref_view_list"
|
app:summary="@string/pref_view_menu_order_summary"
|
||||||
app:useSimpleSummaryProvider="true" />
|
app:title="@string/pref_view_menu_order_title" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
app:title="@string/pref_dashboard_appearance_header">
|
app:title="@string/pref_dashboard_appearance_header">
|
||||||
<MultiSelectListPreference
|
<MultiSelectListPreference
|
||||||
|
app:defaultValue="@array/pref_default_dashboard_tiles"
|
||||||
app:entries="@array/dashboard_tile_entries"
|
app:entries="@array/dashboard_tile_entries"
|
||||||
app:entryValues="@array/dashboard_tile_values"
|
app:entryValues="@array/dashboard_tile_values"
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
app:defaultValue="@array/pref_default_dashboard_tiles"
|
|
||||||
app:key="@string/pref_key_dashboard_tiles"
|
app:key="@string/pref_key_dashboard_tiles"
|
||||||
app:title="@string/pref_dashboard_appearance_tiles_title" />
|
app:title="@string/pref_dashboard_appearance_tiles_title" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
@ -46,7 +46,7 @@ class MainPresenterTest {
|
|||||||
MockKAnnotations.init(this)
|
MockKAnnotations.init(this)
|
||||||
clearMocks(mainView)
|
clearMocks(mainView)
|
||||||
|
|
||||||
every { mainView.initView(any(), any()) } just Runs
|
every { mainView.initView(any(), any(), any()) } just Runs
|
||||||
presenter = MainPresenter(
|
presenter = MainPresenter(
|
||||||
errorHandler = errorHandler,
|
errorHandler = errorHandler,
|
||||||
studentRepository = studentRepository,
|
studentRepository = studentRepository,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user