Settings revamp (#1160)

This commit is contained in:
Damian Czupryn 2021-03-06 18:18:42 +01:00 committed by GitHub
parent 1afa7ecf3c
commit 47b0f1b527
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1001 additions and 413 deletions

View File

@ -52,7 +52,6 @@ class WulkanowyApp : Application(), Configuration.Provider {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
FragmentManager.enableNewStateManager(false) FragmentManager.enableNewStateManager(false)
initializeAppLanguage() initializeAppLanguage()
themeManager.applyDefaultTheme() themeManager.applyDefaultTheme()
initLogging() initLogging()

View File

@ -18,26 +18,43 @@ class PreferencesRepository @Inject constructor(
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt() get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
val isShowPresent: Boolean val isShowPresent: Boolean
get() = getBoolean(R.string.pref_key_attendance_present, R.bool.pref_default_attendance_present) get() = getBoolean(
R.string.pref_key_attendance_present,
R.bool.pref_default_attendance_present
)
val gradeAverageMode: GradeAverageMode val gradeAverageMode: GradeAverageMode
get() = GradeAverageMode.getByValue(getString(R.string.pref_key_grade_average_mode, R.string.pref_default_grade_average_mode)) get() = GradeAverageMode.getByValue(
getString(
R.string.pref_key_grade_average_mode,
R.string.pref_default_grade_average_mode
)
)
val gradeAverageForceCalc: Boolean val gradeAverageForceCalc: Boolean
get() = getBoolean(R.string.pref_key_grade_average_force_calc, R.bool.pref_default_grade_average_force_calc) get() = getBoolean(
R.string.pref_key_grade_average_force_calc,
R.bool.pref_default_grade_average_force_calc
)
val isGradeExpandable: Boolean val isGradeExpandable: Boolean
get() = !getBoolean(R.string.pref_key_expand_grade, R.bool.pref_default_expand_grade) get() = !getBoolean(R.string.pref_key_expand_grade, R.bool.pref_default_expand_grade)
val showAllSubjectsOnStatisticsList: Boolean val showAllSubjectsOnStatisticsList: Boolean
get() = getBoolean(R.string.pref_key_grade_statistics_list, R.bool.pref_default_grade_statistics_list) get() = getBoolean(
R.string.pref_key_grade_statistics_list,
R.bool.pref_default_grade_statistics_list
)
val appThemeKey = context.getString(R.string.pref_key_app_theme) val appThemeKey = context.getString(R.string.pref_key_app_theme)
val appTheme: String val appTheme: String
get() = getString(appThemeKey, R.string.pref_default_app_theme) get() = getString(appThemeKey, R.string.pref_default_app_theme)
val gradeColorTheme: String val gradeColorTheme: String
get() = getString(R.string.pref_key_grade_color_scheme, R.string.pref_default_grade_color_scheme) get() = getString(
R.string.pref_key_grade_color_scheme,
R.string.pref_default_grade_color_scheme
)
val appLanguageKey = context.getString(R.string.pref_key_app_language) val appLanguageKey = context.getString(R.string.pref_key_app_language)
val appLanguage val appLanguage
@ -55,50 +72,86 @@ class PreferencesRepository @Inject constructor(
val isServicesOnlyWifi: Boolean val isServicesOnlyWifi: Boolean
get() = getBoolean(servicesOnlyWifiKey, R.bool.pref_default_services_wifi_only) get() = getBoolean(servicesOnlyWifiKey, R.bool.pref_default_services_wifi_only)
val notificationsEnableKey = context.getString(R.string.pref_key_notifications_enable)
val isNotificationsEnable: Boolean val isNotificationsEnable: Boolean
get() = getBoolean(R.string.pref_key_notifications_enable, R.bool.pref_default_notifications_enable) get() = getBoolean(notificationsEnableKey, R.bool.pref_default_notifications_enable)
val isUpcomingLessonsNotificationsEnableKey = context.getString(R.string.pref_key_notifications_upcoming_lessons_enable) val isUpcomingLessonsNotificationsEnableKey =
context.getString(R.string.pref_key_notifications_upcoming_lessons_enable)
val isUpcomingLessonsNotificationsEnable: Boolean val isUpcomingLessonsNotificationsEnable: Boolean
get() = getBoolean(isUpcomingLessonsNotificationsEnableKey, R.bool.pref_default_notification_upcoming_lessons_enable) get() = getBoolean(
isUpcomingLessonsNotificationsEnableKey,
R.bool.pref_default_notification_upcoming_lessons_enable
)
val isDebugNotificationEnableKey = context.getString(R.string.pref_key_notification_debug) val isDebugNotificationEnableKey = context.getString(R.string.pref_key_notification_debug)
val isDebugNotificationEnable: Boolean val isDebugNotificationEnable: Boolean
get() = getBoolean(isDebugNotificationEnableKey, R.bool.pref_default_notification_debug) get() = getBoolean(isDebugNotificationEnableKey, R.bool.pref_default_notification_debug)
val gradePlusModifier: Double val gradePlusModifier: Double
get() = getString(R.string.pref_key_grade_modifier_plus, R.string.pref_default_grade_modifier_plus).toDouble() get() = getString(
R.string.pref_key_grade_modifier_plus,
R.string.pref_default_grade_modifier_plus
).toDouble()
val gradeMinusModifier: Double val gradeMinusModifier: Double
get() = getString(R.string.pref_key_grade_modifier_minus, R.string.pref_default_grade_modifier_minus).toDouble() get() = getString(
R.string.pref_key_grade_modifier_minus,
R.string.pref_default_grade_modifier_minus
).toDouble()
val fillMessageContent: Boolean val fillMessageContent: Boolean
get() = getBoolean(R.string.pref_key_fill_message_content, R.bool.pref_default_fill_message_content) get() = getBoolean(
R.string.pref_key_fill_message_content,
R.bool.pref_default_fill_message_content
)
val showGroupsInPlan: Boolean val showGroupsInPlan: Boolean
get() = getBoolean(R.string.pref_key_timetable_show_groups, R.bool.pref_default_timetable_show_groups) get() = getBoolean(
R.string.pref_key_timetable_show_groups,
R.bool.pref_default_timetable_show_groups
)
val showWholeClassPlan: String val showWholeClassPlan: String
get() = getString(R.string.pref_key_timetable_show_whole_class, R.string.pref_default_timetable_show_whole_class) get() = getString(
R.string.pref_key_timetable_show_whole_class,
R.string.pref_default_timetable_show_whole_class
)
val gradeSortingMode: GradeSortingMode val gradeSortingMode: GradeSortingMode
get() = GradeSortingMode.getByValue(getString(R.string.pref_key_grade_sorting_mode, R.string.pref_default_grade_sorting_mode)) get() = GradeSortingMode.getByValue(
getString(
R.string.pref_key_grade_sorting_mode,
R.string.pref_default_grade_sorting_mode
)
)
val showTimetableTimers: Boolean val showTimetableTimers: Boolean
get() = getBoolean(R.string.pref_key_timetable_show_timers, R.bool.pref_default_timetable_show_timers) get() = getBoolean(
R.string.pref_key_timetable_show_timers,
R.bool.pref_default_timetable_show_timers
)
var isHomeworkFullscreen: Boolean var isHomeworkFullscreen: Boolean
get() = getBoolean(R.string.pref_key_homework_fullscreen, R.bool.pref_default_homework_fullscreen) get() = getBoolean(
R.string.pref_key_homework_fullscreen,
R.bool.pref_default_homework_fullscreen
)
set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply() set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply()
val showSubjectsWithoutGrades: Boolean val showSubjectsWithoutGrades: Boolean
get() = getBoolean(R.string.pref_key_subjects_without_grades, R.bool.pref_default_subjects_without_grades) get() = getBoolean(
R.string.pref_key_subjects_without_grades,
R.bool.pref_default_subjects_without_grades
)
private fun getString(id: Int, default: Int) = getString(context.getString(id), default) private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
private fun getString(id: String, default: Int) = sharedPref.getString(id, context.getString(default)) ?: context.getString(default) private fun getString(id: String, default: Int) =
sharedPref.getString(id, context.getString(default)) ?: context.getString(default)
private fun getBoolean(id: Int, default: Int) = getBoolean(context.getString(id), default) private fun getBoolean(id: Int, default: Int) = getBoolean(context.getString(id), default)
private fun getBoolean(id: String, default: Int) = sharedPref.getBoolean(id, context.resources.getBoolean(default)) private fun getBoolean(id: String, default: Int) =
sharedPref.getBoolean(id, context.resources.getBoolean(default))
} }

View File

@ -15,12 +15,17 @@ import android.os.Build.VERSION_CODES.P
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.ViewGroup
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updateMargins
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState.ALWAYS_SHOW import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState.ALWAYS_SHOW
import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem
import com.google.android.material.elevation.ElevationOverlayProvider import com.google.android.material.elevation.ElevationOverlayProvider
@ -55,7 +60,8 @@ import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainView { class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainView,
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
@Inject @Inject
override lateinit var presenter: MainPresenter override lateinit var presenter: MainPresenter
@ -245,12 +251,20 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
with(navController) { with(navController) {
setOnViewChangeListener { section, name -> setOnViewChangeListener { section, name ->
if (section == MainView.Section.ACCOUNT || section == MainView.Section.STUDENT_INFO) { if (section == MainView.Section.ACCOUNT || section == MainView.Section.STUDENT_INFO) {
binding.mainBottomNav.visibility = View.GONE binding.mainBottomNav.isVisible = false
binding.mainFragmentContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
updateMargins(bottom = 0)
}
if (appInfo.systemVersion >= P) { if (appInfo.systemVersion >= P) {
window.navigationBarColor = getThemeAttrColor(R.attr.colorSurface) window.navigationBarColor = getThemeAttrColor(R.attr.colorSurface)
} }
} else { } else {
binding.mainBottomNav.visibility = View.VISIBLE binding.mainBottomNav.isVisible = true
binding.mainFragmentContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
updateMargins(bottom = dpToPx(56f).toInt())
}
if (appInfo.systemVersion >= P) { if (appInfo.systemVersion >= P) {
window.navigationBarColor = window.navigationBarColor =
getThemeAttrColor(android.R.attr.navigationBarColor) getThemeAttrColor(android.R.attr.navigationBarColor)
@ -271,6 +285,16 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
} }
} }
override fun onPreferenceStartFragment(
caller: PreferenceFragmentCompat,
pref: Preference
): Boolean {
val fragment =
supportFragmentManager.fragmentFactory.instantiate(classLoader, pref.fragment)
navController.pushFragment(fragment)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return if (item.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected() return if (item.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected()
else false else false

View File

@ -63,9 +63,6 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
override val settingsRes: Pair<String, Drawable?>? override val settingsRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.settings_title) to getCompatDrawable(R.drawable.ic_more_settings) } get() = context?.run { getString(R.string.settings_title) to getCompatDrawable(R.drawable.ic_more_settings) }
override val aboutRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.about_title) to getCompatDrawable(R.drawable.ic_all_about) }
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)
@ -124,10 +121,6 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance()) (activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
} }
override fun openAboutView() {
(activity as? MainActivity)?.pushView(AboutFragment.newInstance())
}
override fun popView(depth: Int) { override fun popView(depth: Int) {
(activity as? MainActivity)?.popView(depth) (activity as? MainActivity)?.popView(depth)
} }

View File

@ -30,7 +30,6 @@ class MorePresenter @Inject constructor(
conferencesRes?.first -> openConferencesView() conferencesRes?.first -> openConferencesView()
schoolAndTeachersRes?.first -> openSchoolAndTeachersView() schoolAndTeachersRes?.first -> openSchoolAndTeachersView()
settingsRes?.first -> openSettingsView() settingsRes?.first -> openSettingsView()
aboutRes?.first -> openAboutView()
} }
} }
} }
@ -51,8 +50,7 @@ class MorePresenter @Inject constructor(
mobileDevicesRes, mobileDevicesRes,
conferencesRes, conferencesRes,
schoolAndTeachersRes, schoolAndTeachersRes,
settingsRes, settingsRes
aboutRes
)) ))
} }
} }

View File

@ -21,16 +21,12 @@ interface MoreView : BaseView {
val settingsRes: Pair<String, Drawable?>? val settingsRes: Pair<String, Drawable?>?
val aboutRes: Pair<String, Drawable?>?
fun initView() fun initView()
fun updateData(data: List<Pair<String, Drawable?>>) fun updateData(data: List<Pair<String, Drawable?>>)
fun openSettingsView() fun openSettingsView()
fun openAboutView()
fun popView(depth: Int) fun popView(depth: Int)
fun openMessagesView() fun openMessagesView()

View File

@ -1,153 +1,22 @@
package io.github.wulkanowy.ui.modules.settings package io.github.wulkanowy.ui.modules.settings
import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.thelittlefireman.appkillermanager.AppKillerManager
import com.thelittlefireman.appkillermanager.exceptions.NoActionFoundException
import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AppInfo import timber.log.Timber
import io.github.wulkanowy.utils.openInternetBrowser
import javax.inject.Inject
@AndroidEntryPoint class SettingsFragment : PreferenceFragmentCompat(), MainView.TitledView {
class SettingsFragment : PreferenceFragmentCompat(),
SharedPreferences.OnSharedPreferenceChangeListener,
MainView.TitledView, SettingsView {
@Inject
lateinit var presenter: SettingsPresenter
@Inject
lateinit var appInfo: AppInfo
@Inject
lateinit var lingver: Lingver
companion object { companion object {
fun newInstance() = SettingsFragment() fun newInstance() = SettingsFragment()
} }
override val titleStringId get() = R.string.settings_title override val titleStringId get() = R.string.settings_title
override val syncSuccessString get() = getString(R.string.pref_services_message_sync_success)
override val syncFailedString get() = getString(R.string.pref_services_message_sync_failed)
override fun initView() {
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
onPreferenceClickListener = Preference.OnPreferenceClickListener {
presenter.onSyncNowClicked()
true
}
}
findPreference<Preference>(getString(R.string.pref_key_notifications_fix_issues))?.run {
isVisible =
AppKillerManager.isDeviceSupported() && AppKillerManager.isAnyActionAvailable(
requireContext()
)
setOnPreferenceClickListener {
presenter.onFixSyncIssuesClicked()
true
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter.onAttachView(this)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.scheme_preferences, rootKey) setPreferencesFromResource(R.xml.scheme_preferences, rootKey)
findPreference<Preference>(getString(R.string.pref_key_notification_debug))?.isVisible = Timber.i("Settings view was initialized")
appInfo.isDebug
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
presenter.onSharedPreferenceChanged(key)
}
override fun recreateView() {
activity?.recreate()
}
override fun updateLanguage(langCode: String) {
lingver.setLocale(requireContext(), langCode)
}
override fun updateLanguageToFollowSystem() {
lingver.setFollowSystemLocale(requireContext())
}
override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) {
findPreference<Preference>(serviceEnablesKey)?.run {
summary = if (isHolidays) getString(R.string.pref_services_suspended) else ""
isEnabled = !isHolidays
}
}
override fun setSyncInProgress(inProgress: Boolean) {
if (activity == null || !isAdded) return
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
isEnabled = !inProgress
summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else ""
}
}
override fun showError(text: String, error: Throwable) {
(activity as? BaseActivity<*, *>)?.showError(text, error)
}
override fun showMessage(text: String) {
(activity as? BaseActivity<*, *>)?.showMessage(text)
}
override fun showExpiredDialog() {
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
}
override fun openClearLoginView() {
(activity as? BaseActivity<*, *>)?.openClearLoginView()
}
override fun showErrorDetailsDialog(error: Throwable) {
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}
override fun showFixSyncDialog() {
AlertDialog.Builder(requireContext())
.setTitle(R.string.pref_notify_fix_sync_issues)
.setMessage(R.string.pref_notify_fix_sync_issues_message)
.setNegativeButton(android.R.string.cancel) { _, _ -> }
.setPositiveButton(R.string.pref_notify_fix_sync_issues_settings_button) { _, _ ->
try {
AppKillerManager.doActionPowerSaving(requireContext())
AppKillerManager.doActionAutoStart(requireContext())
AppKillerManager.doActionNotification(requireContext())
} catch (e: NoActionFoundException) {
requireContext().openInternetBrowser("https://dontkillmyapp.com/${AppKillerManager.getDevice()?.manufacturer}", ::showMessage)
}
}
.show()
}
override fun onResume() {
super.onResume()
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
super.onPause()
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
} }
} }

View File

@ -0,0 +1,78 @@
package io.github.wulkanowy.ui.modules.settings.advanced
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.preference.PreferenceFragmentCompat
import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Inject
@AndroidEntryPoint
class AdvancedFragment : PreferenceFragmentCompat(),
SharedPreferences.OnSharedPreferenceChangeListener,
MainView.TitledView, AdvancedView {
@Inject
lateinit var presenter: AdvancedPresenter
@Inject
lateinit var appInfo: AppInfo
@Inject
lateinit var lingver: Lingver
companion object {
fun newInstance() = AdvancedFragment()
}
override val titleStringId get() = R.string.pref_settings_advanced_title
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter.onAttachView(this)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.scheme_preferences_advanced, rootKey)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
presenter.onSharedPreferenceChanged(key)
}
override fun showError(text: String, error: Throwable) {
(activity as? BaseActivity<*, *>)?.showError(text, error)
}
override fun showMessage(text: String) {
(activity as? BaseActivity<*, *>)?.showMessage(text)
}
override fun showExpiredDialog() {
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
}
override fun openClearLoginView() {
(activity as? BaseActivity<*, *>)?.openClearLoginView()
}
override fun showErrorDetailsDialog(error: Throwable) {
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}
override fun onResume() {
super.onResume()
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
super.onPause()
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
}
}

View File

@ -0,0 +1,25 @@
package io.github.wulkanowy.ui.modules.settings.advanced
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
import timber.log.Timber
import javax.inject.Inject
class AdvancedPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val analytics: AnalyticsHelper,
) : BasePresenter<AdvancedView>(errorHandler, studentRepository) {
override fun onAttachView(view: AdvancedView) {
super.onAttachView(view)
Timber.i("Settings advanced view was initialized")
}
fun onSharedPreferenceChanged(key: String) {
Timber.i("Change settings $key")
analytics.logEvent("setting_changed", "name" to key)
}
}

View File

@ -0,0 +1,5 @@
package io.github.wulkanowy.ui.modules.settings.advanced
import io.github.wulkanowy.ui.base.BaseView
interface AdvancedView : BaseView {}

View File

@ -0,0 +1,90 @@
package io.github.wulkanowy.ui.modules.settings.appearance
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.preference.PreferenceFragmentCompat
import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Inject
@AndroidEntryPoint
class AppearanceFragment : PreferenceFragmentCompat(),
SharedPreferences.OnSharedPreferenceChangeListener,
MainView.TitledView, AppearanceView {
@Inject
lateinit var presenter: AppearancePresenter
@Inject
lateinit var appInfo: AppInfo
@Inject
lateinit var lingver: Lingver
companion object {
fun newInstance() = AppearanceFragment()
}
override val titleStringId get() = R.string.pref_settings_appearance_title
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter.onAttachView(this)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.scheme_preferences_appearance, rootKey)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
presenter.onSharedPreferenceChanged(key)
}
override fun recreateView() {
activity?.recreate()
}
override fun updateLanguage(langCode: String) {
lingver.setLocale(requireContext(), langCode)
}
override fun updateLanguageToFollowSystem() {
lingver.setFollowSystemLocale(requireContext())
}
override fun showError(text: String, error: Throwable) {
(activity as? BaseActivity<*, *>)?.showError(text, error)
}
override fun showMessage(text: String) {
(activity as? BaseActivity<*, *>)?.showMessage(text)
}
override fun showExpiredDialog() {
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
}
override fun openClearLoginView() {
(activity as? BaseActivity<*, *>)?.openClearLoginView()
}
override fun showErrorDetailsDialog(error: Throwable) {
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}
override fun onResume() {
super.onResume()
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
super.onPause()
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
}
}

View File

@ -0,0 +1,45 @@
package io.github.wulkanowy.ui.modules.settings.appearance
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 io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import timber.log.Timber
import javax.inject.Inject
class AppearancePresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val preferencesRepository: PreferencesRepository,
private val analytics: AnalyticsHelper,
private val appInfo: AppInfo
) : BasePresenter<AppearanceView>(errorHandler, studentRepository) {
override fun onAttachView(view: AppearanceView) {
super.onAttachView(view)
Timber.i("Settings appearance view was initialized")
}
fun onSharedPreferenceChanged(key: String) {
Timber.i("Change settings $key")
preferencesRepository.apply {
when (key) {
appThemeKey -> view?.recreateView()
appLanguageKey -> view?.run {
if (appLanguage == "system") {
updateLanguageToFollowSystem()
analytics.logEvent("language", "setting_changed" to appInfo.systemLanguage)
} else {
updateLanguage(appLanguage)
analytics.logEvent("language", "setting_changed" to appLanguage)
}
recreateView()
}
}
}
analytics.logEvent("setting_changed", "name" to key)
}
}

View File

@ -0,0 +1,12 @@
package io.github.wulkanowy.ui.modules.settings.appearance
import io.github.wulkanowy.ui.base.BaseView
interface AppearanceView : BaseView {
fun recreateView()
fun updateLanguage(langCode: String)
fun updateLanguageToFollowSystem()
}

View File

@ -0,0 +1,130 @@
package io.github.wulkanowy.ui.modules.settings.notifications
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.recyclerview.widget.RecyclerView
import com.thelittlefireman.appkillermanager.AppKillerManager
import com.thelittlefireman.appkillermanager.exceptions.NoActionFoundException
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.openInternetBrowser
import javax.inject.Inject
@AndroidEntryPoint
class NotificationsFragment : PreferenceFragmentCompat(),
SharedPreferences.OnSharedPreferenceChangeListener,
MainView.TitledView, NotificationsView {
@Inject
lateinit var presenter: NotificationsPresenter
companion object {
fun newInstance() = NotificationsFragment()
}
override val titleStringId get() = R.string.pref_settings_notifications_title
override fun initView(showDebugNotificationSwitch: Boolean) {
findPreference<Preference>(getString(R.string.pref_key_notification_debug))?.isVisible =
showDebugNotificationSwitch
findPreference<Preference>(getString(R.string.pref_key_notifications_fix_issues))?.run {
isVisible = AppKillerManager.isDeviceSupported()
&& AppKillerManager.isAnyActionAvailable(requireContext())
setOnPreferenceClickListener {
presenter.onFixSyncIssuesClicked()
true
}
}
}
override fun onCreateRecyclerView(
inflater: LayoutInflater?,
parent: ViewGroup?,
state: Bundle?
): RecyclerView? = super.onCreateRecyclerView(inflater, parent, state)
.also {
it.itemAnimator = null
it.layoutAnimation = null
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter.onAttachView(this)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.scheme_preferences_notifications, rootKey)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
presenter.onSharedPreferenceChanged(key)
}
override fun enableNotification(notificationKey: String, enable: Boolean) {
findPreference<Preference>(notificationKey)?.run {
isEnabled = enable
summary = if (enable) null else getString(R.string.pref_notify_disabled_summary)
}
}
override fun showError(text: String, error: Throwable) {
(activity as? BaseActivity<*, *>)?.showError(text, error)
}
override fun showMessage(text: String) {
(activity as? BaseActivity<*, *>)?.showMessage(text)
}
override fun showExpiredDialog() {
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
}
override fun openClearLoginView() {
(activity as? BaseActivity<*, *>)?.openClearLoginView()
}
override fun showErrorDetailsDialog(error: Throwable) {
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}
override fun showFixSyncDialog() {
AlertDialog.Builder(requireContext())
.setTitle(R.string.pref_notify_fix_sync_issues)
.setMessage(R.string.pref_notify_fix_sync_issues_message)
.setNegativeButton(android.R.string.cancel) { _, _ -> }
.setPositiveButton(R.string.pref_notify_fix_sync_issues_settings_button) { _, _ ->
try {
AppKillerManager.doActionPowerSaving(requireContext())
AppKillerManager.doActionAutoStart(requireContext())
AppKillerManager.doActionNotification(requireContext())
} catch (e: NoActionFoundException) {
requireContext().openInternetBrowser(
"https://dontkillmyapp.com/${AppKillerManager.getDevice()?.manufacturer}",
::showMessage
)
}
}
.show()
}
override fun onResume() {
super.onResume()
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
super.onPause()
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
}
}

View File

@ -0,0 +1,58 @@
package io.github.wulkanowy.ui.modules.settings.notifications
import com.chuckerteam.chucker.api.ChuckerCollector
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import timber.log.Timber
import javax.inject.Inject
class NotificationsPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val preferencesRepository: PreferencesRepository,
private val timetableNotificationHelper: TimetableNotificationSchedulerHelper,
private val appInfo: AppInfo,
private val analytics: AnalyticsHelper,
private val chuckerCollector: ChuckerCollector
) : BasePresenter<NotificationsView>(errorHandler, studentRepository) {
override fun onAttachView(view: NotificationsView) {
super.onAttachView(view)
with(view) {
enableNotification(
preferencesRepository.notificationsEnableKey,
preferencesRepository.isServiceEnabled
)
initView(appInfo.isDebug)
}
Timber.i("Settings notifications view was initialized")
}
fun onSharedPreferenceChanged(key: String) {
Timber.i("Change settings $key")
preferencesRepository.apply {
when (key) {
isUpcomingLessonsNotificationsEnableKey -> {
if (!isUpcomingLessonsNotificationsEnable) {
timetableNotificationHelper.cancelNotification()
}
}
isDebugNotificationEnableKey -> {
chuckerCollector.showNotification = isDebugNotificationEnable
}
}
}
analytics.logEvent("setting_changed", "name" to key)
}
fun onFixSyncIssuesClicked() {
view?.showFixSyncDialog()
}
}

View File

@ -0,0 +1,12 @@
package io.github.wulkanowy.ui.modules.settings.notifications
import io.github.wulkanowy.ui.base.BaseView
interface NotificationsView : BaseView {
fun initView(showDebugNotificationSwitch: Boolean)
fun showFixSyncDialog()
fun enableNotification(notificationKey: String, enable: Boolean)
}

View File

@ -0,0 +1,100 @@
package io.github.wulkanowy.ui.modules.settings.sync
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.base.ErrorDialog
import io.github.wulkanowy.ui.modules.main.MainView
import javax.inject.Inject
@AndroidEntryPoint
class SyncFragment : PreferenceFragmentCompat(),
SharedPreferences.OnSharedPreferenceChangeListener,
MainView.TitledView, SyncView {
@Inject
lateinit var presenter: SyncPresenter
companion object {
fun newInstance() = SyncFragment()
}
override val titleStringId get() = R.string.pref_settings_sync_title
override val syncSuccessString get() = getString(R.string.pref_services_message_sync_success)
override val syncFailedString get() = getString(R.string.pref_services_message_sync_failed)
override fun initView() {
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
onPreferenceClickListener = Preference.OnPreferenceClickListener {
presenter.onSyncNowClicked()
true
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter.onAttachView(this)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.scheme_preferences_sync, rootKey)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
presenter.onSharedPreferenceChanged(key)
}
override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) {
findPreference<Preference>(serviceEnablesKey)?.run {
summary = if (isHolidays) getString(R.string.pref_services_suspended) else ""
isEnabled = !isHolidays
}
}
override fun setSyncInProgress(inProgress: Boolean) {
if (activity == null || !isAdded) return
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
isEnabled = !inProgress
summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else ""
}
}
override fun showError(text: String, error: Throwable) {
(activity as? BaseActivity<*, *>)?.showError(text, error)
}
override fun showMessage(text: String) {
(activity as? BaseActivity<*, *>)?.showMessage(text)
}
override fun showExpiredDialog() {
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
}
override fun openClearLoginView() {
(activity as? BaseActivity<*, *>)?.openClearLoginView()
}
override fun showErrorDetailsDialog(error: Throwable) {
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}
override fun onResume() {
super.onResume()
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
super.onPause()
preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
}
}

View File

@ -1,15 +1,12 @@
package io.github.wulkanowy.ui.modules.settings package io.github.wulkanowy.ui.modules.settings.sync
import androidx.work.WorkInfo import androidx.work.WorkInfo
import com.chuckerteam.chucker.api.ChuckerCollector
import io.github.wulkanowy.data.repositories.PreferencesRepository 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.services.alarm.TimetableNotificationSchedulerHelper
import io.github.wulkanowy.services.sync.SyncManager import io.github.wulkanowy.services.sync.SyncManager
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.utils.AnalyticsHelper import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.isHolidays import io.github.wulkanowy.utils.isHolidays
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -17,20 +14,17 @@ import timber.log.Timber
import java.time.LocalDate.now import java.time.LocalDate.now
import javax.inject.Inject import javax.inject.Inject
class SettingsPresenter @Inject constructor( class SyncPresenter @Inject constructor(
errorHandler: ErrorHandler, errorHandler: ErrorHandler,
studentRepository: StudentRepository, studentRepository: StudentRepository,
private val preferencesRepository: PreferencesRepository, private val preferencesRepository: PreferencesRepository,
private val timetableNotificationHelper: TimetableNotificationSchedulerHelper,
private val analytics: AnalyticsHelper, private val analytics: AnalyticsHelper,
private val syncManager: SyncManager, private val syncManager: SyncManager,
private val chuckerCollector: ChuckerCollector, ) : BasePresenter<SyncView>(errorHandler, studentRepository) {
private val appInfo: AppInfo
) : BasePresenter<SettingsView>(errorHandler, studentRepository) {
override fun onAttachView(view: SettingsView) { override fun onAttachView(view: SyncView) {
super.onAttachView(view) super.onAttachView(view)
Timber.i("Settings view was initialized") Timber.i("Settings sync view was initialized")
view.setServicesSuspended(preferencesRepository.serviceEnableKey, now().isHolidays) view.setServicesSuspended(preferencesRepository.serviceEnableKey, now().isHolidays)
view.initView() view.initView()
} }
@ -42,20 +36,6 @@ class SettingsPresenter @Inject constructor(
when (key) { when (key) {
serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startPeriodicSyncWorker() else stopSyncWorker() } serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startPeriodicSyncWorker() else stopSyncWorker() }
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startPeriodicSyncWorker(true) servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startPeriodicSyncWorker(true)
isDebugNotificationEnableKey -> chuckerCollector.showNotification =
isDebugNotificationEnable
appThemeKey -> view?.recreateView()
isUpcomingLessonsNotificationsEnableKey -> if (!isUpcomingLessonsNotificationsEnable) timetableNotificationHelper.cancelNotification()
appLanguageKey -> view?.run {
if (appLanguage == "system") {
updateLanguageToFollowSystem()
analytics.logEvent("language", "setting_changed" to appInfo.systemLanguage)
} else {
updateLanguage(appLanguage)
analytics.logEvent("language", "setting_changed" to appLanguage)
}
recreateView()
}
} }
} }
analytics.logEvent("setting_changed", "name" to key) analytics.logEvent("setting_changed", "name" to key)
@ -89,8 +69,4 @@ class SettingsPresenter @Inject constructor(
}.launch("sync") }.launch("sync")
} }
} }
fun onFixSyncIssuesClicked() {
view?.showFixSyncDialog()
}
} }

View File

@ -1,8 +1,8 @@
package io.github.wulkanowy.ui.modules.settings package io.github.wulkanowy.ui.modules.settings.sync
import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.base.BaseView
interface SettingsView : BaseView { interface SyncView : BaseView {
val syncSuccessString: String val syncSuccessString: String
@ -10,15 +10,7 @@ interface SettingsView : BaseView {
fun initView() fun initView()
fun recreateView()
fun updateLanguage(langCode: String)
fun updateLanguageToFollowSystem()
fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean)
fun setSyncInProgress(inProgress: Boolean) fun setSyncInProgress(inProgress: Boolean)
fun showFixSyncDialog()
} }

View File

@ -2,6 +2,7 @@
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:tint="?colorOnSurface"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FFF" android:fillColor="#FFF"

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M14.17,13.71l1.4,-2.42c0.09,-0.15 0.05,-0.34 -0.08,-0.45l-1.48,-1.16c0.03,-0.22 0.05,-0.45 0.05,-0.68s-0.02,-0.46 -0.05,-0.69l1.48,-1.16c0.13,-0.11 0.17,-0.3 0.08,-0.45l-1.4,-2.42c-0.09,-0.15 -0.27,-0.21 -0.43,-0.15L12,4.83c-0.36,-0.28 -0.75,-0.51 -1.18,-0.69l-0.26,-1.85C10.53,2.13 10.38,2 10.21,2h-2.8C7.24,2 7.09,2.13 7.06,2.3L6.8,4.15C6.38,4.33 5.98,4.56 5.62,4.84l-1.74,-0.7c-0.16,-0.06 -0.34,0 -0.43,0.15l-1.4,2.42C1.96,6.86 2,7.05 2.13,7.16l1.48,1.16C3.58,8.54 3.56,8.77 3.56,9s0.02,0.46 0.05,0.69l-1.48,1.16C2,10.96 1.96,11.15 2.05,11.3l1.4,2.42c0.09,0.15 0.27,0.21 0.43,0.15l1.74,-0.7c0.36,0.28 0.75,0.51 1.18,0.69l0.26,1.85C7.09,15.87 7.24,16 7.41,16h2.8c0.17,0 0.32,-0.13 0.35,-0.3l0.26,-1.85c0.42,-0.18 0.82,-0.41 1.18,-0.69l1.74,0.7C13.9,13.92 14.08,13.86 14.17,13.71zM8.81,11c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C10.81,10.1 9.91,11 8.81,11z" />
<path
android:fillColor="@android:color/white"
android:pathData="M21.92,18.67l-0.96,-0.74c0.02,-0.14 0.04,-0.29 0.04,-0.44c0,-0.15 -0.01,-0.3 -0.04,-0.44l0.95,-0.74c0.08,-0.07 0.11,-0.19 0.05,-0.29l-0.9,-1.55c-0.05,-0.1 -0.17,-0.13 -0.28,-0.1l-1.11,0.45c-0.23,-0.18 -0.48,-0.33 -0.76,-0.44l-0.17,-1.18C18.73,13.08 18.63,13 18.53,13h-1.79c-0.11,0 -0.21,0.08 -0.22,0.19l-0.17,1.18c-0.27,0.12 -0.53,0.26 -0.76,0.44l-1.11,-0.45c-0.1,-0.04 -0.22,0 -0.28,0.1l-0.9,1.55c-0.05,0.1 -0.04,0.22 0.05,0.29l0.95,0.74c-0.02,0.14 -0.03,0.29 -0.03,0.44c0,0.15 0.01,0.3 0.03,0.44l-0.95,0.74c-0.08,0.07 -0.11,0.19 -0.05,0.29l0.9,1.55c0.05,0.1 0.17,0.13 0.28,0.1l1.11,-0.45c0.23,0.18 0.48,0.33 0.76,0.44l0.17,1.18c0.02,0.11 0.11,0.19 0.22,0.19h1.79c0.11,0 0.21,-0.08 0.22,-0.19l0.17,-1.18c0.27,-0.12 0.53,-0.26 0.75,-0.44l1.12,0.45c0.1,0.04 0.22,0 0.28,-0.1l0.9,-1.55C22.03,18.86 22,18.74 21.92,18.67zM17.63,18.83c-0.74,0 -1.35,-0.6 -1.35,-1.35s0.6,-1.35 1.35,-1.35s1.35,0.6 1.35,1.35S18.37,18.83 17.63,18.83z" />
</vector>

View File

@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,22C6.49,22 2,17.51 2,12S6.49,2 12,2s10,4.04 10,9c0,3.31 -2.69,6 -6,6h-1.77c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.12 0.05,0.23 0.13,0.33 0.41,0.47 0.64,1.06 0.64,1.67 0,1.38 -1.12,2.5 -2.5,2.5zM12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8c0.28,0 0.5,-0.22 0.5,-0.5 0,-0.16 -0.08,-0.28 -0.14,-0.35 -0.41,-0.46 -0.63,-1.05 -0.63,-1.65 0,-1.38 1.12,-2.5 2.5,-2.5L16,15c2.21,0 4,-1.79 4,-4 0,-3.86 -3.59,-7 -8,-7z" />
<path
android:fillColor="@android:color/white"
android:pathData="M6.5,11.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
<path
android:fillColor="@android:color/white"
android:pathData="M9.5,7.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
<path
android:fillColor="@android:color/white"
android:pathData="M14.5,7.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
<path
android:fillColor="@android:color/white"
android:pathData="M17.5,11.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM18,16v-5c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.64,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2zM16,17L8,17v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5v6z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z" />
</vector>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mainContainer" android:id="@+id/mainContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -10,19 +10,18 @@
style="@style/Widget.MaterialComponents.Toolbar.Surface" style="@style/Widget.MaterialComponents.Toolbar.Surface"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:contentInsetStartWithNavigation="0dp" app:contentInsetStartWithNavigation="0dp" />
app:layout_constraintTop_toTopOf="parent" />
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView
android:id="@+id/mainFragmentContainer" android:id="@+id/mainFragmentContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent"
app:layout_constraintBottom_toTopOf="@id/mainBottomNav" android:layout_marginTop="?actionBarSize"
app:layout_constraintTop_toBottomOf="@id/mainToolbar" /> android:layout_marginBottom="@dimen/bottom_navigation_height" />
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation <com.aurelhubert.ahbottomnavigation.AHBottomNavigation
android:id="@+id/mainBottomNav" android:id="@+id/mainBottomNav"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" /> android:layout_gravity="bottom" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -464,21 +464,21 @@
<!--Preferences--> <!--Preferences-->
<string name="pref_view_header">Appearance</string> <string name="pref_view_header">App apearance &amp; behavior</string>
<string name="pref_view_list">Default view</string> <string name="pref_view_list">Default view</string>
<string name="pref_view_grade_average_mode">Calculation of the end-of-year average</string> <string name="pref_view_grade_average_mode">Calculation of the end-of-year average</string>
<string name="pref_view_grade_average_force_calc">Force average calculation by app</string> <string name="pref_view_grade_average_force_calc">Force average calculation by app</string>
<string name="pref_view_present">Show presence in attendance</string> <string name="pref_view_present">Show presence</string>
<string name="pref_view_app_theme">Application theme</string> <string name="pref_view_app_theme">Theme</string>
<string name="pref_view_expand_grade">Expand grades</string> <string name="pref_view_expand_grade">Expand grades</string>
<string name="pref_view_timetable_show_timers">Mark current lesson in timetable</string> <string name="pref_view_timetable_show_timers">Mark current lesson</string>
<string name="pref_view_timetable_show_groups">Show groups next to subjects in timetable</string> <string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string> <string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
<string name="pref_view_timetable_show_whole_class">Show whole class lessons</string> <string name="pref_view_timetable_show_whole_class">Show whole class lessons</string>
<string name="pref_view_subjects_without_grades">Show subjects without grades in Grades</string> <string name="pref_view_subjects_without_grades">Show subjects without grades</string>
<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 in "Grades"</string> <string name="pref_view_grade_sorting_mode">Subjects sorting</string>
<string name="pref_view_app_language">App language</string> <string name="pref_view_app_language">Language</string>
<string name="pref_notify_header">Notifications</string> <string name="pref_notify_header">Notifications</string>
<string name="pref_notify_switch">Show notifications</string> <string name="pref_notify_switch">Show notifications</string>
@ -487,6 +487,7 @@
<string name="pref_notify_fix_sync_issues_message">Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings.</string> <string name="pref_notify_fix_sync_issues_message">Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings.</string>
<string name="pref_notify_fix_sync_issues_settings_button">Go to settings</string> <string name="pref_notify_fix_sync_issues_settings_button">Go to settings</string>
<string name="pref_notify_debug_switch">Show debug notifications</string> <string name="pref_notify_debug_switch">Show debug notifications</string>
<string name="pref_notify_disabled_summary">Synchronization is disabled</string>
<string name="pref_services_header">Synchronization</string> <string name="pref_services_header">Synchronization</string>
<string name="pref_services_switch">Automatic update</string> <string name="pref_services_switch">Automatic update</string>
@ -497,17 +498,32 @@
<string name="pref_services_message_sync_success">Synced!</string> <string name="pref_services_message_sync_success">Synced!</string>
<string name="pref_services_message_sync_failed">Sync failed</string> <string name="pref_services_message_sync_failed">Sync failed</string>
<string name="pref_services_sync_in_progress">Sync in progress</string> <string name="pref_services_sync_in_progress">Sync in progress</string>
<string name="pref_services_dialog_force_sync_title">Synchronization</string>
<string name="pref_services_dialog_force_sync_summary">
Manual sync doesn\'t refresh app views.
\nTo see the synced data relaunch the app after syncing.
</string>
<string name="pref_other_header">Other</string>
<string name="pref_other_grade_modifier_plus">Value of the plus</string> <string name="pref_other_grade_modifier_plus">Value of the plus</string>
<string name="pref_other_grade_modifier_minus">Value of the minus</string> <string name="pref_other_grade_modifier_minus">Value of the minus</string>
<string name="pref_other_fill_message_content">Reply with message history</string> <string name="pref_other_fill_message_content">Reply with message history</string>
<string name="pref_settings_advanced_title">Advanced</string>
<string name="pref_settings_appearance_title">Appearance &amp; Behavior</string>
<string name="pref_settings_notifications_title">Notifications</string>
<string name="pref_settings_sync_title">Synchronization</string>
<string name="pref_grades_appearance_header">Grades</string>
<string name="pref_attendance_appearance_view">Attendance</string>
<string name="pref_timetable_appearance_view">Timetable</string>
<string name="pref_grades_advanced_header">Grades</string>
<string name="pref_messages_advanced_header">Messages</string>
<string name="pref_appearance_category">Appearance &amp; Behavior</string>
<string name="pref_appearance_category_summary">Languages, themes, subjects sorting</string>
<string name="pref_notifications_category_summary">App notifications, fix problems</string>
<string name="pref_notifications_category">Notifications</string>
<string name="pref_sync_category">Synchronization</string>
<string name="pref_sync_category_summary">Automatic update, synchronization interval</string>
<string name="pref_advanced_category_summary">Plus and minus values, average calculation</string>
<string name="pref_advanced_category">Advanced</string>
<string name="pref_about_category_summary">App version, contributors, social portals, licenses</string>
<!--Notification Channels--> <!--Notification Channels-->
<string name="channel_new_entries">New entries in register</string> <string name="channel_new_entries">New entries in register</string>

View File

@ -1,182 +1,33 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"> <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_view_header">
<ListPreference
app:defaultValue="@string/pref_default_startup"
app:entries="@array/startup_tab_entries"
app:entryValues="@array/startup_tab_value"
app:iconSpaceReserved="false"
app:key="@string/pref_key_start_menu"
app:title="@string/pref_view_list"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_app_theme"
app:entries="@array/app_theme_entries"
app:entryValues="@array/app_theme_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_app_theme"
app:title="@string/pref_view_app_theme"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_attendance_present"
app:iconSpaceReserved="false"
app:key="@string/pref_key_attendance_present"
app:title="@string/pref_view_present" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_expand_grade"
app:iconSpaceReserved="false"
app:key="@string/pref_key_expand_grade"
app:title="@string/pref_view_expand_grade" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_timetable_show_timers"
app:iconSpaceReserved="false"
app:key="@string/pref_key_timetable_show_timers"
app:title="@string/pref_view_timetable_show_timers" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_grade_statistics_list"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_statistics_list"
app:singleLineTitle="false"
app:title="@string/pref_view_grade_statistics_list" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_timetable_show_groups"
app:iconSpaceReserved="false"
app:key="@string/pref_key_timetable_show_groups"
app:singleLineTitle="false"
app:title="@string/pref_view_timetable_show_groups" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_subjects_without_grades"
app:iconSpaceReserved="false"
app:key="@string/pref_key_subjects_without_grades"
app:singleLineTitle="false"
app:title="@string/pref_view_subjects_without_grades" />
<ListPreference
app:defaultValue="@string/pref_default_timetable_show_whole_class"
app:entries="@array/timetable_show_whole_class_entries"
app:entryValues="@array/timetable_show_whole_class_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_timetable_show_whole_class"
app:title="@string/pref_view_timetable_show_whole_class"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_grade_color_scheme"
app:entries="@array/grade_color_scheme_entries"
app:entryValues="@array/grade_color_scheme_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_color_scheme"
app:title="@string/pref_view_grade_color_scheme"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_grade_sorting_mode"
app:entries="@array/grade_sorting_mode_entries"
app:entryValues="@array/grade_sorting_mode_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_sorting_mode"
app:title="@string/pref_view_grade_sorting_mode"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_app_language"
app:entries="@array/app_language_entries"
app:entryValues="@array/app_language_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_app_language"
app:title="@string/pref_view_app_language"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_services_header">
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_services_enable"
app:iconSpaceReserved="false"
app:key="@string/pref_key_services_enable"
app:title="@string/pref_services_switch" />
<ListPreference
app:defaultValue="@string/pref_default_services_interval"
app:dependency="services_enable"
app:entries="@array/services_interval_entries"
app:entryValues="@array/services_interval_value"
app:iconSpaceReserved="false"
app:key="@string/pref_key_services_interval"
app:title="@string/pref_services_interval"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_services_wifi_only"
app:dependency="services_enable"
app:iconSpaceReserved="false"
app:key="@string/pref_key_services_wifi_only"
app:title="@string/pref_services_wifi" />
<Preference <Preference
app:iconSpaceReserved="false" app:key="appearance"
app:key="@string/pref_key_services_force_sync" app:icon="@drawable/ic_settings_appearance"
app:title="@string/pref_services_force_sync" /> app:summary="@string/pref_appearance_category_summary"
</PreferenceCategory> app:title="@string/pref_appearance_category"
<PreferenceCategory app:fragment="io.github.wulkanowy.ui.modules.settings.appearance.AppearanceFragment" />
app:iconSpaceReserved="false"
app:title="@string/pref_notify_header">
<Preference <Preference
app:iconSpaceReserved="false" app:key="notifications"
app:key="@string/pref_key_notifications_fix_issues" app:icon="@drawable/ic_settings_notifications"
app:title="@string/pref_notify_fix_sync_issues" /> app:summary="@string/pref_notifications_category_summary"
<SwitchPreferenceCompat app:title="@string/pref_notifications_category"
app:defaultValue="@bool/pref_default_notifications_enable" app:fragment="io.github.wulkanowy.ui.modules.settings.notifications.NotificationsFragment" />
app:dependency="services_enable" <Preference
app:iconSpaceReserved="false" app:key="sync"
app:key="@string/pref_key_notifications_enable" app:icon="@drawable/ic_settings_sync"
app:title="@string/pref_notify_switch" /> app:summary="@string/pref_sync_category_summary"
<SwitchPreferenceCompat app:title="@string/pref_sync_category"
app:defaultValue="@bool/pref_default_notification_upcoming_lessons_enable" app:fragment="io.github.wulkanowy.ui.modules.settings.sync.SyncFragment" />
app:iconSpaceReserved="false" <Preference
app:key="@string/pref_key_notifications_upcoming_lessons_enable" app:key="advanced"
app:singleLineTitle="false" app:icon="@drawable/ic_settings_advanced"
app:title="@string/pref_notify_upcoming_lessons_switch" /> app:summary="@string/pref_advanced_category_summary"
<SwitchPreferenceCompat app:title="@string/pref_advanced_category"
app:defaultValue="@bool/pref_default_notification_debug" app:fragment="io.github.wulkanowy.ui.modules.settings.advanced.AdvancedFragment" />
app:iconSpaceReserved="false" <Preference
app:key="@string/pref_key_notification_debug" app:key="about"
app:singleLineTitle="false" app:icon="@drawable/ic_all_about"
app:title="@string/pref_notify_debug_switch" /> app:summary="@string/pref_about_category_summary"
</PreferenceCategory> app:title="@string/about_title"
<PreferenceCategory app:fragment="io.github.wulkanowy.ui.modules.about.AboutFragment" />
app:iconSpaceReserved="false"
app:title="@string/pref_other_header">
<ListPreference
app:defaultValue="@string/pref_default_grade_modifier_plus"
app:entries="@array/grade_modifier_entries"
app:entryValues="@array/grade_modifier_value"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_modifier_plus"
app:title="@string/pref_other_grade_modifier_plus"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_grade_modifier_minus"
app:entries="@array/grade_modifier_entries"
app:entryValues="@array/grade_modifier_value"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_modifier_minus"
app:title="@string/pref_other_grade_modifier_minus"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_grade_average_mode"
app:entries="@array/grade_average_mode_entries"
app:entryValues="@array/grade_average_mode_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_average_mode"
app:title="@string/pref_view_grade_average_mode"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_grade_average_force_calc"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_average_force_calc"
app:singleLineTitle="false"
app:title="@string/pref_view_grade_average_force_calc" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_fill_message_content"
app:iconSpaceReserved="false"
app:key="@string/pref_key_fill_message_content"
app:singleLineTitle="false"
app:title="@string/pref_other_fill_message_content" />
</PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_grades_advanced_header">
<ListPreference
app:defaultValue="@string/pref_default_grade_modifier_plus"
app:entries="@array/grade_modifier_entries"
app:entryValues="@array/grade_modifier_value"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_modifier_plus"
app:title="@string/pref_other_grade_modifier_plus"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_grade_modifier_minus"
app:entries="@array/grade_modifier_entries"
app:entryValues="@array/grade_modifier_value"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_modifier_minus"
app:title="@string/pref_other_grade_modifier_minus"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_grade_average_force_calc"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_average_force_calc"
app:singleLineTitle="false"
app:title="@string/pref_view_grade_average_force_calc" />
<ListPreference
app:defaultValue="@string/pref_default_grade_average_mode"
app:entries="@array/grade_average_mode_entries"
app:entryValues="@array/grade_average_mode_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_average_mode"
app:title="@string/pref_view_grade_average_mode"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_messages_advanced_header">
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_fill_message_content"
app:iconSpaceReserved="false"
app:key="@string/pref_key_fill_message_content"
app:singleLineTitle="false"
app:title="@string/pref_other_fill_message_content" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_view_header">
<ListPreference
app:defaultValue="@string/pref_default_app_language"
app:entries="@array/app_language_entries"
app:entryValues="@array/app_language_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_app_language"
app:title="@string/pref_view_app_language"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_app_theme"
app:entries="@array/app_theme_entries"
app:entryValues="@array/app_theme_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_app_theme"
app:title="@string/pref_view_app_theme"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_startup"
app:entries="@array/startup_tab_entries"
app:entryValues="@array/startup_tab_value"
app:iconSpaceReserved="false"
app:key="@string/pref_key_start_menu"
app:title="@string/pref_view_list"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_grades_appearance_header">
<ListPreference
app:defaultValue="@string/pref_default_grade_color_scheme"
app:entries="@array/grade_color_scheme_entries"
app:entryValues="@array/grade_color_scheme_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_color_scheme"
app:title="@string/pref_view_grade_color_scheme"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_expand_grade"
app:iconSpaceReserved="false"
app:key="@string/pref_key_expand_grade"
app:title="@string/pref_view_expand_grade" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_subjects_without_grades"
app:iconSpaceReserved="false"
app:key="@string/pref_key_subjects_without_grades"
app:singleLineTitle="false"
app:title="@string/pref_view_subjects_without_grades" />
<ListPreference
app:defaultValue="@string/pref_default_grade_sorting_mode"
app:entries="@array/grade_sorting_mode_entries"
app:entryValues="@array/grade_sorting_mode_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_sorting_mode"
app:title="@string/pref_view_grade_sorting_mode"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_grade_statistics_list"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_statistics_list"
app:singleLineTitle="false"
app:title="@string/pref_view_grade_statistics_list" />
</PreferenceCategory>
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_attendance_appearance_view">
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_attendance_present"
app:iconSpaceReserved="false"
app:key="@string/pref_key_attendance_present"
app:title="@string/pref_view_present" />
</PreferenceCategory>
<PreferenceCategory
android:layout_height="wrap_content"
app:iconSpaceReserved="false"
app:title="@string/pref_timetable_appearance_view">
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_timetable_show_timers"
app:iconSpaceReserved="false"
app:key="@string/pref_key_timetable_show_timers"
app:title="@string/pref_view_timetable_show_timers" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_timetable_show_groups"
app:iconSpaceReserved="false"
app:key="@string/pref_key_timetable_show_groups"
app:singleLineTitle="false"
app:title="@string/pref_view_timetable_show_groups" />
<!--Hidden due to not functional hybrid/mobile api modes
<ListPreference
app:defaultValue="@string/pref_default_timetable_show_whole_class"
app:entries="@array/timetable_show_whole_class_entries"
app:entryValues="@array/timetable_show_whole_class_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_timetable_show_whole_class"
app:title="@string/pref_view_timetable_show_whole_class"
app:useSimpleSummaryProvider="true" />
-->
</PreferenceCategory>
</PreferenceScreen>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_notify_header">
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_notifications_enable"
app:iconSpaceReserved="false"
app:key="@string/pref_key_notifications_enable"
app:title="@string/pref_notify_switch" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_notification_upcoming_lessons_enable"
app:iconSpaceReserved="false"
app:key="@string/pref_key_notifications_upcoming_lessons_enable"
app:singleLineTitle="false"
app:title="@string/pref_notify_upcoming_lessons_switch" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_notification_debug"
app:iconSpaceReserved="false"
app:key="@string/pref_key_notification_debug"
app:singleLineTitle="false"
app:title="@string/pref_notify_debug_switch" />
<Preference
app:iconSpaceReserved="false"
app:isPreferenceVisible="false"
app:key="@string/pref_key_notifications_fix_issues"
app:title="@string/pref_notify_fix_sync_issues" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref_services_header">
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_services_enable"
app:iconSpaceReserved="false"
app:key="@string/pref_key_services_enable"
app:title="@string/pref_services_switch" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_services_wifi_only"
app:dependency="services_enable"
app:iconSpaceReserved="false"
app:key="@string/pref_key_services_wifi_only"
app:title="@string/pref_services_wifi" />
<ListPreference
app:defaultValue="@string/pref_default_services_interval"
app:dependency="services_enable"
app:entries="@array/services_interval_entries"
app:entryValues="@array/services_interval_value"
app:iconSpaceReserved="false"
app:key="@string/pref_key_services_interval"
app:title="@string/pref_services_interval"
app:useSimpleSummaryProvider="true" />
<Preference
app:iconSpaceReserved="false"
app:key="@string/pref_key_services_force_sync"
app:title="@string/pref_services_force_sync" />
</PreferenceCategory>
</PreferenceScreen>