From 837bce72862f04d810528a08b731d4b75f79b075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Mon, 22 Oct 2018 22:47:54 +0200 Subject: [PATCH] Settings refactor (#166) --- app/build.gradle | 4 +- .../repositories/PreferencesRepository.kt | 16 ++++ .../wulkanowy/ui/login/LoginActivity.kt | 5 +- .../wulkanowy/ui/login/LoginPresenter.kt | 2 +- .../io/github/wulkanowy/ui/login/LoginView.kt | 4 +- .../github/wulkanowy/ui/main/MainActivity.kt | 60 +++++++++----- .../io/github/wulkanowy/ui/main/MainModule.kt | 6 ++ .../github/wulkanowy/ui/main/MainPresenter.kt | 33 ++++++-- .../io/github/wulkanowy/ui/main/MainView.kt | 25 ++++-- .../wulkanowy/ui/main/about/AboutFragment.kt | 68 ++++++++++++++++ .../wulkanowy/ui/main/about/AboutModule.kt | 15 ++++ .../wulkanowy/ui/main/about/AboutPresenter.kt | 21 +++++ .../wulkanowy/ui/main/about/AboutView.kt | 10 +++ .../ui/main/attendance/AttendanceFragment.kt | 11 ++- .../ui/main/attendance/AttendancePresenter.kt | 10 ++- .../ui/main/attendance/AttendanceView.kt | 4 +- .../wulkanowy/ui/main/exam/ExamFragment.kt | 11 ++- .../wulkanowy/ui/main/exam/ExamPresenter.kt | 2 +- .../github/wulkanowy/ui/main/exam/ExamView.kt | 4 +- .../wulkanowy/ui/main/grade/GradeFragment.kt | 12 ++- .../wulkanowy/ui/main/grade/GradePresenter.kt | 10 +-- .../wulkanowy/ui/main/grade/GradeView.kt | 4 +- .../grade/details/GradeDetailsFragment.kt | 24 +++--- .../grade/details/GradeDetailsPresenter.kt | 12 +-- .../ui/main/grade/details/GradeDetailsView.kt | 24 +++--- .../grade/summary/GradeSummaryFragment.kt | 15 ++-- .../grade/summary/GradeSummaryPresenter.kt | 8 +- .../ui/main/grade/summary/GradeSummaryView.kt | 12 +-- .../wulkanowy/ui/main/more/MoreFragment.kt | 81 ++++++++++++++++++- .../github/wulkanowy/ui/main/more/MoreItem.kt | 51 ++++++++++++ .../wulkanowy/ui/main/more/MorePresenter.kt | 39 +++++++++ .../github/wulkanowy/ui/main/more/MoreView.kt | 21 +++++ .../ui/main/settings/SettingsFragment.kt | 20 +++++ .../ui/main/timetable/TimetableFragment.kt | 10 ++- .../ui/main/timetable/TimetablePresenter.kt | 2 +- .../ui/main/timetable/TimetableView.kt | 4 +- .../utils/FragNavControlerExtension.kt | 15 +++- .../wulkanowy/utils/LibsBuiderExtension.kt | 16 ++++ ...ummary_24dp.xml => ic_more_about_24dp.xml} | 4 +- .../res/drawable/ic_more_settings_24dp.xml | 16 ++++ app/src/main/res/layout/activity_main.xml | 1 + app/src/main/res/layout/fragment_more.xml | 10 +++ app/src/main/res/layout/item_more.xml | 30 +++++++ app/src/main/res/values-pl/strings.xml | 17 ++-- .../main/res/values/library_wulkanowy_api.xml | 17 ++++ app/src/main/res/values/strings.xml | 18 ++--- app/src/main/res/values/styles.xml | 12 +-- app/src/main/res/xml/scheme_preferences.xml | 66 +++------------ .../wulkanowy/ui/login/LoginPresenterTest.kt | 5 +- .../wulkanowy/ui/main/MainPresenterTest.kt | 16 ++-- build.gradle | 1 - 51 files changed, 679 insertions(+), 225 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/about/AboutFragment.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/about/AboutModule.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/about/AboutPresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/about/AboutView.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/more/MoreItem.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/more/MorePresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/more/MoreView.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.kt create mode 100644 app/src/main/java/io/github/wulkanowy/utils/LibsBuiderExtension.kt rename app/src/main/res/drawable/{ic_menu_grade_summary_24dp.xml => ic_more_about_24dp.xml} (85%) create mode 100644 app/src/main/res/drawable/ic_more_settings_24dp.xml create mode 100644 app/src/main/res/layout/fragment_more.xml create mode 100644 app/src/main/res/layout/item_more.xml create mode 100644 app/src/main/res/values/library_wulkanowy_api.xml diff --git a/app/build.gradle b/app/build.gradle index 53489f93..c8d99fa2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -77,11 +77,11 @@ dependencies { implementation "androidx.legacy:legacy-support-v4:$androidx_version" implementation "androidx.appcompat:appcompat:$androidx_version" implementation "androidx.cardview:cardview:$androidx_version" - implementation "androidx.legacy:legacy-preference-v14:$androidx_version" implementation "com.google.android.material:material:$androidx_version" implementation 'androidx.multidex:multidex:2.0.0' - implementation "com.google.android.gms:play-services-oss-licenses:16.0.1" + implementation 'com.takisoft.preferencex:preferencex:1.0.0' + implementation "com.mikepenz:aboutlibraries:6.2.0" implementation "com.firebase:firebase-jobdispatcher:0.8.5" //Do not update dagger https://github.com/google/dagger/issues/1245 diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt new file mode 100644 index 00000000..472eb4bf --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt @@ -0,0 +1,16 @@ +package io.github.wulkanowy.data.repositories + +import android.content.SharedPreferences +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PreferencesRepository @Inject constructor(private val sharedPref: SharedPreferences) { + + val startMenuIndex: Int + get() = sharedPref.getString("start_menu", "0")?.toInt() ?: 0 + + val showPresent: Boolean + get() = sharedPref.getBoolean("attendance_present", true) +} + diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.kt index cb59e911..1f6a4b99 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.kt @@ -24,6 +24,9 @@ class LoginActivity : BaseActivity(), LoginView, LoginSwitchListener { fun getStartIntent(context: Context) = Intent(context, LoginActivity::class.java) } + override val currentViewIndex: Int + get() = loginViewpager.currentItem + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) @@ -63,8 +66,6 @@ class LoginActivity : BaseActivity(), LoginView, LoginSwitchListener { (loginAdapter.getItem(index) as LoginOptionsFragment).loadData() } - override fun currentViewPosition() = loginViewpager.currentItem - public override fun onDestroy() { presenter.onDetachView() super.onDestroy() diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.kt index 4d2ac1f7..103d1150 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.kt @@ -25,7 +25,7 @@ class LoginPresenter @Inject constructor(errorHandler: ErrorHandler) fun onBackPressed(default: () -> Unit) { view?.run { - if (currentViewPosition() == 1) { + if (currentViewIndex == 1) { switchView(0) hideActionBar() } else default() diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginView.kt b/app/src/main/java/io/github/wulkanowy/ui/login/LoginView.kt index 6e01f51b..0ea646fc 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginView.kt @@ -4,6 +4,8 @@ import io.github.wulkanowy.ui.base.BaseView interface LoginView : BaseView { + val currentViewIndex: Int + fun initAdapter() fun loadOptionsView(index: Int) @@ -11,6 +13,4 @@ interface LoginView : BaseView { fun switchView(position: Int) fun hideActionBar() - - fun currentViewPosition(): Int } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.kt index 176890f2..52737e1d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.kt @@ -4,10 +4,11 @@ import android.content.Context import android.content.Intent import android.os.Bundle import androidx.core.content.ContextCompat -import com.aurelhubert.ahbottomnavigation.AHBottomNavigation +import androidx.fragment.app.Fragment +import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState.ALWAYS_SHOW import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem import com.ncapdevi.fragnav.FragNavController -import com.ncapdevi.fragnav.FragNavController.Companion.DETACH_ON_NAVIGATE_HIDE_ON_SWITCH +import com.ncapdevi.fragnav.FragNavController.Companion.HIDE import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.ui.main.attendance.AttendanceFragment @@ -15,7 +16,8 @@ import io.github.wulkanowy.ui.main.exam.ExamFragment import io.github.wulkanowy.ui.main.grade.GradeFragment import io.github.wulkanowy.ui.main.more.MoreFragment import io.github.wulkanowy.ui.main.timetable.TimetableFragment -import io.github.wulkanowy.utils.setOnTabTransactionListener +import io.github.wulkanowy.utils.safelyPopFragment +import io.github.wulkanowy.utils.setOnViewChangeListener import kotlinx.android.synthetic.main.activity_main.* import javax.inject.Inject @@ -28,11 +30,20 @@ class MainActivity : BaseActivity(), MainView { lateinit var navController: FragNavController companion object { - const val DEFAULT_TAB = 2 - fun getStartIntent(context: Context) = Intent(context, MainActivity::class.java) } + override val isRootView: Boolean + get() = navController.isRootFragment + + override val currentViewTitle: String? + get() = (navController.currentFrag as? MainView.TitledView)?.titleStringId?.let { getString(it) } + + override val currentStackSize: Int? + get() = navController.currentStack?.size + + override var startMenuIndex = 0 + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -40,12 +51,16 @@ class MainActivity : BaseActivity(), MainView { messageContainer = mainFragmentContainer presenter.onAttachView(this) - navController.initialize(DEFAULT_TAB, savedInstanceState) + navController.initialize(startMenuIndex, savedInstanceState) } override fun onStart() { super.onStart() - presenter.onStartView() + presenter.onViewStart() + } + + override fun onSupportNavigateUp(): Boolean { + return presenter.onUpNavigate() } override fun initView() { @@ -59,19 +74,18 @@ class MainActivity : BaseActivity(), MainView { )) accentColor = ContextCompat.getColor(context, R.color.colorPrimary) inactiveColor = ContextCompat.getColor(context, android.R.color.black) - titleState = AHBottomNavigation.TitleState.ALWAYS_SHOW - currentItem = DEFAULT_TAB + titleState = ALWAYS_SHOW + currentItem = startMenuIndex isBehaviorTranslationEnabled = false setTitleTextSizeInSp(10f, 10f) - setOnTabSelectedListener { position, wasSelected -> presenter.onTabSelected(position, wasSelected) } } navController.run { - setOnTabTransactionListener { presenter.onMenuViewChange(it) } - fragmentHideStrategy = DETACH_ON_NAVIGATE_HIDE_ON_SWITCH + setOnViewChangeListener { presenter.onViewStart() } + fragmentHideStrategy = HIDE rootFragments = listOf( GradeFragment.newInstance(), AttendanceFragment.newInstance(), @@ -90,22 +104,24 @@ class MainActivity : BaseActivity(), MainView { supportActionBar?.title = title } - override fun viewTitle(index: Int): String { - return getString(listOf(R.string.grade_title, - R.string.attendance_title, - R.string.exam_title, - R.string.timetable_title, - R.string.more_title)[index]) + override fun showHomeArrow(show: Boolean) { + supportActionBar?.setDisplayHomeAsUpEnabled(show) } - override fun currentMenuIndex() = navController.currentStackIndex - override fun notifyMenuViewReselected() { - (navController.currentFrag as? MainView.MenuFragmentView)?.onFragmentReselected() + (navController.currentStack?.get(0) as? MainView.MainChildView)?.onFragmentReselected() + } + + fun pushView(fragment: Fragment) { + navController.pushFragment(fragment) + } + + override fun popView() { + navController.safelyPopFragment() } override fun onBackPressed() { - navController.apply { if (isRootFragment) super.onBackPressed() else popFragment() } + presenter.onBackPressed { super.onBackPressed() } } override fun onSaveInstanceState(outState: Bundle?) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.kt b/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.kt index f750a301..1c333cec 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.kt @@ -7,6 +7,8 @@ import dagger.android.ContributesAndroidInjector import io.github.wulkanowy.R import io.github.wulkanowy.di.scopes.PerActivity import io.github.wulkanowy.di.scopes.PerFragment +import io.github.wulkanowy.ui.main.about.AboutFragment +import io.github.wulkanowy.ui.main.about.AboutModule import io.github.wulkanowy.ui.main.attendance.AttendanceFragment import io.github.wulkanowy.ui.main.exam.ExamFragment import io.github.wulkanowy.ui.main.grade.GradeFragment @@ -47,4 +49,8 @@ abstract class MainModule { @PerFragment @ContributesAndroidInjector abstract fun bindTimetableFragment(): TimetableFragment + + @PerFragment + @ContributesAndroidInjector(modules = [AboutModule::class]) + abstract fun bindAboutFragment(): AboutFragment } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.kt index 1a94a30b..af0606d1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.kt @@ -1,23 +1,44 @@ package io.github.wulkanowy.ui.main import io.github.wulkanowy.data.ErrorHandler +import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.ui.base.BasePresenter import javax.inject.Inject -class MainPresenter @Inject constructor(errorHandler: ErrorHandler) +class MainPresenter @Inject constructor( + errorHandler: ErrorHandler, + private val prefRepository: PreferencesRepository) : BasePresenter(errorHandler) { override fun onAttachView(view: MainView) { super.onAttachView(view) - view.initView() + view.run { + startMenuIndex = prefRepository.startMenuIndex + initView() + } } - fun onStartView() { - view?.run { setViewTitle(viewTitle(currentMenuIndex())) } + fun onViewStart() { + view?.apply { + currentViewTitle?.let { setViewTitle(it) } + currentStackSize?.let { + if (it > 1) showHomeArrow(true) + else showHomeArrow(false) + } + } } - fun onMenuViewChange(index: Int) { - view?.run { setViewTitle(viewTitle(index)) } + fun onUpNavigate(): Boolean { + view?.popView() + return true + } + + + fun onBackPressed(default: () -> Unit) { + view?.run { + if (isRootView) default() + else popView() + } } fun onTabSelected(index: Int, wasSelected: Boolean): Boolean { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/MainView.kt index 67a0b668..c94bc03b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainView.kt @@ -4,20 +4,33 @@ import io.github.wulkanowy.ui.base.BaseView interface MainView : BaseView { + var startMenuIndex: Int + + val isRootView: Boolean + + val currentViewTitle: String? + + val currentStackSize: Int? + fun initView() fun switchMenuView(position: Int) - fun setViewTitle(title: String) - - fun viewTitle(index: Int): String - - fun currentMenuIndex(): Int + fun showHomeArrow(show: Boolean) fun notifyMenuViewReselected() - interface MenuFragmentView { + fun setViewTitle(title: String) + + fun popView() + + interface MainChildView { fun onFragmentReselected() } + + interface TitledView { + + val titleStringId: Int + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutFragment.kt new file mode 100644 index 00000000..2aa8b1b0 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutFragment.kt @@ -0,0 +1,68 @@ +package io.github.wulkanowy.ui.main.about + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.mikepenz.aboutlibraries.LibsBuilder +import com.mikepenz.aboutlibraries.LibsFragmentCompat +import io.github.wulkanowy.R +import io.github.wulkanowy.ui.base.BaseFragment +import io.github.wulkanowy.ui.main.MainView +import io.github.wulkanowy.utils.withOnExtraListener +import javax.inject.Inject + +class AboutFragment : BaseFragment(), AboutView, MainView.TitledView { + + @Inject + lateinit var presenter: AboutPresenter + + @Inject + lateinit var fragmentCompat: LibsFragmentCompat + + companion object { + fun newInstance() = AboutFragment() + } + + override val titleStringId: Int + get() = R.string.about_title + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + presenter.onAttachView(this) + return Bundle().apply { + putSerializable("data", LibsBuilder() + .withAboutAppName(getString(R.string.app_name)) + .withAboutVersionShown(true) + .withAboutIconShown(true) + .withLicenseShown(true) + .withAboutSpecial1(getString(R.string.about_source_code)) + .withAboutSpecial2(getString(R.string.about_feedback)) + .withCheckCachedDetection(false) + .withExcludedLibraries("fastadapter", "AndroidIconics", "gson", + "Jsoup", "Retrofit", "okio", "OkHttp") + .withOnExtraListener { presenter.onExtraSelect(it) }) + }.let { + fragmentCompat.onCreateView(inflater.context, inflater, container, savedInstanceState, it) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + fragmentCompat.onViewCreated(view, savedInstanceState) + } + + override fun openSourceWebView() { + startActivity(Intent.parseUri("https://github.com/wulkanowy/wulkanowy", 0)) + } + + override fun openIssuesWebView() { + startActivity(Intent.parseUri("https://github.com/wulkanowy/wulkanowy/issues", 0)) + } + + override fun onDestroyView() { + fragmentCompat.onDestroyView() + presenter.onDetachView() + super.onDestroyView() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutModule.kt b/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutModule.kt new file mode 100644 index 00000000..5842db1d --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutModule.kt @@ -0,0 +1,15 @@ +package io.github.wulkanowy.ui.main.about + +import com.mikepenz.aboutlibraries.LibsFragmentCompat +import dagger.Module +import dagger.Provides +import io.github.wulkanowy.di.scopes.PerFragment + +@Module +class AboutModule { + + @PerFragment + @Provides + fun provideLibsFragmentCompat() = LibsFragmentCompat() +} + diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutPresenter.kt new file mode 100644 index 00000000..fa083296 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutPresenter.kt @@ -0,0 +1,21 @@ +package io.github.wulkanowy.ui.main.about + +import com.mikepenz.aboutlibraries.Libs +import com.mikepenz.aboutlibraries.Libs.SpecialButton.SPECIAL1 +import com.mikepenz.aboutlibraries.Libs.SpecialButton.SPECIAL2 +import io.github.wulkanowy.data.ErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import javax.inject.Inject + +class AboutPresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresenter(errorHandler) { + + fun onExtraSelect(type: Libs.SpecialButton?) { + view?.run { + when (type) { + SPECIAL1 -> openSourceWebView() + SPECIAL2 -> openIssuesWebView() + else -> TODO() + } + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutView.kt new file mode 100644 index 00000000..cfdba992 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/about/AboutView.kt @@ -0,0 +1,10 @@ +package io.github.wulkanowy.ui.main.about + +import io.github.wulkanowy.ui.base.BaseView + +interface AboutView : BaseView { + + fun openSourceWebView() + + fun openIssuesWebView() +} \ No newline at end of file diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.kt index 1b0cd6f8..1e8eea74 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.kt @@ -15,7 +15,7 @@ import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_attendance.* import javax.inject.Inject -class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MenuFragmentView { +class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildView, MainView.TitledView { @Inject lateinit var presenter: AttendancePresenter @@ -29,6 +29,12 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MenuFragment fun newInstance() = AttendanceFragment() } + override val titleStringId: Int + get() = R.string.attendance_title + + override val isViewEmpty: Boolean + get() = attendanceAdapter.isEmpty + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_attendance, container, false) } @@ -65,8 +71,6 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MenuFragment attendanceAdapter.clear() } - override fun isViewEmpty() = attendanceAdapter.isEmpty - override fun onFragmentReselected() { presenter.onViewReselected() } @@ -109,4 +113,3 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MenuFragment super.onDestroyView() } } - diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.kt index a09c65c2..8a20d626 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.main.attendance import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.data.ErrorHandler import io.github.wulkanowy.data.repositories.AttendanceRepository +import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.data.repositories.SessionRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.utils.* @@ -17,7 +18,8 @@ class AttendancePresenter @Inject constructor( private val errorHandler: ErrorHandler, private val schedulers: SchedulersManager, private val attendanceRepository: AttendanceRepository, - private val sessionRepository: SessionRepository + private val sessionRepository: SessionRepository, + private val prefRepository: PreferencesRepository ) : BasePresenter(errorHandler) { lateinit var currentDate: LocalDate @@ -61,6 +63,10 @@ class AttendancePresenter @Inject constructor( .delay(200, MILLISECONDS) .map { it.single { semester -> semester.current } } .flatMap { attendanceRepository.getAttendance(it, date, date, forceRefresh) } + .map { list -> + if (prefRepository.showPresent) list + else list.filter { !it.presence } + } .map { items -> items.map { AttendanceItem(it) } } .subscribeOn(schedulers.backgroundThread()) .observeOn(schedulers.mainThread()) @@ -77,7 +83,7 @@ class AttendancePresenter @Inject constructor( showContent(it.isNotEmpty()) } }) { - view?.run { showEmpty(isViewEmpty()) } + view?.run { showEmpty(isViewEmpty) } errorHandler.proceed(it) } ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceView.kt index f4d0a433..4c9d18b8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceView.kt @@ -5,6 +5,8 @@ import io.github.wulkanowy.ui.base.BaseView interface AttendanceView : BaseView { + val isViewEmpty: Boolean + fun initView() fun updateData(data: List) @@ -13,8 +15,6 @@ interface AttendanceView : BaseView { fun clearData() - fun isViewEmpty(): Boolean - fun hideRefresh() fun showEmpty(show: Boolean) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt index 444881f1..9403dbac 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt @@ -16,7 +16,7 @@ import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_exam.* import javax.inject.Inject -class ExamFragment : BaseFragment(), ExamView, MainView.MenuFragmentView { +class ExamFragment : BaseFragment(), ExamView, MainView.MainChildView, MainView.TitledView { @Inject lateinit var presenter: ExamPresenter @@ -26,9 +26,16 @@ class ExamFragment : BaseFragment(), ExamView, MainView.MenuFragmentView { companion object { private const val SAVED_DATE_KEY = "CURRENT_DATE" + fun newInstance() = ExamFragment() } + override val titleStringId: Int + get() = R.string.exam_title + + override val isViewEmpty: Boolean + get() = examAdapter.isEmpty + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_exam, container, false) } @@ -68,8 +75,6 @@ class ExamFragment : BaseFragment(), ExamView, MainView.MenuFragmentView { examAdapter.clear() } - override fun isViewEmpty() = examAdapter.isEmpty - override fun onFragmentReselected() { presenter.onViewReselected() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamPresenter.kt index 9df5ba75..afe1b3cf 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamPresenter.kt @@ -80,7 +80,7 @@ class ExamPresenter @Inject constructor( showContent(it.isNotEmpty()) } }) { - view?.run { showEmpty(isViewEmpty()) } + view?.run { showEmpty(isViewEmpty) } errorHandler.proceed(it) }) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamView.kt index e00ab9bb..43f7d4d8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamView.kt @@ -5,6 +5,8 @@ import io.github.wulkanowy.ui.base.BaseView interface ExamView : BaseView { + val isViewEmpty: Boolean + fun initView() fun updateData(data: List) @@ -13,8 +15,6 @@ interface ExamView : BaseView { fun clearData() - fun isViewEmpty(): Boolean - fun hideRefresh() fun showEmpty(show: Boolean) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeFragment.kt index 559c89c8..e49b4ff8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeFragment.kt @@ -15,7 +15,7 @@ import io.github.wulkanowy.utils.setOnSelectPageListener import kotlinx.android.synthetic.main.fragment_grade.* import javax.inject.Inject -class GradeFragment : BaseFragment(), GradeView, MainView.MenuFragmentView { +class GradeFragment : BaseFragment(), GradeView, MainView.MainChildView, MainView.TitledView { @Inject lateinit var presenter: GradePresenter @@ -29,6 +29,12 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MenuFragmentView { fun newInstance() = GradeFragment() } + override val titleStringId: Int + get() = R.string.grade_title + + override val currentPageIndex: Int + get() = gradeViewPager.currentItem + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) @@ -93,8 +99,6 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MenuFragmentView { } } - override fun currentPageIndex() = gradeViewPager.currentItem - fun onChildRefresh() { presenter.onChildViewRefresh() } @@ -124,4 +128,4 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MenuFragmentView { super.onDestroyView() presenter.onDetachView() } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradePresenter.kt index add00e92..e8e70062 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradePresenter.kt @@ -32,7 +32,7 @@ class GradePresenter @Inject constructor( } fun onViewReselected() { - view?.run { notifyChildParentReselected(currentPageIndex()) } + view?.run { notifyChildParentReselected(currentPageIndex) } } fun onSemesterSwitch(): Boolean { @@ -46,20 +46,20 @@ class GradePresenter @Inject constructor( loadedSemesterId.clear() view?.let { notifyChildrenSemesterChange() - loadChild(it.currentPageIndex()) + loadChild(it.currentPageIndex) } } } fun onChildViewRefresh() { - view?.let { loadChild(it.currentPageIndex(), forceRefresh = true) } + view?.let { loadChild(it.currentPageIndex, forceRefresh = true) } } fun onChildViewLoaded(semesterId: Int) { view?.apply { showContent(true) showProgress(false) - loadedSemesterId[currentPageIndex()] = semesterId + loadedSemesterId[currentPageIndex] = semesterId } } @@ -78,7 +78,7 @@ class GradePresenter @Inject constructor( .subscribeOn(schedulers.backgroundThread()) .observeOn(schedulers.mainThread()) .subscribe({ _ -> - view?.let { loadChild(it.currentPageIndex()) } + view?.let { loadChild(it.currentPageIndex) } }) { errorHandler.proceed(it) }) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeView.kt index a343e53d..4c1df29a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeView.kt @@ -4,9 +4,9 @@ import io.github.wulkanowy.ui.base.BaseView interface GradeView : BaseView { - fun initView() + val currentPageIndex: Int - fun currentPageIndex(): Int + fun initView() fun showContent(show: Boolean) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsFragment.kt index 06c64557..15ed2d66 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsFragment.kt @@ -31,6 +31,18 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh fun newInstance() = GradeDetailsFragment() } + override val emptyAverageString: String + get() = getString(R.string.grade_no_average) + + override val averageString: String + get() = getString(R.string.grade_average) + + override val weightString: String + get() = getString(R.string.grade_weight) + + override val isViewEmpty + get() = gradeDetailsAdapter.isEmpty + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_grade_details, container, false) } @@ -80,7 +92,9 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh return gradeDetailsAdapter.getExpandableOf(item) } - override fun isViewEmpty() = gradeDetailsAdapter.isEmpty + override fun getGradeNumberString(number: Int): String { + return resources.getQuantityString(R.plurals.grade_number_item, number, number) + } override fun showProgress(show: Boolean) { gradeDetailsProgress.visibility = if (show) VISIBLE else GONE @@ -122,14 +136,6 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh (parentFragment as? GradeFragment)?.onChildRefresh() } - override fun emptyAverageString(): String = getString(R.string.grade_no_average) - - override fun averageString(): String = getString(R.string.grade_average) - - override fun gradeNumberString(number: Int): String = resources.getQuantityString(R.plurals.grade_number_item, number, number) - - override fun weightString(): String = getString(R.string.grade_weight) - override fun onDestroyView() { super.onDestroyView() presenter.onDetachView() diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsPresenter.kt index dd9e2671..4189fa71 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsPresenter.kt @@ -42,7 +42,7 @@ class GradeDetailsPresenter @Inject constructor( updateData(it) } }) { - view?.run { showEmpty(isViewEmpty()) } + view?.run { showEmpty(isViewEmpty) } errorHandler.proceed(it) }) } @@ -72,7 +72,7 @@ class GradeDetailsPresenter @Inject constructor( fun onParentViewReselected() { view?.run { - if (!isViewEmpty()) resetView() + if (!isViewEmpty) resetView() } } @@ -93,13 +93,13 @@ class GradeDetailsPresenter @Inject constructor( GradeDetailsHeader( subject = it.key, average = formatAverage(average), - number = view?.gradeNumberString(it.value.size).orEmpty(), + number = view?.getGradeNumberString(it.value.size).orEmpty(), newGrades = it.value.filter { grade -> grade.isNew }.size ).apply { subItems = it.value.map { item -> GradeDetailsItem( grade = item, - weightString = view?.weightString().orEmpty(), + weightString = view?.weightString.orEmpty(), valueColor = item.valueColor ) } @@ -110,8 +110,8 @@ class GradeDetailsPresenter @Inject constructor( private fun formatAverage(average: Double): String { return view?.run { - if (average == 0.0) emptyAverageString() - else averageString().format(average) + if (average == 0.0) emptyAverageString + else averageString.format(average) }.orEmpty() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsView.kt index 20b0c2b6..a292ee95 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/details/GradeDetailsView.kt @@ -8,20 +8,24 @@ import io.github.wulkanowy.ui.base.BaseView interface GradeDetailsView : BaseView { + val isViewEmpty: Boolean + + val emptyAverageString: String + + val averageString: String + + val weightString: String + fun initView() fun updateData(data: List) fun updateItem(item: AbstractFlexibleItem<*>) - fun getHeaderOfItem(item: AbstractFlexibleItem<*>): IExpandable<*, out IFlexible<*>>? - fun resetView() fun clearView() - fun isViewEmpty(): Boolean - fun showGradeDialog(grade: Grade) fun showContent(show: Boolean) @@ -32,15 +36,11 @@ interface GradeDetailsView : BaseView { fun showRefresh(show: Boolean) - fun emptyAverageString(): String - - fun averageString(): String - - fun gradeNumberString(number: Int): String - - fun weightString(): String - fun notifyParentDataLoaded(semesterId: Int) fun notifyParentRefresh() + + fun getGradeNumberString(number: Int): String + + fun getHeaderOfItem(item: AbstractFlexibleItem<*>): IExpandable<*, out IFlexible<*>>? } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryFragment.kt index 729e9384..e3e16022 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryFragment.kt @@ -27,6 +27,15 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh fun newInstance() = GradeSummaryFragment() } + override val isViewEmpty + get() = gradeSummaryAdapter.isEmpty + + override val predictedString + get() = getString(R.string.grade_summary_predicted_grade) + + override val finalString + get() = getString(R.string.grade_summary_final_grade) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_grade_summary, container, false) } @@ -63,8 +72,6 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh gradeSummaryAdapter.smoothScrollToPosition(0) } - override fun isViewEmpty() = gradeSummaryAdapter.isEmpty - override fun showContent(show: Boolean) { gradeSummaryRecycler.visibility = if (show) VISIBLE else INVISIBLE } @@ -101,10 +108,6 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh (parentFragment as? GradeFragment)?.onChildRefresh() } - override fun predictedString() = getString(R.string.grade_summary_predicted_grade) - - override fun finalString() = getString(R.string.grade_summary_final_grade) - override fun onDestroyView() { super.onDestroyView() presenter.onDetachView() diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryPresenter.kt index 8fc28d0b..048619a2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryPresenter.kt @@ -61,7 +61,7 @@ class GradeSummaryPresenter @Inject constructor( updateDataSet(it.first, it.second) } }) { - view?.run { showEmpty(isViewEmpty()) } + view?.run { showEmpty(isViewEmpty) } errorHandler.proceed(it) }) } @@ -72,7 +72,7 @@ class GradeSummaryPresenter @Inject constructor( fun onParentViewReselected() { view?.run { - if (!isViewEmpty()) resetView() + if (!isViewEmpty) resetView() } } @@ -97,11 +97,11 @@ class GradeSummaryPresenter @Inject constructor( ).let { listOf(GradeSummaryItem( header = it, - title = view?.predictedString().orEmpty(), + title = view?.predictedString.orEmpty(), grade = gradeSummary.predictedGrade ), GradeSummaryItem( header = it, - title = view?.finalString().orEmpty(), + title = view?.finalString.orEmpty(), grade = gradeSummary.finalGrade )) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryView.kt index 29a23f3a..d5697edf 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/summary/GradeSummaryView.kt @@ -4,6 +4,12 @@ import io.github.wulkanowy.ui.base.BaseView interface GradeSummaryView : BaseView { + val isViewEmpty: Boolean + + val predictedString: String + + val finalString: String + fun initView() fun updateDataSet(data: List, header: GradeSummaryScrollableHeader) @@ -12,8 +18,6 @@ interface GradeSummaryView : BaseView { fun clearView() - fun isViewEmpty(): Boolean - fun showProgress(show: Boolean) fun showRefresh(show: Boolean) @@ -22,10 +26,6 @@ interface GradeSummaryView : BaseView { fun showEmpty(show: Boolean) - fun predictedString(): String - - fun finalString(): String - fun notifyParentDataLoaded(semesterId: Int) fun notifyParentRefresh() diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreFragment.kt index 2bec077e..f0b2cd8c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreFragment.kt @@ -1,20 +1,95 @@ package io.github.wulkanowy.ui.main.more +import android.graphics.drawable.Drawable import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.content.ContextCompat +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseFragment +import io.github.wulkanowy.ui.main.MainActivity +import io.github.wulkanowy.ui.main.MainView +import io.github.wulkanowy.ui.main.about.AboutFragment +import io.github.wulkanowy.ui.main.settings.SettingsFragment +import io.github.wulkanowy.utils.setOnItemClickListener +import kotlinx.android.synthetic.main.fragment_more.* +import javax.inject.Inject -class MoreFragment : BaseFragment() { +class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.MainChildView { + + @Inject + lateinit var presenter: MorePresenter + + @Inject + lateinit var moreAdapter: FlexibleAdapter> companion object { fun newInstance() = MoreFragment() } + override val titleStringId: Int + get() = R.string.more_title + + override val settingsRes: Pair? + get() { + return context?.run { + getString(R.string.settings_title) to + ContextCompat.getDrawable(this, R.drawable.ic_more_settings_24dp) + } + } + + override val aboutRes: Pair? + get() { + return context?.run { + getString(R.string.about_title) to + ContextCompat.getDrawable(this, R.drawable.ic_more_about_24dp) + } + } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_attendance, container, false) + return inflater.inflate(R.layout.fragment_more, container, false) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + presenter.onAttachView(this) + } + + override fun initView() { + moreAdapter.run { setOnItemClickListener { presenter.onItemSelected(getItem(it)) } } + + moreRecycler.apply { + layoutManager = SmoothScrollLinearLayoutManager(context) + adapter = moreAdapter + } + } + + override fun onFragmentReselected() { + presenter.onViewReselected() + } + + override fun updateData(data: List) { + moreAdapter.updateDataSet(data) + } + + override fun openSettingsView() { + (activity as? MainActivity)?.pushView(SettingsFragment.newInstance()) + } + + override fun openAboutView() { + (activity as? MainActivity)?.pushView(AboutFragment.newInstance()) + } + + override fun popView() { + (activity as? MainActivity)?.popView() + } + + override fun onDestroyView() { + presenter.onDetachView() + super.onDestroyView() } } - diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreItem.kt b/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreItem.kt new file mode 100644 index 00000000..78bca660 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreItem.kt @@ -0,0 +1,51 @@ +package io.github.wulkanowy.ui.main.more + +import android.graphics.drawable.Drawable +import android.view.View +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem +import eu.davidea.flexibleadapter.items.IFlexible +import eu.davidea.viewholders.FlexibleViewHolder +import io.github.wulkanowy.R +import kotlinx.android.extensions.LayoutContainer +import kotlinx.android.synthetic.main.item_more.* + +class MoreItem(val title: String, private val drawable: Drawable?) + : AbstractFlexibleItem() { + + override fun getLayoutRes() = R.layout.item_more + + override fun createViewHolder(view: View?, adapter: FlexibleAdapter>?): ViewHolder { + return ViewHolder(view, adapter) + } + + override fun bindViewHolder(adapter: FlexibleAdapter>?, holder: ViewHolder?, + position: Int, payloads: MutableList?) { + holder?.apply { + moreItemTitle.text = title + moreItemImage.setImageDrawable(drawable) + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MoreItem + + if (title != other.title) return false + + return true + } + + override fun hashCode(): Int { + return title.hashCode() + } + + class ViewHolder(view: View?, adapter: FlexibleAdapter<*>?) + : FlexibleViewHolder(view, adapter), LayoutContainer { + + override val containerView: View? + get() = contentView + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/more/MorePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/more/MorePresenter.kt new file mode 100644 index 00000000..ad03857e --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/more/MorePresenter.kt @@ -0,0 +1,39 @@ +package io.github.wulkanowy.ui.main.more + +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem +import io.github.wulkanowy.data.ErrorHandler +import io.github.wulkanowy.ui.base.BasePresenter +import javax.inject.Inject + +class MorePresenter @Inject constructor(errorHandler: ErrorHandler) + : BasePresenter(errorHandler) { + + override fun onAttachView(view: MoreView) { + super.onAttachView(view) + view.initView() + loadData() + } + + fun onItemSelected(item: AbstractFlexibleItem<*>?) { + if (item is MoreItem) { + view?.run { + when (item.title) { + settingsRes?.first -> openSettingsView() + aboutRes?.first -> openAboutView() + } + } + } + } + + fun onViewReselected() { + view?.popView() + } + + private fun loadData() { + view?.run { + updateData(listOfNotNull( + settingsRes?.let { MoreItem(it.first, it.second) }, + aboutRes?.let { MoreItem(it.first, it.second) })) + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreView.kt new file mode 100644 index 00000000..ba598d39 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/more/MoreView.kt @@ -0,0 +1,21 @@ +package io.github.wulkanowy.ui.main.more + +import android.graphics.drawable.Drawable +import io.github.wulkanowy.ui.base.BaseView + +interface MoreView : BaseView { + + val settingsRes: Pair? + + val aboutRes: Pair? + + fun initView() + + fun updateData(data: List) + + fun openSettingsView() + + fun openAboutView() + + fun popView() +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.kt new file mode 100644 index 00000000..a1dcbd92 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.kt @@ -0,0 +1,20 @@ +package io.github.wulkanowy.ui.main.settings + +import android.os.Bundle +import com.takisoft.preferencex.PreferenceFragmentCompat +import io.github.wulkanowy.R +import io.github.wulkanowy.ui.main.MainView + +class SettingsFragment : PreferenceFragmentCompat(), MainView.TitledView { + + companion object { + fun newInstance() = SettingsFragment() + } + + override val titleStringId: Int + get() = R.string.settings_title + + override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.scheme_preferences) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.kt index 058ee1a8..9330e5c4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.kt @@ -15,7 +15,7 @@ import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_timetable.* import javax.inject.Inject -class TimetableFragment : BaseFragment(), TimetableView, MainView.MenuFragmentView { +class TimetableFragment : BaseFragment(), TimetableView, MainView.MainChildView, MainView.TitledView { @Inject lateinit var presenter: TimetablePresenter @@ -29,6 +29,12 @@ class TimetableFragment : BaseFragment(), TimetableView, MainView.MenuFragmentVi fun newInstance() = TimetableFragment() } + override val titleStringId: Int + get() = R.string.timetable_title + + override val roomString: String + get() = getString(R.string.timetable_room) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_timetable, container, false) } @@ -99,8 +105,6 @@ class TimetableFragment : BaseFragment(), TimetableView, MainView.MenuFragmentVi TimetableDialog.newInstance(lesson).show(fragmentManager, lesson.toString()) } - override fun roomString() = getString(R.string.timetable_room) - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay()) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.kt index d91376bb..0a34d16d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.kt @@ -61,7 +61,7 @@ class TimetablePresenter @Inject constructor( .delay(200, MILLISECONDS) .map { it.single { semester -> semester.current } } .flatMap { timetableRepository.getTimetable(it, currentDate, currentDate, forceRefresh) } - .map { items -> items.map { TimetableItem(it, view?.roomString().orEmpty()) } } + .map { items -> items.map { TimetableItem(it, view?.roomString.orEmpty()) } } .subscribeOn(schedulers.backgroundThread()) .observeOn(schedulers.mainThread()) .doFinally { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableView.kt index c04a290b..5694ccb6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableView.kt @@ -5,6 +5,8 @@ import io.github.wulkanowy.ui.base.BaseView interface TimetableView : BaseView { + val roomString: String + fun initView() fun updateData(data: List) @@ -28,6 +30,4 @@ interface TimetableView : BaseView { fun showNextButton(show: Boolean) fun showTimetableDialog(lesson: Timetable) - - fun roomString(): String } diff --git a/app/src/main/java/io/github/wulkanowy/utils/FragNavControlerExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/FragNavControlerExtension.kt index ce1ec72a..dcf47754 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/FragNavControlerExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/FragNavControlerExtension.kt @@ -3,11 +3,18 @@ package io.github.wulkanowy.utils import androidx.fragment.app.Fragment import com.ncapdevi.fragnav.FragNavController -inline fun FragNavController.setOnTabTransactionListener(crossinline listener: (index: Int) -> Unit) { +inline fun FragNavController.setOnViewChangeListener(crossinline listener: (fragment: Fragment?) -> Unit) { transactionListener = object : FragNavController.TransactionListener { - override fun onFragmentTransaction(fragment: Fragment?, transactionType: FragNavController.TransactionType) {} + override fun onFragmentTransaction(fragment: Fragment?, transactionType: FragNavController.TransactionType) { + listener(fragment) + } + override fun onTabTransaction(fragment: Fragment?, index: Int) { - listener(index) + listener(fragment) } } -} \ No newline at end of file +} + +fun FragNavController.safelyPopFragment() { + if (!isRootFragment) popFragment() +} diff --git a/app/src/main/java/io/github/wulkanowy/utils/LibsBuiderExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/LibsBuiderExtension.kt new file mode 100644 index 00000000..d21b998b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utils/LibsBuiderExtension.kt @@ -0,0 +1,16 @@ +package io.github.wulkanowy.utils + +import android.view.View +import com.mikepenz.aboutlibraries.Libs +import com.mikepenz.aboutlibraries.LibsBuilder +import com.mikepenz.aboutlibraries.LibsConfiguration + +inline fun LibsBuilder.withOnExtraListener(crossinline listener: (Libs.SpecialButton?) -> Unit): LibsBuilder { + withListener(object : LibsConfiguration.LibsListenerImpl() { + override fun onExtraClicked(v: View?, specialButton: Libs.SpecialButton?): Boolean { + listener(specialButton) + return true + } + }) + return this +} diff --git a/app/src/main/res/drawable/ic_menu_grade_summary_24dp.xml b/app/src/main/res/drawable/ic_more_about_24dp.xml similarity index 85% rename from app/src/main/res/drawable/ic_menu_grade_summary_24dp.xml rename to app/src/main/res/drawable/ic_more_about_24dp.xml index 1b2a93b8..b0f56132 100644 --- a/app/src/main/res/drawable/ic_menu_grade_summary_24dp.xml +++ b/app/src/main/res/drawable/ic_more_about_24dp.xml @@ -4,10 +4,10 @@ android:viewportHeight="24" android:viewportWidth="24"> diff --git a/app/src/main/res/drawable/ic_more_settings_24dp.xml b/app/src/main/res/drawable/ic_more_settings_24dp.xml new file mode 100644 index 00000000..9e0bd837 --- /dev/null +++ b/app/src/main/res/drawable/ic_more_settings_24dp.xml @@ -0,0 +1,16 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 38057f7c..70c06ce8 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -9,6 +9,7 @@ android:id="@+id/mainAppBarContainer" android:layout_width="match_parent" android:layout_height="wrap_content" + android:theme="@style/WulkanowyTheme.ActionBar" app:elevation="0dp"> + + + + diff --git a/app/src/main/res/layout/item_more.xml b/app/src/main/res/layout/item_more.xml new file mode 100644 index 00000000..4b0f6772 --- /dev/null +++ b/app/src/main/res/layout/item_more.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 3ba7cd6a..fb6d913d 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -10,6 +10,7 @@ Plan lekcji Ustawienia Więcej + O aplikacji @@ -92,6 +93,9 @@ Typ Data wpisu + + Kod źródłowy + Zgłoś błąd Opis @@ -130,22 +134,11 @@ Interwał aktualizacji Tylko WiFi - Informacje o Wulkanowym - Wersja - Licencje open source - Szczegóły licencji na oprogramowanie open source - Kod źródłowy i feedback - - Nie, nie zostaniesz programistą! - Musisz bardziej się postarać! - Kliknij jeszcze parę razy - Odwiedź zakładkę Kod źródłowy i pokaż jaki z ciebie programista! - Wymagany restart - Nowe oceny + Nowe oceny Dostałeś %1$d ocenę "Dostałeś %1$d oceny diff --git a/app/src/main/res/values/library_wulkanowy_api.xml b/app/src/main/res/values/library_wulkanowy_api.xml new file mode 100644 index 00000000..d16bf86b --- /dev/null +++ b/app/src/main/res/values/library_wulkanowy_api.xml @@ -0,0 +1,17 @@ + + + + + Wulkanowy + https://github.com/wulkanowy + + UONET+ Scraping API + The UONET+ client using web scraping + https://github.com/wulkanowy/api + Development + + true + https://github.com/wulkanowy/api + + apache_2_0 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6b2b6cbf..4dc703fb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -10,6 +10,7 @@ Timetable Settings More + About @@ -87,6 +88,10 @@ Type Entry date + + Source code + Report a bug + Description @@ -125,22 +130,11 @@ Updates interval Only WiFi - About Wulkanowy - Version - Open source licences - License details for open source software - Source code & feedback - - No, you will not become a programmer! - You must try harder! - Click a few more times - Visit the Source code tab and show how good a programmer you are! - Restart required - New grades + New grades You received %1$d grade You received %1$d grades diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 98ab441a..18784f5f 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,6 +1,6 @@ - @@ -27,12 +26,7 @@ true - - diff --git a/app/src/main/res/xml/scheme_preferences.xml b/app/src/main/res/xml/scheme_preferences.xml index ae687aa8..9b170fd5 100644 --- a/app/src/main/res/xml/scheme_preferences.xml +++ b/app/src/main/res/xml/scheme_preferences.xml @@ -1,67 +1,21 @@ - - + + - + android:title="@string/pref_view_list" + app:iconSpaceReserved="false" /> - - - - - - - - - - - - - - + android:title="@string/pref_view_present" + app:iconSpaceReserved="false" /> diff --git a/app/src/test/java/io/github/wulkanowy/ui/login/LoginPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/login/LoginPresenterTest.kt index 74f85571..a06ea388 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/login/LoginPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/login/LoginPresenterTest.kt @@ -21,6 +21,7 @@ class LoginPresenterTest { fun initPresenter() { MockitoAnnotations.initMocks(this) clearInvocations(loginView) + presenter = LoginPresenter(errorHandler) presenter.onAttachView(loginView) } @@ -49,7 +50,7 @@ class LoginPresenterTest { @Test fun onBackPressedTest() { clearInvocations(loginView) - doReturn(1).`when`(loginView).currentViewPosition() + doReturn(1).`when`(loginView).currentViewIndex presenter.onBackPressed { } verify(loginView).switchView(0) verify(loginView).hideActionBar() @@ -58,7 +59,7 @@ class LoginPresenterTest { @Test fun onBackPressedDefaultTest() { var i = 0 - doReturn(0).`when`(loginView).currentViewPosition() + doReturn(0).`when`(loginView).currentViewIndex presenter.onBackPressed { i++ } assertNotEquals(0, i) } diff --git a/app/src/test/java/io/github/wulkanowy/ui/main/MainPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/main/MainPresenterTest.kt index 3bc96940..4002f99d 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/main/MainPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/main/MainPresenterTest.kt @@ -1,10 +1,12 @@ package io.github.wulkanowy.ui.main import io.github.wulkanowy.data.ErrorHandler +import io.github.wulkanowy.data.repositories.PreferencesRepository import org.junit.Before import org.junit.Test import org.mockito.Mock -import org.mockito.Mockito.* +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations class MainPresenterTest { @@ -12,6 +14,9 @@ class MainPresenterTest { @Mock lateinit var errorHandler: ErrorHandler + @Mock + lateinit var prefRepository: PreferencesRepository + @Mock lateinit var mainView: MainView @@ -22,7 +27,7 @@ class MainPresenterTest { MockitoAnnotations.initMocks(this) clearInvocations(mainView) - presenter = MainPresenter(errorHandler) + presenter = MainPresenter(errorHandler, prefRepository) presenter.onAttachView(mainView) } @@ -36,12 +41,5 @@ class MainPresenterTest { presenter.onTabSelected(1, false) verify(mainView).switchMenuView(1) } - - @Test - fun onMenuFragmentChangeTest() { - doReturn("Test").`when`(mainView).viewTitle(1) - presenter.onMenuViewChange(1) - verify(mainView).setViewTitle("Test") - } } diff --git a/build.gradle b/build.gradle index ad4fa283..d8960364 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,6 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.android.tools.build:gradle:3.2.1' classpath "io.fabric.tools:gradle:1.26.0" - classpath "com.google.gms:oss-licenses:0.9.2" classpath "com.github.triplet.gradle:play-publisher:1.2.2" classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2" }