From 208d097986ab858970de08573ce3456f2960ff26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 22 Mar 2021 21:01:04 +0100 Subject: [PATCH] [UI] Add new Settings fragment. --- app/build.gradle | 4 +- .../pl/szczodrzynski/edziennik/Extensions.kt | 38 ++++ .../szczodrzynski/edziennik/MainActivity.kt | 9 +- .../ui/dialogs/bell/BellSyncConfigDialog.kt | 117 ++++++++++ .../ui/dialogs/event/EventManualDialog.kt | 32 +-- .../ui/dialogs/grade/GradeDetailsDialog.kt | 1 - .../{settings => grade}/GradesConfigDialog.kt | 2 +- .../ui/dialogs/settings/AppLanguageDialog.kt | 71 +++++++ .../dialogs/settings/MiniMenuConfigDialog.kt | 96 +++++++++ .../ui/dialogs/settings/ThemeChooserDialog.kt | 65 ++++++ .../ui/dialogs/sync/QuietHoursConfigDialog.kt | 107 ++++++++++ .../dialogs/sync/RegistrationConfigDialog.kt | 147 +++++++++++++ .../dialogs/sync/RegistrationEnableDialog.kt | 89 -------- .../ui/dialogs/sync/SyncIntervalDialog.kt | 77 +++++++ .../ui/modules/grades/GradesListFragment.kt | 2 +- .../grades/viewholder/StatsViewHolder.kt | 2 +- .../settings/MaterialAboutProfileItem.kt | 40 ++++ .../ui/modules/settings/SettingsCard.kt | 28 +++ .../ui/modules/settings/SettingsFragment.kt | 62 ++++++ .../modules/settings/SettingsNewFragment.java | 22 +- .../ui/modules/settings/SettingsUtil.kt | 188 ++++++++++++++++ .../settings/SettingsViewTypeManager.kt | 46 ++++ .../settings/cards/SettingsAboutCard.kt | 150 +++++++++++++ .../settings/cards/SettingsProfileCard.kt | 59 ++++++ .../settings/cards/SettingsRegisterCard.kt | 152 +++++++++++++ .../settings/cards/SettingsSyncCard.kt | 200 ++++++++++++++++++ .../settings/cards/SettingsThemeCard.kt | 96 +++++++++ .../szczodrzynski/edziennik/utils/Themes.kt | 41 ++-- app/src/main/res/layout/dialog_edit_text.xml | 32 +++ .../mal_material_about_profile_item.xml | 48 +++++ app/src/main/res/values-de/strings.xml | 22 +- app/src/main/res/values-en/strings.xml | 24 ++- app/src/main/res/values/strings.xml | 28 ++- 33 files changed, 1920 insertions(+), 177 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt rename app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/{settings => grade}/GradesConfigDialog.kt (99%) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt create mode 100644 app/src/main/res/layout/dialog_edit_text.xml create mode 100644 app/src/main/res/layout/mal_material_about_profile_item.xml diff --git a/app/build.gradle b/app/build.gradle index 0e83e107..1766c3bf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -115,7 +115,7 @@ dependencies { implementation "eu.szkolny:agendacalendarview:1799f8ef47" implementation "eu.szkolny:cafebar:5bf0c618de" implementation "eu.szkolny.fslogin:lib:2.0.0" - implementation "eu.szkolny:material-about-library:0534abf316" + implementation "eu.szkolny:material-about-library:fe4a5cd6f1" implementation "eu.szkolny:mhttp:af4b62e6e9" implementation "eu.szkolny:nachos:0e5dfcaceb" implementation "eu.szkolny.selective-dao:annotation:27f8f3f194" @@ -129,7 +129,7 @@ dependencies { implementation "com.mikepenz:iconics-core:5.2.8" implementation "com.mikepenz:iconics-views:5.2.8" implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar" - implementation "eu.szkolny:szkolny-font:1dab7d64ed" + implementation "eu.szkolny:szkolny-font:1.2" // Other dependencies implementation "cat.ereza:customactivityoncrash:2.3.0" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt index 71febada..aaf0eec7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt @@ -1278,3 +1278,41 @@ operator fun Iterable>.get(key: K): V? { } fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) } + +fun MutableList.after(what: E, insert: E) { + val index = indexOf(what) + if (index != -1) + add(index + 1, insert) +} + +fun MutableList.before(what: E, insert: E) { + val index = indexOf(what) + if (index != -1) + add(index, insert) +} + +fun MutableList.after(what: E, insert: Collection) { + val index = indexOf(what) + if (index != -1) + addAll(index + 1, insert) +} + +fun MutableList.before(what: E, insert: Collection) { + val index = indexOf(what) + if (index != -1) + addAll(index, insert) +} + +fun Context.getSyncInterval(interval: Int): String { + val hours = interval / 60 / 60 + val minutes = interval / 60 % 60 + val hoursText = if (hours > 0) + plural(R.plurals.time_till_hours, hours) + else + null + val minutesText = if (minutes > 0) + plural(R.plurals.time_till_minutes, minutes) + else + "" + return hoursText?.plus(" $minutesText") ?: minutesText +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index de9b5f85..10caf080 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -79,6 +79,7 @@ import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment import pl.szczodrzynski.edziennik.ui.modules.messages.compose.MessagesComposeFragment import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsFragment import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushFragment @@ -199,12 +200,18 @@ class MainActivity : AppCompatActivity(), CoroutineScope { .isStatic(true) .isBelowSeparator(true) - list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class) + list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsFragment::class) .withIcon(CommunityMaterial.Icon.cmd_cog_outline) .isInDrawer(true) .isStatic(true) .isBelowSeparator(true) + list += NavTarget(DRAWER_ITEM_SETTINGS+1, R.string.menu_settings, SettingsNewFragment::class) + .withIcon(CommunityMaterial.Icon3.cmd_seal) + .isInDrawer(true) + .isStatic(true) + .isBelowSeparator(true) + // profile settings items list += NavTarget(DRAWER_PROFILE_ADD_NEW, R.string.menu_add_new_profile, null) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt new file mode 100644 index 00000000..13dcb6f9 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/bell/BellSyncConfigDialog.kt @@ -0,0 +1,117 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-20. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.bell + +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.core.widget.addTextChangedListener +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.textfield.TextInputLayout +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.utils.models.Time +import kotlin.coroutines.CoroutineContext + +class BellSyncConfigDialog( + val activity: AppCompatActivity, + val onChangeListener: (() -> Unit)? = null, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "BellSyncConfigDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + private fun parse(input: String): Pair? { + if (input.length < 8) { + return null + } + if (input[2] != ':' || input[5] != ':') { + return null + } + val multiplier = when { + input[0] == '+' -> 1 + input[0] == '-' -> -1 + else -> return null + } + val time = Time.fromH_m_s("0" + input.substring(1)) + + return time to multiplier + } + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.bell_sync_title) + .setView(R.layout.dialog_edit_text) + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.cancel, null) + .setNeutralButton(R.string.reset) { _, _ -> + app.config.timetable.bellSyncDiff = null + app.config.timetable.bellSyncMultiplier = 0 + onChangeListener?.invoke() + } + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + + val message = dialog.findViewById(android.R.id.title) + val editText = dialog.findViewById(android.R.id.text1) + val textLayout = dialog.findViewById(R.id.text_input_layout) + + message?.setText(R.string.bell_sync_adjust_content) + editText?.hint = "±H:MM:SS" + editText?.setText(app.config.timetable.bellSyncDiff?.let { + (if (app.config.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS + } ?: "+0:00:00") + editText?.addTextChangedListener { text -> + val input = text?.toString() + textLayout?.error = + if (input != null && parse(input) == null) + activity.getString(R.string.bell_sync_adjust_error) + else + null + } + + dialog.getButton(AlertDialog.BUTTON_POSITIVE)?.onClick { + val input = editText?.text?.toString() ?: return@onClick + val parsed = parse(input) + if (parsed == null) { + Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show() + return@onClick + } + + val (time, multiplier) = parsed + app.config.timetable.bellSyncDiff = + if (time.value == 0) + null + else + time + app.config.timetable.bellSyncMultiplier = multiplier + + onChangeListener?.invoke() + dialog.dismiss() + } + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt index 7240934b..db5a2b09 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt @@ -33,7 +33,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding -import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationEnableDialog +import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog import pl.szczodrzynski.edziennik.ui.modules.views.TimeDropdown.Companion.DISPLAY_LESSONS import pl.szczodrzynski.edziennik.utils.Anim import pl.szczodrzynski.edziennik.utils.TextInputDropDown @@ -64,7 +64,7 @@ class EventManualDialog( private val app by lazy { activity.application as App } private lateinit var b: DialogEventManualV2Binding private lateinit var dialog: AlertDialog - private var profile: Profile? = null + private lateinit var profile: Profile private var customColor: Int? = null private val editingShared = editingEvent?.sharedBy != null @@ -80,9 +80,9 @@ class EventManualDialog( private var progressDialog: AlertDialog? = null - init { run { + init { launch { if (activity.isFinishing) - return@run + return@launch onShowListener?.invoke(TAG) EventBus.getDefault().register(this) b = DialogEventManualV2Binding.inflate(activity.layoutInflater) @@ -236,8 +236,15 @@ class EventManualDialog( progressDialog?.dismiss() } - private fun loadLists() { launch { - profile = withContext(Dispatchers.Default) { app.db.profileDao().getByIdNow(profileId) } + private fun loadLists() = launch { + val profile = withContext(Dispatchers.Default) { + app.db.profileDao().getByIdNow(profileId) + } + if (profile == null) { + Toast.makeText(activity, R.string.event_manual_no_profile, Toast.LENGTH_SHORT).show() + return@launch + } + this@EventManualDialog.profile = profile with (b.dateDropdown) { db = app.db @@ -380,7 +387,7 @@ class EventManualDialog( }) colorPickerDialog.show(activity.supportFragmentManager, "color-picker-dialog") } - }} + } private fun showRemoveEventDialog() { val shareNotice = when { @@ -417,12 +424,11 @@ class EventManualDialog( val share = b.shareSwitch.isChecked - if (share && profile?.registration != Profile.REGISTRATION_ENABLED) { - RegistrationEnableDialog(activity, profileId).showEventShareDialog { - if (it != null) - profile = it - saveEvent() - } + if (share && profile.registration != Profile.REGISTRATION_ENABLED) { + RegistrationConfigDialog(activity, profile, onChangeListener = { enabled -> + if (enabled) + saveEvent() + }).showEventShareDialog() return } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt index 4877413f..5b9579ed 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt @@ -13,7 +13,6 @@ import pl.szczodrzynski.edziennik.data.db.full.GradeFull import pl.szczodrzynski.edziennik.databinding.DialogGradeDetailsBinding import pl.szczodrzynski.edziennik.onClick import pl.szczodrzynski.edziennik.setTintColor -import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration import kotlin.coroutines.CoroutineContext diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradesConfigDialog.kt similarity index 99% rename from app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt rename to app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradesConfigDialog.kt index e74f3577..20325447 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradesConfigDialog.kt @@ -2,7 +2,7 @@ * Copyright (c) Kacper Ziubryniewicz 2020-1-16 */ -package pl.szczodrzynski.edziennik.ui.dialogs.settings +package pl.szczodrzynski.edziennik.ui.dialogs.grade import android.annotation.SuppressLint import androidx.appcompat.app.AlertDialog diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt new file mode 100644 index 00000000..6db33e70 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-19. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.settings + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.* +import kotlin.coroutines.CoroutineContext + +class AppLanguageDialog( + val activity: AppCompatActivity, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "AppLanguageDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + val languages = mapOf( + null to R.string.language_system, + "pl" to R.string.language_polish, + "en" to R.string.language_english, + "de" to R.string.language_german + ) + val languageIds = languages.map { it.key } + val languageNames = languages.map { + activity.getString(it.value) + } + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.app_language_dialog_title) + //.setMessage(R.string.settings_about_language_dialog_text) + .setSingleChoiceItems( + languageNames.toTypedArray(), + languageIds.indexOf(app.config.ui.language), + null + ) + .setPositiveButton(R.string.ok) { _, _ -> + val which = dialog.listView.checkedItemPosition + + app.config.ui.language = languageIds[which] + activity.recreate() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt new file mode 100644 index 00000000..61e95a8b --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt @@ -0,0 +1,96 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.settings + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_NOTIFICATIONS +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_SETTINGS +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE +import pl.szczodrzynski.edziennik.R +import kotlin.coroutines.CoroutineContext + +class MiniMenuConfigDialog( + val activity: AppCompatActivity, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "MiniMenuConfigDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + val buttons = mapOf( + DRAWER_ITEM_HOME to R.string.menu_home_page, + DRAWER_ITEM_TIMETABLE to R.string.menu_timetable, + DRAWER_ITEM_AGENDA to R.string.menu_agenda, + DRAWER_ITEM_GRADES to R.string.menu_grades, + DRAWER_ITEM_MESSAGES to R.string.menu_messages, + DRAWER_ITEM_HOMEWORK to R.string.menu_homework, + DRAWER_ITEM_BEHAVIOUR to R.string.menu_notices, + DRAWER_ITEM_ATTENDANCE to R.string.menu_attendance, + DRAWER_ITEM_ANNOUNCEMENTS to R.string.menu_announcements, + DRAWER_ITEM_NOTIFICATIONS to R.string.menu_notifications, + DRAWER_ITEM_SETTINGS to R.string.menu_settings + ) + val miniMenuButtons = app.config.ui.miniMenuButtons + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.settings_theme_mini_drawer_buttons_dialog_title) + //.setMessage(R.string.settings_theme_mini_drawer_buttons_dialog_text) + .setMultiChoiceItems( + buttons.map { activity.getString(it.value) }.toTypedArray(), + buttons.map { it.key in miniMenuButtons }.toBooleanArray(), + null + ) + .setPositiveButton(R.string.ok) { _, _ -> + app.config.ui.miniMenuButtons = + buttons.keys.mapIndexedNotNull { index, id -> + if (dialog.listView.checkedItemPositions[index]) + id + else + null + } + + if (activity is MainActivity) { + activity.setDrawerItems() + activity.drawer.updateBadges() + } + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt new file mode 100644 index 00000000..ca9b2f11 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.settings + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.utils.Themes +import kotlin.coroutines.CoroutineContext + +class ThemeChooserDialog( + val activity: AppCompatActivity, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "ThemeChooserDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.settings_theme_theme_text) + .setSingleChoiceItems( + Themes.getThemeNames(activity).toTypedArray(), + Themes.themeIndex, + null + ) + .setPositiveButton(R.string.ok) { _, _ -> + val which = dialog.listView.checkedItemPosition + + val theme = Themes.themeList[which] + if (app.config.ui.theme == theme.id) + return@setPositiveButton + app.config.ui.theme = theme.id + Themes.themeIndex = which + activity.recreate() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt new file mode 100644 index 00000000..5c933e20 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/QuietHoursConfigDialog.kt @@ -0,0 +1,107 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-20. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.sync + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.timepicker.MaterialTimePicker +import com.google.android.material.timepicker.TimeFormat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.utils.models.Time +import kotlin.coroutines.CoroutineContext + +class QuietHoursConfigDialog( + val activity: AppCompatActivity, + val onChangeListener: (() -> Unit)? = null, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "QuietHoursConfigDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.settings_sync_quiet_hours_dialog_title) + .setItems(arrayOf( + activity.getString(R.string.settings_sync_quiet_hours_set_beginning), + activity.getString(R.string.settings_sync_quiet_hours_set_end) + )) { dialog, which -> + when (which) { + 0 -> configStartTime() + 1 -> configEndTime() + } + dialog.dismiss() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} + + private fun configStartTime() { + onShowListener?.invoke(TAG + "Start") + + val time = app.config.sync.quietHoursStart ?: return + val picker = MaterialTimePicker.Builder() + .setTitleText(R.string.settings_sync_quiet_hours_set_beginning) + .setTimeFormat(TimeFormat.CLOCK_24H) + .setHour(time.hour) + .setMinute(time.minute) + .build() + + picker.show(activity.supportFragmentManager, TAG) + picker.addOnPositiveButtonClickListener { + app.config.sync.quietHoursEnabled = true + app.config.sync.quietHoursStart = Time(picker.hour, picker.minute, 0) + onChangeListener?.invoke() + } + picker.addOnDismissListener { + onDismissListener?.invoke(TAG + "Start") + } + } + + private fun configEndTime() { + onShowListener?.invoke(TAG + "End") + + val time = app.config.sync.quietHoursEnd ?: return + val picker = MaterialTimePicker.Builder() + .setTitleText(R.string.settings_sync_quiet_hours_set_end) + .setTimeFormat(TimeFormat.CLOCK_24H) + .setHour(time.hour) + .setMinute(time.minute) + .build() + + picker.show(activity.supportFragmentManager, TAG) + picker.addOnPositiveButtonClickListener { + app.config.sync.quietHoursEnabled = true + app.config.sync.quietHoursEnd = Time(picker.hour, picker.minute, 0) + onChangeListener?.invoke() + } + picker.addOnDismissListener { + onDismissListener?.invoke(TAG + "End") + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt new file mode 100644 index 00000000..9470534d --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationConfigDialog.kt @@ -0,0 +1,147 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-15. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.sync + +import android.text.Html +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.* +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi +import pl.szczodrzynski.edziennik.data.api.task.AppSync +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import kotlin.coroutines.CoroutineContext + +class RegistrationConfigDialog( + val activity: AppCompatActivity, + val profile: Profile, + val onChangeListener: ((enabled: Boolean) -> Unit)? = null, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "RegistrationEnableDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + app = activity.applicationContext as App + }} + + fun showEventShareDialog() { + onShowListener?.invoke(TAG + "EventShare") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.registration_config_event_sharing_title) + .setMessage(R.string.registration_config_event_sharing_text) + .setPositiveButton(R.string.i_agree) { _, _ -> + enableRegistration() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "EventShare") + } + .show() + } + + fun showEnableDialog() { + onShowListener?.invoke(TAG + "Enable") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.registration_config_title) + .setMessage(Html.fromHtml(app.getString(R.string.registration_config_enable_text))) + .setPositiveButton(R.string.i_agree) { _, _ -> + enableRegistration() + } + .setNegativeButton(R.string.i_disagree, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "Enable") + } + .show() + } + + fun showDisableDialog() { + onShowListener?.invoke(TAG + "Disable") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.registration_config_title) + .setMessage(Html.fromHtml(app.getString(R.string.registration_config_disable_text))) + .setPositiveButton(R.string.ok) { _, _ -> + disableRegistration() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "Disable") + } + .show() + } + + private fun enableRegistration() = launch { + onShowListener?.invoke(TAG + "Enabling") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.please_wait) + .setMessage(R.string.registration_config_enable_progress_text) + .setCancelable(false) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "Enabling") + } + .show() + + withContext(Dispatchers.Default) { + profile.registration = Profile.REGISTRATION_ENABLED + + // force full registration of the user + App.config.getFor(profile.id).hash = "" + + AppSync(app, mutableListOf(), listOf(profile), SzkolnyApi(app)).run( + 0L, + markAsSeen = true + ) + app.db.profileDao().add(profile) + if (profile.id == App.profileId) { + App.profile.registration = profile.registration + } + } + + dialog.dismiss() + onChangeListener?.invoke(true) + } + + private fun disableRegistration() = launch { + onShowListener?.invoke(TAG + "Disabling") + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.please_wait) + .setMessage(R.string.registration_config_disable_progress_text) + .setCancelable(false) + .setOnDismissListener { + onDismissListener?.invoke(TAG + "Disabling") + } + .show() + + withContext(Dispatchers.Default) { + profile.registration = Profile.REGISTRATION_DISABLED + + SzkolnyApi(app).runCatching(activity) { + unregisterAppUser(profile.userCode) + } + app.db.profileDao().add(profile) + if (profile.id == App.profileId) { + App.profile.registration = profile.registration + } + } + + dialog.dismiss() + onChangeListener?.invoke(false) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt deleted file mode 100644 index 7fc0caf3..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/RegistrationEnableDialog.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2020-3-15. - */ - -package pl.szczodrzynski.edziennik.ui.dialogs.sync - -import android.text.Html -import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlinx.coroutines.* -import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi -import pl.szczodrzynski.edziennik.data.api.task.AppSync -import pl.szczodrzynski.edziennik.data.db.entity.Profile -import kotlin.coroutines.CoroutineContext - -class RegistrationEnableDialog( - val activity: AppCompatActivity, - val profileId: Int -) : CoroutineScope { - companion object { - private const val TAG = "RegistrationEnableDialog" - } - - private lateinit var app: App - - private val job = Job() - override val coroutineContext: CoroutineContext - get() = job + Dispatchers.Main - - // local variables go here - private var progressDialog: AlertDialog? = null - - init { run { - if (activity.isFinishing) - return@run - app = activity.applicationContext as App - }} - - fun showEventShareDialog(onSuccess: (profile: Profile?) -> Unit) { - MaterialAlertDialogBuilder(activity) - .setTitle(R.string.event_manual_need_registration_title) - .setMessage(R.string.event_manual_need_registration_text) - .setPositiveButton(R.string.ok) { dialog, which -> - enableRegistration(onSuccess) - } - .setNegativeButton(R.string.cancel, null) - .show() - } - - fun showEnableDialog(onSuccess: (profile: Profile?) -> Unit) { - MaterialAlertDialogBuilder(activity) - .setTitle(R.string.registration_enable_dialog_title) - .setMessage(Html.fromHtml(app.getString(R.string.registration_enable_dialog_text))) - .setPositiveButton(R.string.ok) { dialog, which -> - enableRegistration(onSuccess) - } - .setNegativeButton(R.string.cancel, null) - .show() - } - - private fun enableRegistration(onSuccess: (profile: Profile?) -> Unit) { launch { - progressDialog = MaterialAlertDialogBuilder(activity) - .setTitle(R.string.please_wait) - .setMessage(R.string.registration_enable_progress_text) - .setCancelable(false) - .show() - - val profile = withContext(Dispatchers.Default) { - val profile = app.db.profileDao().getByIdNow(profileId) ?: return@withContext null - profile.registration = Profile.REGISTRATION_ENABLED - - // force full registration of the user - App.config.getFor(profile.id).hash = "" - - AppSync(app, mutableListOf(), listOf(profile), SzkolnyApi(app)).run(0L, markAsSeen = true) - app.db.profileDao().add(profile) - if (profile.id == App.profileId) { - App.profile.registration = profile.registration - } - return@withContext profile - } - - progressDialog?.dismiss() - onSuccess(profile) - }} -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt new file mode 100644 index 00000000..6f4f027b --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncIntervalDialog.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-20. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.sync + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.* +import kotlin.coroutines.CoroutineContext + +class SyncIntervalDialog( + val activity: AppCompatActivity, + val onChangeListener: (() -> Unit)? = null, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "SyncIntervalDialog" + } + + private lateinit var app: App + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + + val intervals = listOf( + 30 * MINUTE, + 45 * MINUTE, + 60 * MINUTE, + 90 * MINUTE, + 2 * HOUR, + 3 * HOUR, + 4 * HOUR, + 6 * HOUR, + 10 * HOUR + ) + val intervalNames = intervals.map { + activity.getSyncInterval(it.toInt()) + } + + dialog = MaterialAlertDialogBuilder(activity) + .setTitle(R.string.settings_sync_sync_interval_dialog_title) + //.setMessage(R.string.settings_sync_sync_interval_dialog_text) + .setSingleChoiceItems( + intervalNames.toTypedArray(), + intervals.indexOf(app.config.sync.interval.toLong()), + null + ) + .setPositiveButton(R.string.ok) { _, _ -> + val which = dialog.listView.checkedItemPosition + + val interval = intervals[which] + app.config.sync.interval = interval.toInt() + onChangeListener?.invoke() + } + .setNegativeButton(R.string.cancel, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt index eb7fdcb1..63521e97 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListFragment.kt @@ -23,7 +23,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_GRADE import pl.szczodrzynski.edziennik.data.db.full.GradeFull import pl.szczodrzynski.edziennik.databinding.GradesListFragmentBinding import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradeDetailsDialog -import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesAverages import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesSemester import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt index de1b071f..532ade84 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt @@ -15,7 +15,7 @@ import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.databinding.GradesItemStatsBinding import pl.szczodrzynski.edziennik.onClick -import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats import java.text.DecimalFormat diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt new file mode 100644 index 00000000..dfff3246 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/MaterialAboutProfileItem.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-17. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import android.content.Context +import android.view.View +import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder +import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem + +class MaterialAboutProfileItem(item: MaterialAboutTitleItem) : MaterialAboutTitleItem(item) { + companion object { + fun getViewHolder(view: View): MaterialAboutItemViewHolder = + MaterialAboutTitleItem.getViewHolder(view) + + fun setupItem( + holder: MaterialAboutTitleItemViewHolder, + item: MaterialAboutProfileItem, + context: Context + ) = MaterialAboutTitleItem.setupItem(holder, item, context) + } + + override fun getType(): Int { + return SettingsViewTypeManager.ItemType.PROFILE_ITEM + } + + override fun getDetailString() = "MaterialAboutProfileItem{" + + "text=" + text + + ", textRes=" + textRes + + ", desc=" + desc + + ", descRes=" + descRes + + ", icon=" + icon + + ", iconRes=" + iconRes + + ", onClickAction=" + onClickAction + + ", onLongClickAction=" + onLongClickAction + + '}' + + override fun clone() = MaterialAboutProfileItem(this) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt new file mode 100644 index 00000000..c31116d9 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsCard.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-17. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import com.danielstone.materialaboutlibrary.items.MaterialAboutItem +import com.danielstone.materialaboutlibrary.model.MaterialAboutCard +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity + +abstract class SettingsCard( + protected val util: SettingsUtil, +) { + protected val app: App = util.activity.application as App + protected val activity: MainActivity = util.activity + + protected val configGlobal by lazy { app.config } + protected val configProfile by lazy { app.config.forProfile() } + + val card by lazy { + buildCard() + } + + protected abstract fun buildCard(): MaterialAboutCard + protected abstract fun getItems(): List + protected abstract fun getItemsMore(): List +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt new file mode 100644 index 00000000..cf7fa625 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsFragment.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-16. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.danielstone.materialaboutlibrary.MaterialAboutFragment +import com.danielstone.materialaboutlibrary.model.MaterialAboutList +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.ui.modules.settings.cards.* +import kotlin.coroutines.CoroutineContext + +class SettingsFragment : MaterialAboutFragment(), CoroutineScope { + companion object { + private const val TAG = "SettingsFragment" + } + + private lateinit var app: App + private lateinit var activity: MainActivity + + private val job: Job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + private val util by lazy { + SettingsUtil(activity) { + refreshMaterialAboutList() + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + activity = (getActivity() as MainActivity?) ?: return null + app = activity.application as App + return super.onCreateView(inflater, container, savedInstanceState) + } + + override fun getViewTypeManager() = + SettingsViewTypeManager() + + override fun getMaterialAboutList(activityContext: Context?): MaterialAboutList { + return MaterialAboutList( + SettingsProfileCard(util).card, + SettingsThemeCard(util).card, + SettingsSyncCard(util).card, + SettingsRegisterCard(util).card, + SettingsAboutCard(util).card, + ) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index d009cdf1..80aee4dd 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -53,8 +53,8 @@ import pl.szczodrzynski.edziennik.network.NetworkUtils; import pl.szczodrzynski.edziennik.sync.SyncWorker; import pl.szczodrzynski.edziennik.sync.UpdateWorker; import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog; +import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog; import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog; -import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog; import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog; import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog; import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity; @@ -641,6 +641,9 @@ public class SettingsNewFragment extends MaterialAboutFragment { Time time = app.getConfig().getSync().getQuietHoursStart(); if (time == null) time = new Time(22, 30, 0); + Time timeEnd = app.getConfig().getSync().getQuietHoursEnd(); + if (timeEnd == null) + app.getConfig().getSync().setQuietHoursEnd(new Time(5, 30, 0)); TimePickerDialog.newInstance((v2, hourOfDay, minute, second) -> { app.getConfig().getSync().setQuietHoursEnabled(true); app.getConfig().getSync().setQuietHoursStart(new Time(hourOfDay, minute, second)); @@ -654,6 +657,9 @@ public class SettingsNewFragment extends MaterialAboutFragment { Time time = app.getConfig().getSync().getQuietHoursEnd(); if (time == null) time = new Time(5, 30, 0); + Time timeStart = app.getConfig().getSync().getQuietHoursStart(); + if (timeStart == null) + app.getConfig().getSync().setQuietHoursStart(new Time(22, 30, 0)); TimePickerDialog.newInstance((v2, hourOfDay, minute, second) -> { app.getConfig().getSync().setQuietHoursEnabled(true); app.getConfig().getSync().setQuietHoursEnd(new Time(hourOfDay, minute, second)); @@ -847,7 +853,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { registerCardAllowRegistrationItem.setChecked(true); app.getProfile().setRegistration(REGISTRATION_ENABLED); app.profileSave(); - addCardItem(CARD_REGISTER, 2, getRegisterCardSharedEventsItem()); + addCardItem(CARD_REGISTER, 3, getRegisterCardSharedEventsItem()); refreshMaterialAboutList(); })) .show(); @@ -860,7 +866,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { registerCardAllowRegistrationItem.setChecked(false); app.getProfile().setRegistration(REGISTRATION_DISABLED); app.profileSave(); - removeCardItem(CARD_REGISTER, 2); + removeCardItem(CARD_REGISTER, 3); refreshMaterialAboutList(); MaterialDialog progressDialog = new MaterialDialog.Builder(activity) .title(getString(R.string.settings_register_allow_registration_dialog_disabling_title)) @@ -1058,8 +1064,8 @@ public class SettingsNewFragment extends MaterialAboutFragment { .icon(icon(CommunityMaterial.Icon3.cmd_translate, iconSizeDp, primaryTextOnPrimaryBg)) .setOnClickAction(() -> { new MaterialDialog.Builder(activity) - .title(getString(R.string.settings_about_language_dialog_title)) - .content(getString(R.string.settings_about_language_dialog_text)) + .title(getString(R.string.app_language_dialog_title)) + .content(getString(R.string.app_language_dialog_text)) .items(getString(R.string.language_system), getString(R.string.language_polish), getString(R.string.language_english), getString(R.string.language_german)) .itemsCallbackSingleChoice(app.getConfig().getUi().getLanguage() == null ? 0 : app.getConfig().getUi().getLanguage().equals("pl") ? 1 : app.getConfig().getUi().getLanguage().equals("en") ? 2 : 3, (dialog, itemView, which, text) -> { switch (which) { @@ -1168,9 +1174,9 @@ public class SettingsNewFragment extends MaterialAboutFragment { MaterialAboutList materialAboutList = new MaterialAboutList(); materialAboutList.addCard(getCardWithItems(null, getProfileCard(false))); - materialAboutList.addCard(getCardWithItems(getString(R.string.settings_theme_title_text), getThemeCard(false))); - materialAboutList.addCard(getCardWithItems(getString(R.string.settings_sync_title_text), getSyncCard(false))); - materialAboutList.addCard(getCardWithItems(getString(R.string.settings_about_register_title_text), getRegisterCard(false))); + materialAboutList.addCard(getCardWithItems(getString(R.string.settings_card_theme_title), getThemeCard(false))); + materialAboutList.addCard(getCardWithItems(getString(R.string.settings_card_sync_title), getSyncCard(false))); + materialAboutList.addCard(getCardWithItems(getString(R.string.settings_card_register_title), getRegisterCard(false))); //if (configurableEndpoints != null) // materialAboutList.addCard(getCardWithItems(getString(R.string.settings_sync_customize_title_text), getSyncCustomizeCard(false))); materialAboutList.addCard(getCardWithItems(null, getAboutCard(false), true)); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt new file mode 100644 index 00000000..5ed3fb5d --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsUtil.kt @@ -0,0 +1,188 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-17. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import androidx.core.graphics.drawable.toBitmap +import com.danielstone.materialaboutlibrary.items.* +import com.danielstone.materialaboutlibrary.model.MaterialAboutCard +import com.mikepenz.iconics.IconicsDrawable +import com.mikepenz.iconics.typeface.IIcon +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import com.mikepenz.iconics.utils.colorInt +import com.mikepenz.iconics.utils.sizeDp +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.after +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.utils.Colors +import pl.szczodrzynski.edziennik.utils.Themes + +class SettingsUtil( + val activity: MainActivity, + private val onRefresh: () -> Unit +) { + + fun refresh() = onRefresh() + + private fun IIcon.asDrawable(color: Int? = null, size: Int = 20) = IconicsDrawable(activity).apply { + icon = this@asDrawable + sizeDp = size + colorInt = color ?: Themes.getPrimaryTextColor(activity) + } + + fun createCard( + titleRes: Int?, + items: List, + itemsMore: List, + backgroundColor: Int? = null, + theme: Int? = null + ): MaterialAboutCard { + val card = MaterialAboutCard.Builder() + .title(titleRes ?: 0) + .cardColor(backgroundColor ?: 0) + .theme(theme ?: 0) + .build() + card.items.addAll(items) + + if (itemsMore.isNotEmpty()) { + card.items.add(createMoreItem(card, itemsMore)) + } + + return card + } + + fun createMoreItem( + card: MaterialAboutCard, + items: List + ): MaterialAboutActionItem { + val iconColor = card.cardColor.let { + if (it == 0) + null + else + Colors.legibleTextColor(it) + } + + val moreItem = MaterialAboutActionItem.Builder() + .text(R.string.settings_more_text) + .icon(CommunityMaterial.Icon.cmd_chevron_down.asDrawable(iconColor, size = 14)) + .build() + + moreItem.setOnClickAction { + card.items.after(moreItem, items) + card.items.remove(moreItem) + onRefresh() + } + + return moreItem + } + + fun createSectionItem(text: Int) = MaterialAboutSectionItem(text) + + fun createActionItem( + text: Int, + subText: Int? = null, + icon: IIcon, + backgroundColor: Int? = null, + onClick: (item: MaterialAboutActionItem) -> Unit + ): MaterialAboutActionItem { + val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) } + + val item = MaterialAboutActionItem.Builder() + .text(text) + .subText(subText ?: 0) + .icon(icon.asDrawable(iconColor)) + .build() + + item.setOnClickAction { + onClick(item) + } + + return item + } + + fun createPropertyItem( + text: Int, + subText: Int? = null, + subTextChecked: Int? = null, + icon: IIcon, + backgroundColor: Int? = null, + value: Boolean, + beforeChange: ((item: MaterialAboutSwitchItem, value: Boolean) -> Boolean)? = null, + onChange: (item: MaterialAboutSwitchItem, value: Boolean) -> Unit + ): MaterialAboutSwitchItem { + val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) } + + val item = MaterialAboutSwitchItem.Builder() + .text(text) + .subText(subText ?: 0) + .subTextChecked(subTextChecked ?: 0) + .icon(icon.asDrawable(iconColor)) + .setChecked(value) + .build() + + item.setOnCheckedChangedAction { item, isChecked -> + if (beforeChange?.invoke(item as MaterialAboutSwitchItem, isChecked) == false) + return@setOnCheckedChangedAction false + onChange(item as MaterialAboutSwitchItem, isChecked) + true + } + + return item + } + + fun createPropertyActionItem( + text: Int, + subText: Int? = null, + subTextChecked: Int? = null, + icon: IIcon, + backgroundColor: Int? = null, + value: Boolean, + onChange: (item: MaterialAboutActionSwitchItem, value: Boolean) -> Unit, + onClick: (item: MaterialAboutActionSwitchItem) -> Unit + ): MaterialAboutSwitchItem { + val iconColor = backgroundColor?.let { Colors.legibleTextColor(it) } + + val item = MaterialAboutActionSwitchItem.Builder() + .text(text) + .subText(subText ?: 0) + .subTextChecked(subTextChecked ?: 0) + .icon(icon.asDrawable(iconColor)) + .setChecked(value) + .build() + + item.setOnClickAction { + onClick(item) + } + item.setOnCheckedChangedAction { item, isChecked -> + onChange(item as MaterialAboutActionSwitchItem, isChecked) + true + } + + return item + } + + fun createTitleItem(): MaterialAboutTitleItem = + MaterialAboutTitleItem.Builder() + .text(R.string.app_name) + .desc(R.string.settings_about_title_subtext) + .icon(R.mipmap.ic_splash) + .build() + + fun createProfileItem(profile: Profile, onClick: (profile: Profile) -> Unit) = + MaterialAboutProfileItem( + MaterialAboutTitleItem.Builder() + .text(profile.name) + .desc(profile.subname) + .icon(RoundedBitmapDrawableFactory.create( + activity.resources, + profile.getImageDrawable(activity).toBitmap() + ).also { + it.isCircular = true + }) + .setOnClickAction { onClick(profile) } + .build() + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt new file mode 100644 index 00000000..1fb14fcd --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsViewTypeManager.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-17. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings + +import android.content.Context +import android.view.View +import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder +import com.danielstone.materialaboutlibrary.items.MaterialAboutItem +import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem.MaterialAboutTitleItemViewHolder +import com.danielstone.materialaboutlibrary.util.DefaultViewTypeManager +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsViewTypeManager.ItemType.Companion.PROFILE_ITEM + +class SettingsViewTypeManager : DefaultViewTypeManager() { + class ItemType { + companion object { + const val PROFILE_ITEM = 10 + } + } + + override fun getLayout(itemType: Int) = when (itemType) { + PROFILE_ITEM -> R.layout.mal_material_about_profile_item + else -> super.getLayout(itemType) + } + + override fun getViewHolder(itemType: Int, view: View): MaterialAboutItemViewHolder = + when (itemType) { + PROFILE_ITEM -> MaterialAboutProfileItem.getViewHolder(view) + else -> super.getViewHolder(itemType, view) + } + + override fun setupItem( + itemType: Int, + holder: MaterialAboutItemViewHolder, + item: MaterialAboutItem, + context: Context + ) = when (itemType) { + PROFILE_ITEM -> MaterialAboutProfileItem.setupItem( + holder as MaterialAboutTitleItemViewHolder, + item as MaterialAboutProfileItem, context + ) + else -> super.setupItem(itemType, holder, item, context) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt new file mode 100644 index 00000000..97e4a538 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsAboutCard.kt @@ -0,0 +1,150 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import android.content.Intent +import android.media.MediaPlayer +import android.widget.Toast +import com.danielstone.materialaboutlibrary.items.MaterialAboutItem +import com.danielstone.materialaboutlibrary.model.MaterialAboutCard +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import eu.szkolny.font.SzkolnyFont +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.BuildConfig +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.sync.UpdateWorker +import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsLicenseActivity +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil +import pl.szczodrzynski.edziennik.utils.Utils +import kotlin.coroutines.CoroutineContext + +class SettingsAboutCard(util: SettingsUtil) : SettingsCard(util), CoroutineScope { + + private val job: Job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + private var clickCounter = 0 + private val mediaPlayer by lazy { + MediaPlayer.create(activity, R.raw.ogarnij_sie) + } + + override fun buildCard(): MaterialAboutCard = + util.createCard( + null, + items = listOf(), + itemsMore = listOf(), + backgroundColor = 0xff1976d2.toInt(), + theme = R.style.AppTheme_Dark + ).also { + it.items.addAll(getItems(it)) + } + + override fun getItems() = listOf() + override fun getItemsMore() = listOf() + + private fun getItems(card: MaterialAboutCard) = listOf( + util.createTitleItem(), + + util.createActionItem( + text = R.string.settings_about_version_text, + icon = CommunityMaterial.Icon2.cmd_information_outline, + onClick = { item -> + clickCounter++ + if (clickCounter < 7) + Toast.makeText(activity, "\uD83D\uDE02", Toast.LENGTH_SHORT).show() + item.subText = + BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE + " \uD83D\uDCA3" + util.refresh() + if (clickCounter >= 7) { + mediaPlayer.start() + clickCounter = 0 + } + } + ).also { + it.subText = BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE + }, + + util.createMoreItem(card, items = listOf( + util.createActionItem( + text = R.string.settings_about_changelog_text, + icon = CommunityMaterial.Icon3.cmd_radar + ) { + ChangelogDialog(activity) + }, + + util.createActionItem( + text = R.string.settings_about_update_text, + subText = R.string.settings_about_update_subtext, + icon = CommunityMaterial.Icon3.cmd_update + ) { + launch { + UpdateWorker.runNow(app) + } + } + )), + + util.createSectionItem( + text = R.string.see_also + ), + + util.createActionItem( + text = R.string.settings_about_privacy_policy_text, + icon = CommunityMaterial.Icon3.cmd_shield_outline + ) { + Utils.openUrl(activity, "https://szkolny.eu/privacy-policy") + }, + + util.createActionItem( + text = R.string.settings_about_discord_text, + subText = R.string.settings_about_discord_subtext, + icon = SzkolnyFont.Icon.szf_discord_outline + ) { + Utils.openUrl(activity, "https://szkolny.eu/discord") + }, + + util.createActionItem( + text = R.string.settings_about_github_text, + subText = R.string.settings_about_github_subtext, + icon = SzkolnyFont.Icon.szf_github_face + ) { + Utils.openUrl(activity, "https://szkolny.eu/github/android") + }, + + util.createMoreItem(card, items = listOfNotNull( + util.createActionItem( + text = R.string.settings_about_homepage_text, + subText = R.string.settings_about_homepage_subtext, + icon = CommunityMaterial.Icon.cmd_earth + ) { + Utils.openUrl(activity, "https://szkolny.eu/") + }, + + util.createActionItem( + text = R.string.settings_about_licenses_text, + icon = CommunityMaterial.Icon.cmd_code_braces + ) { + activity.startActivity(Intent(activity, SettingsLicenseActivity::class.java)) + }, + + if (App.devMode) + util.createActionItem( + text = R.string.settings_about_crash_text, + subText = R.string.settings_about_crash_subtext, + icon = CommunityMaterial.Icon.cmd_bug_outline + ) { + throw RuntimeException("MANUAL CRASH") + } + else + null + )) + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt new file mode 100644 index 00000000..a783731f --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsProfileCard.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import android.content.Intent +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import eu.szkolny.font.SzkolnyFont +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog +import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil + +class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) { + + override fun buildCard() = util.createCard( + null, + items = getItems(), + itemsMore = getItemsMore() + ) + + override fun getItems() = listOf( + util.createProfileItem( + profile = app.profile + ) { + + }, + + util.createActionItem( + text = R.string.settings_add_student_text, + subText = R.string.settings_add_student_subtext, + icon = CommunityMaterial.Icon.cmd_account_plus_outline + ) { + activity.startActivity(Intent(activity, LoginActivity::class.java)) + }, + + util.createActionItem( + text = R.string.settings_profile_remove_text, + subText = R.string.settings_profile_remove_subtext, + icon = SzkolnyFont.Icon.szf_delete_empty_outline + ) { + ProfileRemoveDialog(activity, app.profile.id, app.profile.name, false) + } + ) + + override fun getItemsMore() = listOf( + util.createPropertyItem( + text = R.string.settings_profile_sync_text, + subText = R.string.settings_profile_sync_subtext, + icon = CommunityMaterial.Icon.cmd_account_convert, + value = app.profile.syncEnabled, + ) { _, it -> + app.profile.syncEnabled = it + app.profileSave() + } + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt new file mode 100644 index 00000000..14afd0cb --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsRegisterCard.kt @@ -0,0 +1,152 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import eu.szkolny.font.SzkolnyFont +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.after +import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS +import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_ENABLED +import pl.szczodrzynski.edziennik.ui.dialogs.bell.BellSyncConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil + +class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) { + + override fun buildCard() = util.createCard( + R.string.settings_card_register_title, + items = getItems(), + itemsMore = getItemsMore() + ) + + private fun getBellSync() = + configGlobal.timetable.bellSyncDiff?.let { + activity.getString( + R.string.settings_register_bell_sync_subtext_format, + (if (configGlobal.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS + ) + } ?: activity.getString(R.string.settings_register_bell_sync_subtext_disabled) + + private val sharedEventsItem by lazy { + util.createPropertyItem( + text = R.string.settings_register_shared_events_text, + subText = R.string.settings_register_shared_events_subtext, + icon = CommunityMaterial.Icon3.cmd_share_outline, + value = app.profile.enableSharedEvents + ) { _, value -> + app.profile.enableSharedEvents = value + app.profileSave() + MaterialAlertDialogBuilder(activity) + .setTitle(R.string.event_sharing) + .setMessage( + if (value) + R.string.settings_register_shared_events_dialog_enabled_text + else + R.string.settings_register_shared_events_dialog_disabled_text + ) + .setPositiveButton(R.string.ok, null) + .show() + } + } + + override fun getItems() = listOfNotNull( + util.createActionItem( + text = R.string.menu_grades_config, + icon = CommunityMaterial.Icon3.cmd_numeric_5_box_outline + ) { + GradesConfigDialog(activity, reloadOnDismiss = false) + }, + + util.createActionItem( + text = R.string.menu_attendance_config, + icon = CommunityMaterial.Icon.cmd_calendar_remove_outline + ) { + AttendanceConfigDialog(activity, reloadOnDismiss = false) + }, + + util.createPropertyItem( + text = R.string.settings_register_allow_registration_text, + subText = R.string.settings_register_allow_registration_subtext, + icon = CommunityMaterial.Icon.cmd_account_circle_outline, + value = app.profile.registration == REGISTRATION_ENABLED, + beforeChange = { item, value -> + if (app.profile.registration == REGISTRATION_ENABLED == value) + // allow the switch to change - needed for util.refresh() to change the visual state + return@createPropertyItem true + val dialog = + RegistrationConfigDialog(activity, app.profile, onChangeListener = { enabled -> + if (item.isChecked == enabled) + return@RegistrationConfigDialog + item.isChecked = enabled + if (value) { + card.items.after(item, sharedEventsItem) + } else { + card.items.remove(sharedEventsItem) + } + util.refresh() + }) + if (value) + dialog.showEnableDialog() + else + dialog.showDisableDialog() + false + } + ) { _, _ -> }, + + if (app.profile.registration == REGISTRATION_ENABLED) + sharedEventsItem + else + null + ) + + override fun getItemsMore() = listOfNotNull( + util.createActionItem( + text = R.string.settings_register_bell_sync_text, + icon = SzkolnyFont.Icon.szf_alarm_bell_outline, + onClick = { + BellSyncConfigDialog(activity, onChangeListener = { + it.subText = getBellSync() + util.refresh() + }) + } + ).also { + it.subText = getBellSync() + }, + + util.createPropertyItem( + text = R.string.settings_register_count_in_seconds_text, + subText = R.string.settings_register_count_in_seconds_subtext, + icon = CommunityMaterial.Icon3.cmd_timer_outline, + value = configGlobal.timetable.countInSeconds + ) { _, it -> + configGlobal.timetable.countInSeconds = it + }, + + if (app.profile.loginStoreType == LOGIN_TYPE_LIBRUS) + util.createPropertyItem( + text = R.string.settings_register_show_teacher_absences_text, + icon = CommunityMaterial.Icon.cmd_account_arrow_right_outline, + value = app.profile.getStudentData("showTeacherAbsences", true) + ) { _, it -> + app.profile.putStudentData("showTeacherAbsences", it) + app.profileSave() + } + else + null, + + util.createPropertyItem( + text = R.string.settings_register_hide_sticks_from_old, + icon = CommunityMaterial.Icon3.cmd_numeric_1_box_outline, + value = configProfile.grades.hideSticksFromOld + ) { _, it -> + configProfile.grades.hideSticksFromOld = it + } + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt new file mode 100644 index 00000000..1d42b86b --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsSyncCard.kt @@ -0,0 +1,200 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import android.content.Intent +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK +import android.net.Uri +import android.os.Build.VERSION.SDK_INT +import android.os.Build.VERSION_CODES +import android.provider.Settings +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.after +import pl.szczodrzynski.edziennik.getSyncInterval +import pl.szczodrzynski.edziennik.sync.SyncWorker +import pl.szczodrzynski.edziennik.sync.UpdateWorker +import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog +import pl.szczodrzynski.edziennik.ui.dialogs.sync.QuietHoursConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncIntervalDialog +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil +import pl.szczodrzynski.edziennik.utils.models.Time + +class SettingsSyncCard(util: SettingsUtil) : SettingsCard(util) { + + override fun buildCard() = util.createCard( + R.string.settings_card_sync_title, + items = getItems(), + itemsMore = getItemsMore() + ) + + private fun getQuietHours(): String { + if (configGlobal.sync.quietHoursStart == null) { + configGlobal.sync.quietHoursStart = Time(22, 30, 0) + } + if (configGlobal.sync.quietHoursEnd == null) { + configGlobal.sync.quietHoursEnd = Time(6, 30, 0) + } + + return activity.getString( + if (configGlobal.sync.quietHoursStart!! > configGlobal.sync.quietHoursEnd!!) + R.string.settings_sync_quiet_hours_subtext_next_day_format + else + R.string.settings_sync_quiet_hours_subtext_format, + configGlobal.sync.quietHoursStart?.stringHM, + configGlobal.sync.quietHoursEnd?.stringHM + ) + } + + private val syncWifiItem by lazy { + util.createPropertyItem( + text = R.string.settings_sync_wifi_text, + subText = R.string.settings_sync_wifi_subtext, + icon = CommunityMaterial.Icon3.cmd_wifi_strength_2, + value = configGlobal.sync.onlyWifi + ) { _, it -> + configGlobal.sync.onlyWifi = it + SyncWorker.rescheduleNext(app) + } + } + + override fun getItems() = listOfNotNull( + util.createPropertyActionItem( + text = R.string.settings_sync_sync_interval_text, + subText = R.string.settings_sync_sync_interval_subtext_disabled, + icon = CommunityMaterial.Icon.cmd_download_outline, + value = configGlobal.sync.enabled, + onChange = { item, value -> + // When calling onChange from the onClick listener below + // a list refresh is requested, the adapter refreshes + // all view holders, changing the state of the switch + // view, thus calling onChange again, causing it to + // try to recursively refresh the list, therefore + // crashing the app. To avoid this, the method will + // continue only if the checked state is different + // from the saved value, which should only happen + // when clicking the switch manually or when called + // by onClick, **once** (because onClick doesn't + // update the config value - we let the switch + // listener do it). Then there comes a different problem, + // when onClick changes the subText and the onChange + // listener returns because the boolean value + // is unchanged, leaving the list not refreshed. + // To solve this, a list refresh is also requested + // in onClick, when the config value is the same + // as the new switch value, which would normally + // cause the onChange method to exit here. + if (value == configGlobal.sync.enabled) + return@createPropertyActionItem + + if (value) { + card.items.after(item, syncWifiItem) + } else { + card.items.remove(syncWifiItem) + } + util.refresh() + + configGlobal.sync.enabled = value + SyncWorker.rescheduleNext(app) + }, + onClick = { item -> + SyncIntervalDialog(activity, onChangeListener = { + item.subTextChecked = activity.getSyncInterval(configGlobal.sync.interval) + item.isChecked = true + item.onCheckedChangedAction.onCheckedChanged(item, true) + if (configGlobal.sync.enabled) + util.refresh() + }) + } + ).also { + it.subTextChecked = activity.getSyncInterval(configGlobal.sync.interval) + }, + + if (configGlobal.sync.enabled) + syncWifiItem + else + null, + + util.createActionItem( + text = R.string.settings_profile_notifications_text, + subText = R.string.settings_profile_notifications_subtext, + icon = CommunityMaterial.Icon2.cmd_filter_outline + ) { + NotificationFilterDialog(activity) + }, + + util.createPropertyActionItem( + text = R.string.settings_sync_quiet_hours_text, + subText = R.string.settings_sync_quiet_hours_subtext_disabled, + icon = CommunityMaterial.Icon.cmd_bell_sleep_outline, + value = configGlobal.sync.quietHoursEnabled, + onChange = { _, value -> + configGlobal.sync.quietHoursEnabled = value + }, + onClick = { item -> + QuietHoursConfigDialog(activity, onChangeListener = { + item.subTextChecked = getQuietHours() + item.isChecked = configGlobal.sync.quietHoursEnabled + util.refresh() + }) + } + ).also { + it.subTextChecked = getQuietHours() + }, + + util.createActionItem( + text = R.string.settings_sync_web_push_text, + subText = R.string.settings_sync_web_push_subtext, + icon = CommunityMaterial.Icon2.cmd_laptop + ) { + activity.loadTarget(MainActivity.TARGET_WEB_PUSH) + } + ) + + override fun getItemsMore() = listOfNotNull( + util.createPropertyItem( + text = R.string.settings_sync_updates_text, + icon = CommunityMaterial.Icon.cmd_cellphone_arrow_down, + value = configGlobal.sync.notifyAboutUpdates + ) { _, it -> + configGlobal.sync.notifyAboutUpdates = it + UpdateWorker.rescheduleNext(app) + }, + + if (SDK_INT >= VERSION_CODES.KITKAT) + util.createActionItem( + text = R.string.settings_sync_notifications_settings_text, + subText = R.string.settings_sync_notifications_settings_subtext, + icon = CommunityMaterial.Icon.cmd_cog_outline + ) { + val channel = app.notificationChannelsManager.data.key + val intent = Intent().apply { + when { + SDK_INT >= VERSION_CODES.O -> { + action = Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS + putExtra(Settings.EXTRA_APP_PACKAGE, app.packageName) + putExtra(Settings.EXTRA_CHANNEL_ID, channel) + addFlags(FLAG_ACTIVITY_NEW_TASK) + } + SDK_INT >= VERSION_CODES.LOLLIPOP -> { + action = "android.settings.APP_NOTIFICATION_SETTINGS" + putExtra("app_package", app.packageName) + putExtra("app_uid", app.applicationInfo.uid) + } + else -> { + action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS + addCategory(Intent.CATEGORY_DEFAULT) + data = Uri.parse("package:" + app.packageName) + } + } + } + activity.startActivity(intent) + } + else + null + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt new file mode 100644 index 00000000..0cb710cb --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/cards/SettingsThemeCard.kt @@ -0,0 +1,96 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-18. + */ + +package pl.szczodrzynski.edziennik.ui.modules.settings.cards + +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.ui.dialogs.settings.AppLanguageDialog +import pl.szczodrzynski.edziennik.ui.dialogs.settings.MiniMenuConfigDialog +import pl.szczodrzynski.edziennik.ui.dialogs.settings.ThemeChooserDialog +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsCard +import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsUtil +import pl.szczodrzynski.edziennik.utils.Themes +import pl.szczodrzynski.edziennik.utils.models.Date + +class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) { + + override fun buildCard() = util.createCard( + R.string.settings_card_theme_title, + items = getItems(), + itemsMore = getItemsMore() + ) + + override fun getItems() = listOfNotNull( + if (Date.getToday().month % 11 == 1) // cool math games + util.createPropertyItem( + text = R.string.settings_theme_snowfall_text, + subText = R.string.settings_theme_snowfall_subtext, + icon = CommunityMaterial.Icon3.cmd_snowflake, + value = configGlobal.ui.snowfall + ) { _, it -> + configGlobal.ui.snowfall = it + activity.recreate() + } + else null, + + util.createActionItem( + text = R.string.settings_theme_theme_text, + subText = Themes.getThemeNameRes(), + icon = CommunityMaterial.Icon3.cmd_palette_outline + ) { + ThemeChooserDialog(activity) + }, + + util.createActionItem( + text = R.string.settings_about_language_text, + subText = R.string.settings_about_language_subtext, + icon = CommunityMaterial.Icon3.cmd_translate + ) { + AppLanguageDialog(activity) + }, + + util.createPropertyItem( + text = R.string.settings_theme_mini_drawer_text, + subText = R.string.settings_theme_mini_drawer_subtext, + icon = CommunityMaterial.Icon.cmd_dots_vertical, + value = configGlobal.ui.miniMenuVisible + ) { _, it -> + configGlobal.ui.miniMenuVisible = it + activity.navView.drawer.miniDrawerVisiblePortrait = it + } + ) + + override fun getItemsMore() = listOf( + util.createActionItem( + text = R.string.settings_theme_mini_drawer_buttons_text, + icon = CommunityMaterial.Icon2.cmd_format_list_checks + ) { + MiniMenuConfigDialog(activity) + }, + + util.createActionItem( + text = R.string.settings_theme_drawer_header_text, + icon = CommunityMaterial.Icon2.cmd_image_outline + ) { + // TODO: 2021-03-17 + }, + + util.createActionItem( + text = R.string.settings_theme_app_background_text, + subText = R.string.settings_theme_app_background_subtext, + icon = CommunityMaterial.Icon2.cmd_image_filter_hdr + ) { + // TODO: 2021-03-17 + }, + + util.createPropertyItem( + text = R.string.settings_theme_open_drawer_on_back_pressed_text, + icon = CommunityMaterial.Icon3.cmd_menu_open, + value = configGlobal.ui.openDrawerOnBackPressed + ) { _, it -> + configGlobal.ui.openDrawerOnBackPressed = it + } + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt index e2189f71..5f62b794 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Themes.kt @@ -42,6 +42,12 @@ object Themes { theme = themeList[value] } + var themeIndex + get() = themeList.indexOf(theme) + set(value) { + theme = themeList[value] + } + val appThemeNoDisplay: Int get() = if (theme.isDark) R.style.AppTheme_Dark_NoDisplay else R.style.AppTheme_Light_NoDisplay @@ -61,38 +67,15 @@ object Themes { return getColorFromAttr(context, android.R.attr.textColorSecondary) } - /*public static int getChipColorRes() { - switch (themeInt) { - case THEME_LIGHT: - return R.color.chipBackgroundLight; - default: - case THEME_DARK: - return R.color.chipBackgroundDark; - case THEME_BLACK: - return R.color.chipBackgroundBlack; - case THEME_CHOCOLATE: - return R.color.chipBackgroundChocolate; - case THEME_BLUE: - return R.color.chipBackgroundBlue; - case THEME_PURPLE: - return R.color.chipBackgroundPurple; - case THEME_GREEN: - return R.color.chipBackgroundGreen; - case THEME_AMBER: - return R.color.chipBackgroundAmber; - case THEME_RED: - return R.color.chipBackgroundRed; - } - }*/ fun getThemeName(context: Context): String { return context.getString(theme.name) } - fun getThemeNames(context: Context): List { - val list = mutableListOf() - for (theme in themeList) { - list += context.getString(theme.name) + @StringRes + fun getThemeNameRes() = theme.name + + fun getThemeNames(context: Context) = + themeList.map { + context.getString(it.name) } - return list - } } diff --git a/app/src/main/res/layout/dialog_edit_text.xml b/app/src/main/res/layout/dialog_edit_text.xml new file mode 100644 index 00000000..6937705e --- /dev/null +++ b/app/src/main/res/layout/dialog_edit_text.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/mal_material_about_profile_item.xml b/app/src/main/res/layout/mal_material_about_profile_item.xml new file mode 100644 index 00000000..e1802130 --- /dev/null +++ b/app/src/main/res/layout/mal_material_about_profile_item.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 6e37bf58..9949f2e2 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -351,8 +351,6 @@ Hinzugefügt %1$s%3$s {cmd-share-variant} %1$s von %2$s%3$s {cmd-share-variant} %1$s von Ihnen%3$s - Um das Ereignis freigeben zu können, müssen Sie die Serverregistrierungsoption aktivieren. Auf diese Weise können Sie Ereignisse erstellen und empfangen, die in Ihrer Klasse geteilt werden.\n\nWenn Sie auf OK klicken, wird diese automatisch aktiviert.\n\nStellen Sie sicher, dass Sie die Bedingungen lesen und akzeptieren. - Ereignisse teilen Ereignis entfernen… Ereignis speichern… Ereignis teilen… @@ -830,9 +828,13 @@ etzt bewerten Zeigen Sie, dass Ihnen Szkolny.eu gefällt - bewerten Sie die App und machen Sie sie noch besser! Aktualisieren - Die Registrierung erfolgt automatisch, wenn diese Option aktiviert ist. Sie können Ereignisse erstellen und empfangen, die mit anderen Schülern in Ihrer Klasse geteilt werden. Dank dessen können Sie Elemente, die nicht vom Lehrer gespeichert wurden, zum Klassenbuch hinzufügen.\n\nStellen Sie sicher, dass Sie die Bestimmungen der Datenschutzrichtlinie lesen und die Bestimmungen akzeptieren. - Server-Registrierung - Gemeinsame Ereignisse herunterladen… + Benutzerregistrierung aufheben… + Einige Funktionen wie Ereignisfreigabe oder Benachrichtigungsweiterleitung können nicht mehr verwendet werden.\n\nDie Funktion kann je nach ausgewähltem Profil aktiviert / deaktiviert werden. + Gemeinsame Ereignisse herunterladen… + Die Registrierung erfolgt automatisch, wenn diese Option aktiviert ist. Sie können Ereignisse erstellen und empfangen, die mit anderen Schülern in Ihrer Klasse geteilt werden. Dank dessen können Sie Elemente, die nicht vom Lehrer gespeichert wurden, zum Klassenbuch hinzufügen.\n\nStellen Sie sicher, dass Sie die Bestimmungen der Datenschutzrichtlinie lesen und die Bestimmungen akzeptieren. + Um das Ereignis freigeben zu können, müssen Sie die Serverregistrierungsoption aktivieren. Auf diese Weise können Sie Ereignisse erstellen und empfangen, die in Ihrer Klasse geteilt werden.\n\nWenn Sie auf OK klicken, wird diese automatisch aktiviert.\n\nStellen Sie sicher, dass Sie die Bedingungen lesen und akzeptieren. + Ereignisse teilen + Szkolny.eu Server-Registrierung Löschen gelöschtet Melden @@ -847,13 +849,13 @@ Klicken Sie hier, um eine unerwartete Ausnahme auszulösen Treten Sie unserem Discord-Server bei! Discord Server - Hinweis. Diese Option funktioniert möglicherweise auf einigen Geräten und in einigen Teilen der App nicht. - App-Sprache ändern + Hinweis. Diese Option funktioniert möglicherweise auf einigen Geräten und in einigen Teilen der App nicht. + App-Sprache ändern Deutsch Sprache der App Open-Source-Lizenzen Datenschutzrichtlinie - E-Klassenbuch + E-Klassenbuch © Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - Februar 2021 Klicken Sie hier, um nach Aktualisierungen zu suchen Aktualisierung @@ -944,7 +946,7 @@ Deaktiviert Daten alle %s herunterladen Automatische Synchronisierung - Synchronisation und Benachrichtigungen + Synchronisation und Benachrichtigungen Über App-Aktualisierungen benachrichtigen Benachrichtigungen auf Ihrem PC anzeigen Benachrichtigungsweiterleitung @@ -968,7 +970,7 @@ Rosa System Thema - Aussehen + Aussehen Teilen Teilen über… Daten Teilen… diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index ab80b93c..2f5cb1fe 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -351,8 +351,6 @@ Adde %1$s%3$s {cmd-share-variant} %1$s by %2$s%3$s {cmd-share-variant} %1$s by you%3$s - You need to turn on server registration, in order to share an event. This option lets you create and receive shared events in your class.\n\nIt will be turned on automatically by pressing OK.\n\nBefore turning it on, make sure you\'ve read the terms and accept them - Sharing events Removing event… Saving event… Sharing event… @@ -832,9 +830,13 @@ Rate now Show that you like Szkolny.eu - rate the app and make it even better! Refresh - Registration is automatic if this option is enabled. It allows you to create and receive events shared with other students in your class. Thanks to this, you can add items not saved by the teacher to the journal.\n\nMake sure you read the terms and accept them. - Server registration - Syncing shared events… + Unregistering the user… + You won\'t be able to use some functions anymore, like Event sharing and Notification forwarding.\n\nThis feature may be enabled/disabled depending on the active profile. + Syncing shared events… + Registration is automatic if this option is enabled. It allows you to create and receive events shared with other students in your class. Thanks to this, you can add items not saved by the teacher to the journal.\n\nContinuing means reading and accepting the Privacy policy. + You need to turn on server registration, in order to share an event. This option lets you create and receive shared events in your class.\n\nIt will be turned on automatically by pressing OK.\n\nContinuing means reading and accepting the Privacy policy. + Sharing events + Szkolny.eu server registration Remove Removed Report @@ -849,13 +851,13 @@ Click to throw an unexpected exception Join our Discord community! Discord server - Notice. This feature may not work on some devices or in some parts of the app. - Change app language - "English " + Notice. This feature may not work on some devices or in some parts of the app. + Change app language + English App language Open-source licenses Privacy policy - E-register + E-register © Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - February 2021 Click to check for updates Update @@ -946,7 +948,7 @@ Disabled Download data every %s Automatic sync - Sync & notifications + Sync & notifications Notify about app updates Show notifications on your PC Notification forwarding @@ -970,7 +972,7 @@ Pink System Theme - Appearance + Appearance Share Share… Sharing events… diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ea45e49..9251f4b4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -386,8 +386,6 @@ Dodano %1$s%3$s {cmd-share-variant} %1$s przez %2$s%3$s {cmd-share-variant} %1$s przez Ciebie%3$s - Aby móc udostępnić wydarzenie, należy włączyć opcję rejestracji na serwerze. Pozwala to na tworzenie i odbieranie wydarzeń udostępnionych w Twojej klasie.\n\nPo kliknięciu OK zostanie ona automatycznie włączona.\n\nUpewnij się, że zapoznałeś się z warunkami i akceptujesz jej postanowienia. - Udostępnianie wydarzeń Usuwam wydarzenie… Zapisuję wydarzenie… Udostępniam wydarzenie… @@ -895,9 +893,13 @@ Oceń teraz Pokaż, że podoba ci się Szkolny.eu - oceń aplikację i spraw, by była jeszcze lepsza! Odśwież - Rejestracja jest automatyczna, jeśli ta opcja jest włączona. Pozwala na tworzenie i odbieranie wydarzeń udostępnionych innym uczniom z Twojej klasy. Dzięki temu, można dodawać do dziennika pozycje nie zapisane przez nauczyciela.\n\nUpewnij się, że zapoznałeś się z warunkami Polityki prywatności i akceptujesz jej postanowienia. - Rejestracja na serwerze - Pobieranie udostępnionych wydarzeń… + Trwa wyrejestrowywanie użytkownika… + Stracisz możliwość korzystania z niektórych funkcji, takich jak Udostępnianie wydarzeń czy Przekazywanie powiadomień.\n\nFunkcja może być włączona/wyłączona w zależności od wybranego profilu. + Pobieranie udostępnionych wydarzeń… + Rejestracja jest automatyczna, jeśli ta opcja jest włączona. Pozwala na tworzenie i odbieranie wydarzeń udostępnionych innym uczniom z Twojej klasy. Dzięki temu, można dodawać do dziennika pozycje nie zapisane przez nauczyciela.\n\nKontynuując, oświadczasz przeczytanie i akceptację postanowień Polityki prywatności. + Aby móc udostępnić wydarzenie, należy włączyć opcję rejestracji na serwerze. Pozwala to na tworzenie i odbieranie wydarzeń udostępnionych w Twojej klasie.\n\nPo kliknięciu OK zostanie ona automatycznie włączona.\n\nKontynuując, oświadczasz przeczytanie i akceptację postanowień Polityki prywatności. + Udostępnianie wydarzeń + Rejestracja aplikacji Szkolny.eu Usuń Usunięto Zgłoś @@ -912,13 +914,13 @@ Kliknij, aby wywołać nieoczekiwany wyjątek Dołącz do naszego serwera Discord! Serwer Discord - Uwaga. Ta opcja może nie działać na niektórych urządzeniach oraz w niektórych fragmentach aplikacji. - Zmień język aplikacji + Uwaga. Ta opcja może nie działać na niektórych urządzeniach oraz w niektórych fragmentach aplikacji. + Zmień język aplikacji Polski Język aplikacji Licencje open-source Polityka prywatności - E-dziennik + E-dziennik © Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - luty 2021 Kliknij, aby sprawdzić aktualizacje Aktualizacja @@ -1011,7 +1013,7 @@ Wyłączona Pobieraj dane co %s Synchronizacja automatyczna - Synchronizacja i powiadomienia + Synchronizacja i powiadomienia Powiadamiaj o aktualizacjach aplikacji Pokazuj powiadomienia na swoim komputerze Przekazywanie powiadomień @@ -1035,7 +1037,7 @@ Różowy Systemowy Motyw - Wygląd + Wygląd Udostępnij Udostępnij przez… Udostępnianie danych… @@ -1387,4 +1389,10 @@ {cmd-android-studio} Wersja deweloperska \??? Szkoda, opinie innych pomagają mi rozwijać aplikację. + Nie znaleziono profilu ucznia. + Zobacz także + Wejdź na stronę aplikacji + Uzyskaj pomoc lub wesprzyj autorów + Kod źródłowy + Pomóż w rozwoju aplikacji na GitHubie