[UI] Add SimpleDialog class, migrate app dialogs (#208)
Some checks failed
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
Schedule/dispatch / Check new changes (push) Failing after 21s

* Make onShow() abstract and onDismiss() suspend

* Add dialog suspend show method

* Add SimpleDialog, support text field and choice items in BaseDialog

* Migrate MaterialAlertDialogBuilder to SimpleDialog

* Remove dialog onShow and onDismiss listeners
This commit is contained in:
Kuba Szczodrzyński 2024-07-06 19:36:59 +02:00 committed by GitHub
parent 09f0c986e0
commit 6371d71b7a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
87 changed files with 1261 additions and 1387 deletions

View File

@ -22,7 +22,6 @@ import androidx.navigation.NavOptions
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.danimahardhika.cafebar.CafeBar
import com.danimahardhika.cafebar.CafeBarTheme
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.jetradarmobile.snowfall.SnowfallView
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.materialdrawer.model.DividerDrawerItem
@ -77,12 +76,12 @@ import pl.szczodrzynski.edziennik.ext.keys
import pl.szczodrzynski.edziennik.ext.putExtras
import pl.szczodrzynski.edziennik.ext.resolveAttr
import pl.szczodrzynski.edziennik.ext.resolveString
import pl.szczodrzynski.edziennik.ext.setMessage
import pl.szczodrzynski.edziennik.ext.setTintColor
import pl.szczodrzynski.edziennik.ext.shouldArchive
import pl.szczodrzynski.edziennik.ext.takePositive
import pl.szczodrzynski.edziennik.ext.toDrawable
import pl.szczodrzynski.edziennik.ext.toImageHolder
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.dialogs.ChangelogDialog
import pl.szczodrzynski.edziennik.ui.dialogs.ErrorDetailsDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileConfigDialog
@ -457,37 +456,37 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|__*/
private suspend fun syncCurrentFeature() {
if (app.profile.archived) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.profile_archived_title)
.setMessage(
SimpleDialog<Unit>(this) {
title(R.string.profile_archived_title)
message(
R.string.profile_archived_text,
app.profile.studentSchoolYearStart,
app.profile.studentSchoolYearStart + 1
)
.setPositiveButton(R.string.ok, null)
.show()
positive(R.string.ok)
}.show()
swipeRefreshLayout.isRefreshing = false
return
}
if (app.profile.shouldArchive()) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.profile_archiving_title)
.setMessage(
SimpleDialog<Unit>(this) {
title(R.string.profile_archiving_title)
message(
R.string.profile_archiving_format,
app.profile.dateYearEnd.formattedString
)
.setPositiveButton(R.string.ok, null)
.show()
positive(R.string.ok)
}.show()
}
if (app.profile.isBeforeYear()) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.profile_year_not_started_title)
.setMessage(
SimpleDialog<Unit>(this) {
title(R.string.profile_year_not_started_title)
message(
R.string.profile_year_not_started_format,
app.profile.dateSemester1Start.formattedString
)
.setPositiveButton(R.string.ok, null)
.show()
positive(R.string.ok)
}.show()
swipeRefreshLayout.isRefreshing = false
return
}
@ -625,10 +624,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
EventBus.getDefault().removeStickyEvent(event)
if (app.config.sync.dontShowAppManagerDialog)
return
MaterialAlertDialogBuilder(this)
.setTitle(R.string.app_manager_dialog_title)
.setMessage(R.string.app_manager_dialog_text)
.setPositiveButton(R.string.ok) { _, _ ->
SimpleDialog<Unit>(this) {
title(R.string.app_manager_dialog_title)
message(R.string.app_manager_dialog_text)
positive(R.string.ok) {
try {
for (intent in appManagerIntentList) {
if (packageManager.resolveActivity(intent,
@ -642,16 +641,16 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
startActivity(Intent(Settings.ACTION_SETTINGS))
} catch (e: Exception) {
Timber.e(e)
Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT)
Toast.makeText(this@MainActivity, R.string.app_manager_open_failed, Toast.LENGTH_SHORT)
.show()
}
}
}
.setNeutralButton(R.string.dont_ask_again) { _, _ ->
neutral(R.string.dont_ask_again) {
app.config.sync.dontShowAppManagerDialog = true
}
.setCancelable(false)
.show()
cancelable(false)
}.show()
}
@Subscribe(threadMode = ThreadMode.MAIN)

View File

@ -6,9 +6,7 @@ package pl.szczodrzynski.edziennik.core.manager
import android.content.pm.PackageManager
import android.text.TextUtils
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
@ -34,6 +32,8 @@ import pl.szczodrzynski.edziennik.ext.md5
import pl.szczodrzynski.edziennik.ext.resolveAttr
import pl.szczodrzynski.edziennik.ext.resolveColor
import pl.szczodrzynski.edziennik.ext.toJsonObject
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.main.BuildInvalidActivity
import pl.szczodrzynski.edziennik.utils.Utils
import timber.log.Timber
@ -174,18 +174,19 @@ class BuildManager(val app: App) : CoroutineScope {
)
}.concat("\n\n")
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.build_details)
.setMessage(message)
.setPositiveButton(R.string.ok, null)
.setNeutralButton(R.string.build_dialog_open_repo) { _, _ ->
SimpleDialog<Unit>(activity) {
title(R.string.build_details)
message(message)
positive(R.string.ok, null)
neutral(R.string.build_dialog_open_repo) {
val url = if (gitRemote == null)
"https://szkolny.eu/github/android"
else
"https://github.com/$gitRemote/tree/$gitHash"
Utils.openUrl(activity, url)
}
.show()
show()
}
}
enum class InvalidBuildReason(
@ -294,11 +295,11 @@ class BuildManager(val app: App) : CoroutineScope {
return@launch
}
val dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.please_wait)
.setMessage(R.string.build_validate_progress)
.setCancelable(false)
.show()
val dialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(R.string.build_validate_progress)
cancelable(false)
}.show()
val isRepoValid = if (app.config.validation == "invalid$gitRemote$gitHash".md5())
false
@ -320,7 +321,7 @@ class BuildManager(val app: App) : CoroutineScope {
private fun invalidateBuild(
activity: AppCompatActivity,
progressDialog: AlertDialog?,
progressDialog: BaseDialog<*>?,
reason: InvalidBuildReason
) {
progressDialog?.dismiss()

View File

@ -218,8 +218,6 @@ class NoteManager(private val app: App) {
activity = activity,
attendance = item,
showNotes = false,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
is NoticeFull -> return
is Date -> DayDialog(
@ -227,29 +225,21 @@ class NoteManager(private val app: App) {
profileId = App.profileId,
date = item,
showNotes = false,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
is EventFull -> EventDetailsDialog(
activity = activity,
event = item,
showNotes = false,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
is GradeFull -> GradeDetailsDialog(
activity = activity,
grade = item,
showNotes = false,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
is LessonFull -> LessonDetailsDialog(
activity = activity,
lesson = item,
showNotes = false,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
is MessageFull -> return
}

View File

@ -12,7 +12,6 @@ import android.os.Build
import android.provider.Settings
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.qifan.powerpermission.coroutines.awaitAskPermissions
import com.qifan.powerpermission.data.hasAllGranted
import com.qifan.powerpermission.data.hasPermanentDenied
@ -23,6 +22,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import kotlin.coroutines.CoroutineContext
class PermissionManager(val app: App) : CoroutineScope {
@ -70,10 +70,10 @@ class PermissionManager(val app: App) : CoroutineScope {
onSuccess()
return@launch
}
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.permissions_required)
.setMessage(permissionMessage)
.setPositiveButton(R.string.ok) { _, _ ->
SimpleDialog<Unit>(activity) {
title(R.string.permissions_required)
message(permissionMessage)
positive(R.string.ok) {
requestPermission(
activity,
permissionMessage,
@ -82,22 +82,22 @@ class PermissionManager(val app: App) : CoroutineScope {
onSuccess
)
}
.setNegativeButton(R.string.cancel, null)
.show()
negative(R.string.cancel)
}.show()
}
result.hasPermanentDenied() -> {
if (!isRequired) {
onSuccess()
return@launch
}
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.permissions_required)
.setMessage(R.string.permissions_denied)
.setPositiveButton(R.string.ok) { _, _ ->
SimpleDialog<Unit>(activity) {
title(R.string.permissions_required)
message(R.string.permissions_denied)
positive(R.string.ok) {
openPermissionSettings(activity)
}
.setNegativeButton(R.string.cancel, null)
.show()
negative(R.string.cancel)
}.show()
}
}
}

View File

@ -287,8 +287,6 @@ class TextStylingManager(private val app: App) {
activity: AppCompatActivity,
textLayout: TextInputLayout,
textEdit: TextInputKeyboardEdit,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) {
textLayout.endIconDrawable = CommunityMaterial.Icon3.cmd_open_in_new.toDrawable(activity)
textLayout.setEndIconOnClickListener {
@ -298,8 +296,6 @@ class TextStylingManager(private val app: App) {
onSuccess = {
textEdit.text = it
},
onShowListener,
onDismissListener
).show()
}
}

View File

@ -6,67 +6,14 @@ package pl.szczodrzynski.edziennik.ext
import android.annotation.SuppressLint
import android.content.res.ColorStateList
import android.text.InputType
import android.view.LayoutInflater
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.core.graphics.ColorUtils
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.dialog.MaterialDialogs
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.textfield.TextInputEditText
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.DialogEditTextBinding
fun MaterialAlertDialogBuilder.input(
message: CharSequence? = null,
type: Int = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE,
hint: CharSequence? = null,
value: CharSequence? = null,
changeListener: ((editText: TextInputEditText, input: String) -> Boolean)? = null,
positiveButton: Int? = null,
positiveListener: ((editText: TextInputEditText, input: String) -> Boolean)? = null,
): MaterialAlertDialogBuilder {
val b = DialogEditTextBinding.inflate(LayoutInflater.from(context), null, false)
b.title.text = message
b.title.isVisible = message.isNotNullNorBlank()
b.text1.hint = hint
b.text1.inputType = type
b.text1.setText(value)
b.text1.addTextChangedListener { text ->
if (changeListener?.invoke(b.text1, text?.toString() ?: "") != false)
b.text1.error = null
}
if (positiveButton != null) {
setPositiveButton(positiveButton) { dialog, _ ->
if (positiveListener?.invoke(b.text1, b.text1.text?.toString() ?: "") != false)
dialog.dismiss()
}
}
setView(b.root)
return this
}
fun MaterialAlertDialogBuilder.setTitle(
@StringRes resId: Int,
vararg formatArgs: Any,
): MaterialAlertDialogBuilder {
setTitle(context.getString(resId, *formatArgs))
return this
}
fun MaterialAlertDialogBuilder.setMessage(
@StringRes resId: Int,
vararg formatArgs: Any,
): MaterialAlertDialogBuilder {
setMessage(context.getString(resId, *formatArgs))
return this
}
@SuppressLint("RestrictedApi")
fun AlertDialog.overlayBackgroundColor(color: Int, alpha: Int) {

View File

@ -157,7 +157,7 @@ fun IIcon.toDrawable(
colorRes: Int? = null,
colorAttr: Int = R.attr.colorOnBackground,
sizeDp: Int = 24,
) = toDrawable(activity, colorInt, colorRes, colorAttr, sizeDp)
) = toDrawable(app, colorInt, colorRes, colorAttr, sizeDp)
context(View)
fun IIcon.toDrawable(

View File

@ -16,6 +16,7 @@ import androidx.lifecycle.Observer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
import java.io.PrintWriter
import java.io.StringWriter
@ -88,3 +89,13 @@ fun Long?.takePositive() = if (this == -1L || this == 0L) null else this
fun String?.takeValue() = if (this.isNullOrBlank()) null else this
fun Any?.ignore() = Unit
fun EventBus.registerSafe(subscriber: Any) = try {
EventBus.getDefault().register(subscriber)
} catch (_: Exception) {
}
fun EventBus.unregisterSafe(subscriber: Any) = try {
EventBus.getDefault().unregister(subscriber)
} catch (_: Exception) {
}

View File

@ -63,7 +63,7 @@ class AgendaFragment : BaseFragment<ViewBinding, MainActivity>(
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
AgendaConfigDialog(activity, true, null, null).show()
AgendaConfigDialog(activity, true).show()
},
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_agenda_change_view)

View File

@ -39,11 +39,7 @@ class DayDialog(
private val date: Date,
private val eventTypeId: Long? = null,
private val showNotes: Boolean = false,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogDayBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "DayDialog"
) : BindingDialog<DialogDayBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -59,8 +55,6 @@ class DayDialog(
activity,
profileId,
defaultDate = date,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
return NO_DISMISS
}
@ -114,8 +108,6 @@ class DayDialog(
activity,
profileId,
date,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
}
}
@ -139,8 +131,6 @@ class DayDialog(
activity,
profileId,
date,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
}
}
@ -158,8 +148,6 @@ class DayDialog(
EventDetailsDialog(
activity,
it,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
},
onEventEditClick = {
@ -167,8 +155,6 @@ class DayDialog(
activity,
it.profileId,
editingEvent = it,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
}
)
@ -209,8 +195,6 @@ class DayDialog(
b.notesButton.setupNotesButton(
activity = activity,
owner = date,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
)
b.legend.isVisible = showNotes
if (showNotes)

View File

@ -15,14 +15,9 @@ class LessonChangesDialog(
activity: AppCompatActivity,
private val profileId: Int,
private val defaultDate: Date,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogLessonChangeListBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "LessonChangesDialog"
) : BindingDialog<DialogLessonChangeListBinding>(activity) {
override fun getTitle(): String = defaultDate.formattedString
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
DialogLessonChangeListBinding.inflate(layoutInflater)
@ -39,8 +34,6 @@ class LessonChangesDialog(
LessonDetailsDialog(
activity,
it,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
}
).apply {

View File

@ -14,14 +14,9 @@ class TeacherAbsenceDialog(
activity: AppCompatActivity,
private val profileId: Int,
private val date: Date,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogTeacherAbsenceListBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "TeacherAbsenceDialog"
) : BindingDialog<DialogTeacherAbsenceListBinding>(activity) {
override fun getTitle(): String = date.formattedString
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
DialogTeacherAbsenceListBinding.inflate(layoutInflater)

View File

@ -22,11 +22,7 @@ class AttendanceDetailsDialog(
activity: AppCompatActivity,
private val attendance: AttendanceFull,
private val showNotes: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<AttendanceDetailsDialogBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "AttendanceDetailsDialog"
) : BindingDialog<AttendanceDetailsDialogBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -34,7 +30,7 @@ class AttendanceDetailsDialog(
override fun getPositiveButtonText() = R.string.close
override suspend fun onShow() {
override suspend fun onBeforeShow(): Boolean {
val manager = app.attendanceManager
val attendanceColor = manager.getAttendanceColor(attendance)
@ -49,7 +45,7 @@ class AttendanceDetailsDialog(
BetterLink.attach(
b.teacherName,
teachers = mapOf(attendance.teacherId to name),
onActionSelected = dialog::dismiss
onActionSelected = ::dismiss
)
}
@ -57,11 +53,10 @@ class AttendanceDetailsDialog(
b.notesButton.setupNotesButton(
activity = activity,
owner = attendance,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
)
b.legend.isVisible = showNotes
if (showNotes)
NoteManager.setLegendText(attendance, b.legend)
return true
}
}

View File

@ -38,7 +38,7 @@ class AttendanceFragment : PagerFragment<BasePagerFragmentBinding, MainActivity>
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
AttendanceConfigDialog(activity, true, null, null).show()
AttendanceConfigDialog(activity, true).show()
},
)

View File

@ -4,88 +4,108 @@
package pl.szczodrzynski.edziennik.ui.base.dialog
import android.text.Editable
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AlertDialog.*
import androidx.appcompat.app.AlertDialog.BUTTON_NEGATIVE
import androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL
import androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE
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 kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.databinding.DialogEditTextBinding
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.setMessage
import pl.szczodrzynski.edziennik.ext.registerSafe
import pl.szczodrzynski.edziennik.ext.resolveString
import pl.szczodrzynski.edziennik.ext.unregisterSafe
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.resume
abstract class BaseDialog<I : Any>(
internal val activity: AppCompatActivity,
protected val onShowListener: ((tag: String) -> Unit)? = null,
protected val onDismissListener: ((tag: String) -> Unit)? = null,
protected val activity: AppCompatActivity,
) : CoroutineScope {
companion object {
const val DISMISS = true
const val NO_DISMISS = false
}
@Suppress("PropertyName")
abstract val TAG: String
protected lateinit var app: App
internal val app = activity.applicationContext as App
protected lateinit var dialog: AlertDialog
private val job = Job()
private var job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private var continuation: Continuation<BaseDialog<I>>? = null
private var button: Int? = null
private var items = emptyList<I>()
private var itemSelected: I? = null
private var itemStates = BooleanArray(0)
private var input: TextInputEditText? = null
protected open fun getTitle(): CharSequence? = null
protected abstract fun getTitleRes(): Int?
protected open fun getTitleRes(): Int? = null
protected open fun getMessage(): CharSequence? = null
protected open fun getMessageRes(): Int? = null
protected open fun getMessageFormat(): Pair<Int, List<CharSequence>>? = null
protected open fun getView(): View? = null
open fun isCancelable() = true
open fun getPositiveButtonText(): Int? = null
open fun getNeutralButtonText(): Int? = null
open fun getNegativeButtonText(): Int? = null
protected open fun isCancelable() = true
protected open fun getPositiveButtonText(): Int? = null
protected open fun getNeutralButtonText(): Int? = null
protected open fun getNegativeButtonText(): Int? = null
protected open fun getItems(): Map<CharSequence, I>? = null
protected open fun getSingleChoiceItems(): Map<CharSequence, I>? = null
protected open fun getMultiChoiceItems(): Map<CharSequence, I>? = null
protected open fun getDefaultSelectedItem(): I? = null
protected open fun getDefaultSelectedItems(): Set<I> = emptySet()
open suspend fun onPositiveClick() = true
open suspend fun onNeutralClick() = true
open suspend fun onNegativeClick() = true
open suspend fun onSingleSelectionChanged(item: I?) = Unit
open suspend fun onMultiSelectionChanged(items: Set<I>) = Unit
protected open fun getInputType(): Int? = null
protected open fun getInputHint(): CharSequence? = null
protected open fun getInputHintRes(): Int? = null
protected open fun getInputValue(): CharSequence? = null
protected open suspend fun onPositiveClick() = DISMISS
protected open suspend fun onNeutralClick() = DISMISS
protected open suspend fun onNegativeClick() = DISMISS
protected open suspend fun onItemClick(item: I) = DISMISS
protected open suspend fun onSingleSelectionChanged(item: I) = Unit
protected open suspend fun onMultiSelectionChanged(item: I, isChecked: Boolean) = Unit
protected open suspend fun onInputTextChanged(input: TextInputEditText, text: Editable?) = Unit
protected open suspend fun onBeforeShow() = true
protected abstract suspend fun onShow()
protected open fun onDismiss() = Unit
protected open suspend fun onShow() = Unit
protected open suspend fun onDismiss() = Unit
fun show() {
fun show(): BaseDialog<I> {
if (activity.isFinishing)
return
onShowListener?.invoke(TAG)
app = activity.applicationContext as App
return this
job.cancel()
job = Job()
dialog = MaterialAlertDialogBuilder(activity)
.also(this::configure)
.setCancelable(isCancelable())
.setOnDismissListener {
onDismiss()
onDismissListener?.invoke(TAG)
launch {
dispatchOnDismiss()
job.cancel()
}
}
.create()
reload()
}
protected fun reload() {
launch {
if (activity.isFinishing)
return@launch
@ -93,10 +113,37 @@ abstract class BaseDialog<I : Any>(
dialog.dismiss()
return@launch
}
if (activity.isFinishing)
return@launch
dialog.show()
setButtons()
onShow()
dispatchOnShow()
}
return this
}
suspend fun showModal() = suspendCancellableCoroutine {
it.invokeOnCancellation {
dismiss()
}
continuation = it
show()
}
private suspend fun dispatchOnShow() {
if (activity.isFinishing)
return
EventBus.getDefault().registerSafe(this)
onShow()
}
private suspend fun dispatchOnDismiss() {
if (activity.isFinishing)
return
onDismiss()
EventBus.getDefault().unregisterSafe(this)
continuation?.resume(this)
continuation = null
}
private fun configure(md: MaterialAlertDialogBuilder) {
@ -106,6 +153,19 @@ abstract class BaseDialog<I : Any>(
getTitleRes()?.let {
md.setTitle(it)
}
getMessage()?.let {
md.setMessage(it)
}
getMessageRes()?.let {
md.setMessage(it)
}
getMessageFormat()?.let { (stringId, formatArgs) ->
md.setMessage(activity.getString(stringId, *formatArgs.toTypedArray()))
}
getView()?.let {
md.setView(it)
}
getPositiveButtonText()?.let {
md.setPositiveButton(it, null)
}
@ -116,26 +176,30 @@ abstract class BaseDialog<I : Any>(
md.setNegativeButton(it, null)
}
getMessage()?.let {
md.setMessage(it)
getItems()?.let { map ->
md.setItems(map.keys.toTypedArray()) { _, which ->
button = null
launch {
itemSelected = items[which]
if (onItemClick(items[which]))
dismiss()
}
}
items = map.values.toList()
itemSelected = null
md.setMessage(null)
}
getMessageRes()?.let {
md.setMessage(it)
}
getMessageFormat()?.let { (stringId, formatArgs) ->
md.setMessage(stringId, *formatArgs.toTypedArray())
}
getView()?.let {
md.setView(it)
}
getSingleChoiceItems()?.let { map ->
val default = getDefaultSelectedItem()
val defaultIndex = map.values.indexOf(default)
md.setSingleChoiceItems(map.keys.toTypedArray(), defaultIndex) { _, which ->
md.setSingleChoiceItems(
map.keys.toTypedArray(),
defaultIndex
) { _, which ->
button = null
launch {
itemSelected = items[which]
onSingleSelectionChanged(getSingleSelection())
onSingleSelectionChanged(items[which])
}
}
items = map.values.toList()
@ -147,44 +211,71 @@ abstract class BaseDialog<I : Any>(
val defaultStates = map.values.map {
it in default
}.toBooleanArray()
md.setMultiChoiceItems(map.keys.toTypedArray(),
defaultStates) { _, position, isChecked ->
md.setMultiChoiceItems(
map.keys.toTypedArray(),
defaultStates
) { _, position, isChecked ->
button = null
launch {
itemStates[position] = isChecked
onMultiSelectionChanged(getMultiSelection())
onMultiSelectionChanged(items[position], isChecked)
}
}
items = map.values.toList()
itemStates = defaultStates
md.setMessage(null)
}
getInputType()?.let { inputType ->
val b = DialogEditTextBinding.inflate(LayoutInflater.from(activity), null, false)
b.text1.let {
it.inputType = inputType
it.hint = getInputHint() ?: getInputHintRes()?.resolveString(activity)
it.setText(getInputValue() ?: "")
it.addTextChangedListener {
launch {
onInputTextChanged(b.text1, it)
}
}
}
input = b.text1
md.setView(b.root)
}
}
private fun setButtons() {
dialog.getButton(BUTTON_POSITIVE)?.onClick {
button = BUTTON_POSITIVE
launch {
if (onPositiveClick())
dialog.dismiss()
dismiss()
}
}
dialog.getButton(BUTTON_NEUTRAL)?.onClick {
button = BUTTON_NEUTRAL
launch {
if (onNeutralClick())
dialog.dismiss()
dismiss()
}
}
dialog.getButton(BUTTON_NEGATIVE)?.onClick {
button = BUTTON_NEGATIVE
launch {
if (onNegativeClick())
dialog.dismiss()
dismiss()
}
}
dialog.findViewById<TextView>(android.R.id.message)?.movementMethod =
BetterLinkMovementMethod.getInstance()
}
protected fun getSingleSelection() = itemSelected
protected fun getMultiSelection(): Set<I> {
fun getButton() = button
fun getItem() = itemSelected
fun getSingleSelection() = itemSelected
fun getMultiSelection(): Set<I> {
return itemStates.mapIndexed { position, isChecked ->
if (isChecked)
items[position]
@ -193,7 +284,9 @@ abstract class BaseDialog<I : Any>(
}.filterNotNull().toSet()
}
protected fun dismiss() {
fun getInput(): TextInputEditText? = input
fun dismiss() {
dialog.dismiss()
}
}

View File

@ -11,9 +11,7 @@ import androidx.viewbinding.ViewBinding
abstract class BindingDialog<B : ViewBinding>(
activity: AppCompatActivity,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : ViewDialog<View>(activity, onShowListener, onDismissListener) {
) : ViewDialog<View>(activity) {
protected lateinit var b: B
protected abstract fun inflate(layoutInflater: LayoutInflater): B

View File

@ -13,9 +13,7 @@ import pl.szczodrzynski.edziennik.R
abstract class ConfigDialog<B : ViewBinding>(
activity: AppCompatActivity,
private val reloadOnDismiss: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<B>(activity, onShowListener, onDismissListener) {
) : BindingDialog<B>(activity) {
final override fun getPositiveButtonText() = R.string.ok
final override suspend fun onShow() = Unit
@ -32,10 +30,8 @@ abstract class ConfigDialog<B : ViewBinding>(
return true
}
final override fun onDismiss() {
launch {
saveConfig()
}
final override suspend fun onDismiss() {
saveConfig()
if (reloadOnDismiss && activity is MainActivity)
activity.reloadTarget()
}

View File

@ -0,0 +1,258 @@
/*
* Copyright (c) Kuba Szczodrzyński 2024-7-5.
*/
package pl.szczodrzynski.edziennik.ui.base.dialog
import android.text.Editable
import android.text.InputType
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.textfield.TextInputEditText
import pl.szczodrzynski.edziennik.ext.resolveString
class SimpleDialog<I : Any>(
activity: AppCompatActivity,
config: SimpleDialog<I>.() -> Unit,
) : BaseDialog<I>(activity) {
init {
config()
}
private var title: CharSequence? = null
private var titleRes: Int? = null
private var message: CharSequence? = null
private var messageRes: Int? = null
private var messageFormat: Pair<Int, List<CharSequence>>? = null
private var isCancelable = true
private var positiveButtonText: Int? = null
private var neutralButtonText: Int? = null
private var negativeButtonText: Int? = null
private var items: Map<CharSequence, I>? = null
private var singleChoiceItems: Map<CharSequence, I>? = null
private var multiChoiceItems: Map<CharSequence, I>? = null
private var defaultSelectedItem: I? = null
private var defaultSelectedItems: Set<I>? = null
private var inputType: Int? = null
private var inputHint: CharSequence? = null
private var inputHintRes: Int? = null
private var inputValue: CharSequence? = null
private var onPositiveClick: (suspend () -> Unit)? = null
private var onNeutralClick: (suspend () -> Unit)? = null
private var onNegativeClick: (suspend () -> Unit)? = null
private var onItemClick: (suspend (item: I) -> Unit)? = null
private var onSingleSelectionChanged: (suspend (item: I) -> Unit)? = null
private var onMultiSelectionChanged: (suspend (item: I, isChecked: Boolean) -> Unit)? = null
private var onInputTextChanged: (suspend TextInputEditText.(text: Editable?) -> Unit)? = null
fun title(value: CharSequence) {
title = value
}
fun title(value: Int) {
titleRes = value
}
fun message(value: CharSequence) {
message = value
}
fun message(value: Int, vararg args: Any) {
if (args.isEmpty()) {
messageRes = value
} else {
messageFormat = value to args.map {
if (it is CharSequence) it else it.toString()
}
}
}
fun cancelable(value: Boolean) {
isCancelable = value
}
fun positive(text: Int, block: (suspend () -> Unit)? = null) {
positiveButtonText = text
onPositiveClick = block
}
fun neutral(text: Int, block: (suspend () -> Unit)? = null) {
neutralButtonText = text
onNeutralClick = block
}
fun negative(text: Int, block: (suspend () -> Unit)? = null) {
negativeButtonText = text
onNegativeClick = block
}
fun items(
items: Map<CharSequence, I>,
block: (suspend (item: I) -> Unit)? = null,
) {
this.items = items
onItemClick = block
}
fun itemsRes(
items: Map<Int, I>,
block: (suspend (item: I) -> Unit)? = null,
) {
this.items = items.mapKeys { (k, _) -> k.resolveString(activity) }
onItemClick = block
}
fun single(
items: Map<CharSequence, I>,
default: I? = null,
block: (suspend (item: I) -> Unit)? = null,
) {
singleChoiceItems = items
defaultSelectedItem = default
onSingleSelectionChanged = block
}
fun singleRes(
items: Map<Int, I>,
default: I? = null,
block: (suspend (item: I) -> Unit)? = null,
) {
singleChoiceItems = items.mapKeys { (k, _) -> k.resolveString(activity) }
defaultSelectedItem = default
onSingleSelectionChanged = block
}
fun multi(
items: Map<CharSequence, I>,
default: Set<I> = emptySet(),
block: (suspend (item: I, isChecked: Boolean) -> Unit)? = null,
) {
multiChoiceItems = items
defaultSelectedItems = default
onMultiSelectionChanged = block
}
fun multiRes(
items: Map<Int, I>,
default: Set<I> = emptySet(),
block: (suspend (item: I, isChecked: Boolean) -> Unit)? = null,
) {
singleChoiceItems = items.mapKeys { (k, _) -> k.resolveString(activity) }
defaultSelectedItems = default
onMultiSelectionChanged = block
}
fun items(
vararg items: Pair<CharSequence, I>,
block: (suspend (item: I) -> Unit)? = null,
) = items(items.toMap(), block)
fun itemsRes(
vararg items: Pair<Int, I>,
block: (suspend (item: I) -> Unit)? = null,
) = itemsRes(items.toMap(), block)
fun single(
vararg items: Pair<CharSequence, I>,
default: I? = null,
block: (suspend (item: I) -> Unit)? = null,
) = single(items.toMap(), default, block)
fun singleRes(
vararg items: Pair<Int, I>,
default: I? = null,
block: (suspend (item: I) -> Unit)? = null,
) = singleRes(items.toMap(), default, block)
fun multi(
vararg items: Pair<CharSequence, I>,
default: Set<I> = emptySet(),
block: (suspend (item: I, isChecked: Boolean) -> Unit)? = null,
) = multi(items.toMap(), default, block)
fun multiRes(
vararg items: Pair<Int, I>,
default: Set<I> = emptySet(),
block: (suspend (item: I, isChecked: Boolean) -> Unit)? = null,
) = multiRes(items.toMap(), default, block)
fun input(
type: Int = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE,
hint: CharSequence? = null,
value: CharSequence? = null,
block: (suspend TextInputEditText.(text: Editable?) -> Unit)? = null,
) {
inputType = type
inputHint = hint
inputValue = value
onInputTextChanged = block
}
fun inputRes(
type: Int,
hint: Int? = null,
value: CharSequence? = null,
block: (suspend TextInputEditText.(text: Editable?) -> Unit)? = null,
) {
inputType = type
inputHintRes = hint
inputValue = value
onInputTextChanged = block
}
override fun getTitle() = title
override fun getTitleRes() = titleRes
override fun getMessage() = message
override fun getMessageRes() = messageRes
override fun getMessageFormat() = messageFormat
override fun isCancelable() = isCancelable
override fun getPositiveButtonText() = positiveButtonText
override fun getNeutralButtonText() = neutralButtonText
override fun getNegativeButtonText() = negativeButtonText
override fun getItems() = items
override fun getSingleChoiceItems() = singleChoiceItems
override fun getMultiChoiceItems() = multiChoiceItems
override fun getDefaultSelectedItem() = defaultSelectedItem
override fun getDefaultSelectedItems() = defaultSelectedItems ?: setOf()
override fun getInputType() = inputType
override fun getInputHint() = inputHint
override fun getInputHintRes() = inputHintRes
override fun getInputValue() = inputValue
override suspend fun onPositiveClick(): Boolean {
onPositiveClick?.invoke()
return DISMISS
}
override suspend fun onNeutralClick(): Boolean {
onNeutralClick?.invoke()
return DISMISS
}
override suspend fun onNegativeClick(): Boolean {
onNegativeClick?.invoke()
return DISMISS
}
override suspend fun onItemClick(item: I): Boolean {
onItemClick?.invoke(item)
return DISMISS
}
override suspend fun onSingleSelectionChanged(item: I) {
onSingleSelectionChanged?.invoke(item)
}
override suspend fun onMultiSelectionChanged(item: I, isChecked: Boolean) {
onMultiSelectionChanged?.invoke(item, isChecked)
}
override suspend fun onInputTextChanged(input: TextInputEditText, text: Editable?) {
onInputTextChanged?.let { input.it(text) }
}
}

View File

@ -9,9 +9,7 @@ import androidx.appcompat.app.AppCompatActivity
abstract class ViewDialog<V : View>(
activity: AppCompatActivity,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null
) : BaseDialog<Any>(activity, onShowListener, onDismissListener) {
) : BaseDialog<Any>(activity) {
protected lateinit var root: V
protected abstract fun getRootView(): V

View File

@ -20,7 +20,9 @@ import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.data.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.registerSafe
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
import pl.szczodrzynski.edziennik.ext.unregisterSafe
import pl.szczodrzynski.edziennik.ui.login.LoginActivity
import pl.szczodrzynski.navlib.bottomsheet.items.IBottomSheetItem
import kotlin.coroutines.CoroutineContext
@ -86,11 +88,7 @@ abstract class BaseFragment<B : ViewBinding, A : AppCompatActivity>(
override fun onResume() {
super.onResume()
try {
EventBus.getDefault().register(this)
} catch (_: Exception) {
}
EventBus.getDefault().registerSafe(this)
if (!isAdded || isViewReady)
return
isViewReady = true
@ -109,10 +107,7 @@ abstract class BaseFragment<B : ViewBinding, A : AppCompatActivity>(
override fun onPause() {
super.onPause()
try {
EventBus.getDefault().unregister(this)
} catch (_: Exception) {
}
EventBus.getDefault().unregisterSafe(this)
}
final override fun onDestroyView() {

View File

@ -9,14 +9,13 @@ import android.content.ContextWrapper
import android.text.InputType
import android.util.AttributeSet
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Subject
import pl.szczodrzynski.edziennik.ext.crc16
import pl.szczodrzynski.edziennik.ext.input
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
class SubjectDropdown : TextInputDropDown {
@ -108,25 +107,25 @@ class SubjectDropdown : TextInputDropDown {
private fun customNameDialog() {
activity ?: return
MaterialAlertDialogBuilder(activity!!)
.setTitle("Własny przedmiot")
.input(
hint = "Nazwa",
SimpleDialog<Unit>(activity!!) {
title("Własny przedmiot")
input(
type = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE,
positiveButton = R.string.ok,
positiveListener = { _, input ->
customSubjectName = input
select(Item(
hint = "Nazwa",
)
positive(R.string.ok) {
customSubjectName = getInput()?.text?.toString() ?: ""
select(
Item(
-1L * customSubjectName.crc16(),
customSubjectName,
tag = customSubjectName
))
onCustomSubjectSelected?.invoke(customSubjectName)
true
}
)
.setNegativeButton(R.string.cancel, null)
.show()
)
)
onCustomSubjectSelected?.invoke(customSubjectName)
}
negative(R.string.cancel)
}.show()
}
/**

View File

@ -26,11 +26,7 @@ class RecaptchaDialog(
private val onSuccess: (recaptchaCode: String) -> Unit,
private val onFailure: (() -> Unit)? = null,
private val onServerError: (() -> Unit)? = null,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<RecaptchaDialogBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "RecaptchaDialog"
) : BindingDialog<RecaptchaDialogBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -72,7 +68,7 @@ class RecaptchaDialog(
b.image8.isChecked = false
}
override fun onDismiss() {
override suspend fun onDismiss() {
if (!success)
onFailure?.invoke()
}

View File

@ -20,10 +20,7 @@ class RecaptchaPromptDialog(
private val onSuccess: (recaptchaCode: String) -> Unit,
private val onCancel: (() -> Unit)?,
private val onServerError: (() -> Unit)? = null,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<RecaptchaViewBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "RecaptchaPromptDialog"
) : BindingDialog<RecaptchaViewBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -57,7 +54,7 @@ class RecaptchaPromptDialog(
b.progress.visibility = View.GONE
success = true
onSuccess(recaptchaCode)
dialog.dismiss()
dismiss()
},
onFailure = {
b.checkbox.background = checkboxBackground
@ -69,7 +66,7 @@ class RecaptchaPromptDialog(
}
}
override fun onDismiss() {
override suspend fun onDismiss() {
if (!success)
onCancel?.invoke()
}

View File

@ -5,19 +5,16 @@
package pl.szczodrzynski.edziennik.ui.debug
import android.os.Bundle
import android.os.Process
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged
import androidx.sqlite.db.SimpleSQLiteQuery
import com.chuckerteam.chucker.api.Chucker
import com.chuckerteam.chucker.api.Chucker.SCREEN_HTTP
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor
import pl.szczodrzynski.edziennik.data.config.Config
import pl.szczodrzynski.edziennik.data.db.entity.EventType.Companion.SOURCE_DEFAULT
@ -34,9 +31,9 @@ import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
import pl.szczodrzynski.edziennik.ext.takeValue
import pl.szczodrzynski.edziennik.ui.base.fragment.BaseFragment
import pl.szczodrzynski.edziennik.ui.dialogs.ProfileRemoveDialog
import pl.szczodrzynski.edziennik.ui.dialogs.RestartDialog
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
import pl.szczodrzynski.fslogin.decode
import kotlin.system.exitProcess
class LabPageFragment : BaseFragment<LabFragmentBinding, AppCompatActivity>(
inflater = LabFragmentBinding::inflate,
@ -100,16 +97,7 @@ class LabPageFragment : BaseFragment<LabFragmentBinding, AppCompatActivity>(
b.chucker.onChange { _, isChecked ->
app.config.enableChucker = isChecked
App.enableChucker = isChecked
MaterialAlertDialogBuilder(activity)
.setTitle("Restart")
.setMessage("Wymagany restart aplikacji")
.setPositiveButton(R.string.ok) { _, _ ->
Process.killProcess(Process.myPid())
Runtime.getRuntime().exit(0)
exitProcess(0)
}
.setCancelable(false)
.show()
RestartDialog(activity).show()
}
if (App.enableChucker) {
@ -122,16 +110,7 @@ class LabPageFragment : BaseFragment<LabFragmentBinding, AppCompatActivity>(
b.disableDebug.onClick {
app.config.devMode = false
App.devMode = false
MaterialAlertDialogBuilder(activity)
.setTitle("Restart")
.setMessage("Wymagany restart aplikacji")
.setPositiveButton(R.string.ok) { _, _ ->
Process.killProcess(Process.myPid())
Runtime.getRuntime().exit(0)
exitProcess(0)
}
.setCancelable(false)
.show()
RestartDialog(activity).show()
}
b.unarchive.onClick {

View File

@ -8,7 +8,6 @@ import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.google.gson.JsonParser
@ -18,6 +17,7 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.databinding.TemplateListPageFragmentBinding
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.base.fragment.BaseFragment
import pl.szczodrzynski.edziennik.ui.login.LoginActivity
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
@ -73,17 +73,16 @@ class LabProfileFragment : BaseFragment<TemplateListPageFragmentBinding, AppComp
objVal.isBoolean -> objVal.asBoolean.toString()
else -> objVal.asString
}
is Enum<*> -> objVal.toString()
else -> objVal.toString()
}
MaterialAlertDialogBuilder(activity)
.setTitle(item.key)
.input(
hint = "value",
value = value,
positiveButton = R.string.ok,
positiveListener = { _, input ->
SimpleDialog<Unit>(activity) {
title(item.key)
input(hint = "value", value = value)
positive(R.string.ok) {
val input = getInput()?.text?.toString() ?: return@positive
when (parent) {
is JsonObject -> {
val v = objVal as JsonPrimitive
@ -102,6 +101,7 @@ class LabProfileFragment : BaseFragment<TemplateListPageFragmentBinding, AppComp
else
app.config[objName] = input
}
else -> {
val field = parent::class.java.getDeclaredField(objName)
field.isAccessible = true
@ -127,12 +127,9 @@ class LabProfileFragment : BaseFragment<TemplateListPageFragmentBinding, AppComp
}
showJson()
return@input true
}
)
.setNegativeButton(R.string.cancel, null)
.show()
}
negative(R.string.cancel)
}.show()
}
catch (e: Exception) {
if (activity is MainActivity)

View File

@ -6,24 +6,19 @@ package pl.szczodrzynski.edziennik.ui.dialogs
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.DialogBellSyncBinding
import pl.szczodrzynski.edziennik.ext.resolveDrawable
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
import pl.szczodrzynski.edziennik.ui.base.dialog.BindingDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.utils.models.Time
class BellSyncDialog(
activity: AppCompatActivity,
private val bellTime: Time,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogBellSyncBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "BellSyncDialog"
) : BindingDialog<DialogBellSyncBinding>(activity) {
override fun getTitleRes() = R.string.bell_sync_title
override fun inflate(layoutInflater: LayoutInflater) =
@ -31,8 +26,6 @@ class BellSyncDialog(
override fun getNeutralButtonText() = R.string.cancel
private var counterJob: Job? = null
private val actualBellDiff: Pair<Time, Int>
get() {
val now = Time.getNow()
@ -48,30 +41,25 @@ class BellSyncDialog(
app.config.timetable.bellSyncDiff = bellDiff
app.config.timetable.bellSyncMultiplier = multiplier
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.bell_sync_title)
.setMessage(app.getString(R.string.bell_sync_results, bellDiffText))
.setPositiveButton(R.string.ok) { resultsDialog, _ ->
resultsDialog.dismiss()
dialog.dismiss()
SimpleDialog<Unit>(activity) {
title(R.string.bell_sync_title)
message(app.getString(R.string.bell_sync_results, bellDiffText))
positive(R.string.ok) {
this@BellSyncDialog.dismiss()
if (activity is MainActivity) activity.reloadTarget()
}
.show()
}.show()
}
if (Time.diff(Time.getNow(), bellTime) > Time(2, 0, 0)) { // Easter egg ^^
b.bellSyncButton.setImageDrawable(R.drawable.ic_bell_wtf.resolveDrawable(app)) // wtf
}
counterJob = startCoroutineTimer(repeatMillis = 500) {
startCoroutineTimer(repeatMillis = 500) {
val (bellDiff, multiplier) = actualBellDiff
val bellDiffText = (if (multiplier == -1) '-' else '+') + bellDiff.stringHMS
b.bellSyncHowto.text =
app.getString(R.string.bell_sync_howto, bellTime.stringHM, bellDiffText)
}
}
override fun onDismiss() {
counterJob?.cancel()
}
}

View File

@ -6,29 +6,26 @@ package pl.szczodrzynski.edziennik.ui.dialogs
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.databinding.DialogBellSyncTimeChooseBinding
import pl.szczodrzynski.edziennik.ui.base.dialog.BindingDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
class BellSyncTimeChooseDialog(
activity: AppCompatActivity,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogBellSyncTimeChooseBinding>(activity, onShowListener, onDismissListener) {
) : BindingDialog<DialogBellSyncTimeChooseBinding>(activity) {
companion object {
private const val MAX_DIFF_MINUTES = 10
}
override val TAG = "BellSyncTimeChooseDialog"
override fun getTitleRes() = R.string.bell_sync_title
override fun inflate(layoutInflater: LayoutInflater) =
DialogBellSyncTimeChooseBinding.inflate(layoutInflater)
@ -37,8 +34,6 @@ class BellSyncTimeChooseDialog(
override fun getNeutralButtonText() = R.string.reset
override fun getNegativeButtonText() = R.string.cancel
override suspend fun onShow() = Unit
private val today = Date.getToday()
private val selectedTime: Time?
get() = b.timeDropdown.selected?.tag as Time?
@ -51,20 +46,19 @@ class BellSyncTimeChooseDialog(
}
override suspend fun onNeutralClick(): Boolean {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.bell_sync_title)
.setMessage(R.string.bell_sync_reset_confirm)
.setPositiveButton(R.string.yes) { dialog, _ ->
SimpleDialog<Unit>(activity) {
title(R.string.bell_sync_title)
message(R.string.bell_sync_reset_confirm)
positive(R.string.yes) {
app.config.timetable.bellSyncDiff = null
app.config.timetable.bellSyncMultiplier = 0
dialog.dismiss()
reload()
this@BellSyncTimeChooseDialog.dismiss()
this@BellSyncTimeChooseDialog.show()
if (activity is MainActivity)
activity.reloadTarget()
}
.setNegativeButton(R.string.no, null)
.show()
negative(R.string.no)
}.show()
return NO_DISMISS
}
@ -127,11 +121,11 @@ class BellSyncTimeChooseDialog(
if (!checkForLessons(timeItems.map { it.tag as Time })) {
/* Synchronization not possible */
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.bell_sync_title)
.setMessage(R.string.bell_sync_cannot_now)
.setPositiveButton(R.string.ok, null)
.show()
SimpleDialog<Unit>(activity) {
title(R.string.bell_sync_title)
message(R.string.bell_sync_cannot_now)
positive(R.string.ok)
}.show()
return false
} else {
b.timeDropdown.clear()

View File

@ -15,17 +15,11 @@ import pl.szczodrzynski.edziennik.utils.html.BetterHtml
class ChangelogDialog(
activity: AppCompatActivity,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : ViewDialog<ScrollView>(activity, onShowListener, onDismissListener) {
override val TAG = "ChangelogDialog"
) : ViewDialog<ScrollView>(activity) {
override fun getTitleRes() = R.string.whats_new
override fun getPositiveButtonText() = R.string.close
override suspend fun onShow() = Unit
override fun getRootView(): ScrollView {
val textView = TextView(activity)
textView.setPadding(24.dp, 24.dp, 24.dp, 0)

View File

@ -19,11 +19,7 @@ class ErrorDetailsDialog(
activity: AppCompatActivity,
private val errors: List<ApiError>,
private val titleRes: Int = R.string.dialog_error_details_title,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<Any>(activity, onShowListener, onDismissListener) {
override val TAG = "ErrorDetailsDialog"
) : BaseDialog<Any>(activity) {
override fun getTitleRes() = titleRes
override fun getMessage() = errors.map {
@ -43,8 +39,6 @@ class ErrorDetailsDialog(
override fun getPositiveButtonText() = R.string.close
override fun getNeutralButtonText() = R.string.report
override suspend fun onShow() = Unit
private val api by lazy { SzkolnyApi(activity.applicationContext as App) }
override suspend fun onBeforeShow(): Boolean {

View File

@ -18,11 +18,7 @@ class ProfileRemoveDialog(
val profileName: String,
val noProfileRemoval: Boolean = false,
val onRemove: (() -> Unit)? = null,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<Any>(activity, onShowListener, onDismissListener) {
override val TAG = "ProfileRemoveDialog"
) : BaseDialog<Any>(activity) {
override fun getTitleRes() = R.string.profile_menu_remove_confirm
override fun getMessageFormat() =
@ -35,8 +31,6 @@ class ProfileRemoveDialog(
override fun getPositiveButtonText() = R.string.remove
override fun getNeutralButtonText() = R.string.cancel
override suspend fun onShow() = Unit
override suspend fun onPositiveClick(): Boolean {
withContext(Dispatchers.Default) {
val profileObject = app.db.profileDao().getByIdNow(profileId) ?: return@withContext

View File

@ -13,11 +13,7 @@ import pl.szczodrzynski.edziennik.ui.base.dialog.ViewDialog
class QrScannerDialog(
activity: AppCompatActivity,
val onCodeScanned: (text: String) -> Unit,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : ViewDialog<ZXingScannerView>(activity, onShowListener, onDismissListener) {
override val TAG = "QrScannerDialog"
) : ViewDialog<ZXingScannerView>(activity) {
override fun getTitleRes() = R.string.qr_scanner_dialog_title
override fun getPositiveButtonText() = R.string.close
@ -31,13 +27,13 @@ class QrScannerDialog(
override suspend fun onShow() {
root.setResultHandler {
root.stopCamera()
dialog.dismiss()
dismiss()
onCodeScanned(it.text)
}
root.startCamera()
}
override fun onDismiss() {
override suspend fun onDismiss() {
root.stopCamera()
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) Kuba Szczodrzyński 2024-7-5.
*/
package pl.szczodrzynski.edziennik.ui.dialogs
import android.os.Process
import androidx.appcompat.app.AppCompatActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import kotlin.system.exitProcess
class RestartDialog(
activity: AppCompatActivity,
) : BaseDialog<Unit>(activity) {
override fun getTitle() = "Restart"
override fun getMessage() = "Wymagany restart aplikacji"
override fun isCancelable() = false
override fun getPositiveButtonText() = R.string.ok
override suspend fun onPositiveClick(): Boolean {
Process.killProcess(Process.myPid())
Runtime.getRuntime().exit(0)
exitProcess(0)
}
}

View File

@ -22,11 +22,7 @@ class StyledTextDialog(
activity: AppCompatActivity,
val initialText: Editable?,
val onSuccess: (text: Editable) -> Unit,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<StyledTextDialogBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "StyledTextDialog"
) : BindingDialog<StyledTextDialogBinding>(activity) {
private lateinit var config: StylingConfig

View File

@ -15,16 +15,7 @@ import pl.szczodrzynski.edziennik.ui.base.dialog.ConfigDialog
class AgendaConfigDialog(
activity: AppCompatActivity,
reloadOnDismiss: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : ConfigDialog<DialogConfigAgendaBinding>(
activity,
reloadOnDismiss,
onShowListener,
onDismissListener,
) {
override val TAG = "AgendaConfigDialog"
) : ConfigDialog<DialogConfigAgendaBinding>(activity, reloadOnDismiss) {
override fun getTitleRes() = R.string.menu_agenda_config
override fun inflate(layoutInflater: LayoutInflater) =
@ -51,8 +42,6 @@ class AgendaConfigDialog(
b.eventSharingEnabled.isChecked = enabled
b.shareByDefault.isEnabled = enabled
},
onShowListener,
onDismissListener,
)
if (isChecked)
dialog.showEnableDialog()

View File

@ -10,10 +10,7 @@ import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
class AppLanguageDialog(
activity: AppCompatActivity,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<Any>(activity, onShowListener, onDismissListener) {
override val TAG = "AppLanguageDialog"
) : BaseDialog<Any>(activity) {
override fun getTitleRes() = R.string.app_language_dialog_title
override fun getMessage() = activity.getString(R.string.app_language_dialog_text)
@ -29,8 +26,6 @@ class AppLanguageDialog(
override fun getDefaultSelectedItem() = app.config.ui.language
override suspend fun onShow() = Unit
override suspend fun onPositiveClick(): Boolean {
val language = getSingleSelection() as? String ?: return DISMISS
if (language.isEmpty())

View File

@ -14,16 +14,7 @@ import pl.szczodrzynski.edziennik.ui.base.dialog.ConfigDialog
class AttendanceConfigDialog(
activity: AppCompatActivity,
reloadOnDismiss: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : ConfigDialog<AttendanceConfigDialogBinding>(
activity,
reloadOnDismiss,
onShowListener,
onDismissListener,
) {
override val TAG = "AttendanceConfigDialog"
) : ConfigDialog<AttendanceConfigDialogBinding>(activity, reloadOnDismiss) {
override fun getTitleRes() = R.string.menu_attendance_config
override fun inflate(layoutInflater: LayoutInflater) =

View File

@ -4,32 +4,33 @@
package pl.szczodrzynski.edziennik.ui.dialogs.settings
import android.view.LayoutInflater
import android.text.Editable
import android.text.InputType
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.addTextChangedListener
import com.google.android.material.textfield.TextInputEditText
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.DialogEditTextBinding
import pl.szczodrzynski.edziennik.ui.base.dialog.BindingDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import pl.szczodrzynski.edziennik.utils.models.Time
class BellSyncConfigDialog(
activity: AppCompatActivity,
private val onChangeListener: (() -> Unit)? = null,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogEditTextBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "BellSyncConfigDialog"
) : BaseDialog<Unit>(activity) {
override fun getTitleRes() = R.string.bell_sync_title
override fun inflate(layoutInflater: LayoutInflater) =
DialogEditTextBinding.inflate(layoutInflater)
override fun getMessageRes() = R.string.bell_sync_adjust_content
override fun getPositiveButtonText() = R.string.ok
override fun getNeutralButtonText() = R.string.reset
override fun getNegativeButtonText() = R.string.cancel
override fun getInputType() = InputType.TYPE_CLASS_TEXT
override fun getInputHint() = "±H:MM:SS"
override fun getInputValue() = app.config.timetable.bellSyncDiff?.let {
(if (app.config.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS
} ?: "+0:00:00"
private fun parse(input: String): Pair<Time, Int>? {
if (input.length < 8) {
return null
@ -47,24 +48,17 @@ class BellSyncConfigDialog(
return time to multiplier
}
override suspend fun onShow() {
b.title.setText(R.string.bell_sync_adjust_content)
b.text1.hint = "±H:MM:SS"
b.text1.setText(app.config.timetable.bellSyncDiff?.let {
(if (app.config.timetable.bellSyncMultiplier == -1) "-" else "+") + it.stringHMS
} ?: "+0:00:00")
b.text1.addTextChangedListener { text ->
val input = text?.toString()
b.textInputLayout.error =
if (input != null && parse(input) == null)
activity.getString(R.string.bell_sync_adjust_error)
else
null
}
override suspend fun onInputTextChanged(input: TextInputEditText, text: Editable?) {
val value = text?.toString()
input.error =
if (value != null && parse(value) == null)
activity.getString(R.string.bell_sync_adjust_error)
else
null
}
override suspend fun onPositiveClick(): Boolean {
val input = b.text1.text?.toString() ?: return NO_DISMISS
val input = getInput()?.text?.toString() ?: return NO_DISMISS
val parsed = parse(input)
if (parsed == null) {
Toast.makeText(activity, R.string.bell_sync_adjust_error, Toast.LENGTH_SHORT).show()

View File

@ -8,15 +8,8 @@ import android.annotation.SuppressLint
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import it.sephiroth.android.library.numberpicker.doOnStopTrackingTouch
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.DialogConfigGradesBinding
import pl.szczodrzynski.edziennik.ext.join
import pl.szczodrzynski.edziennik.ext.onChange
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.setOnSelectedListener
import pl.szczodrzynski.edziennik.ui.base.dialog.ConfigDialog
import pl.szczodrzynski.edziennik.core.manager.GradesManager.Companion.COLOR_MODE_DEFAULT
import pl.szczodrzynski.edziennik.core.manager.GradesManager.Companion.COLOR_MODE_WEIGHTED
import pl.szczodrzynski.edziennik.core.manager.GradesManager.Companion.ORDER_BY_DATE_DESC
@ -26,20 +19,18 @@ import pl.szczodrzynski.edziennik.core.manager.GradesManager.Companion.YEAR_1_AV
import pl.szczodrzynski.edziennik.core.manager.GradesManager.Companion.YEAR_1_SEM_2_AVG
import pl.szczodrzynski.edziennik.core.manager.GradesManager.Companion.YEAR_1_SEM_2_SEM
import pl.szczodrzynski.edziennik.core.manager.GradesManager.Companion.YEAR_ALL_GRADES
import pl.szczodrzynski.edziennik.databinding.DialogConfigGradesBinding
import pl.szczodrzynski.edziennik.ext.join
import pl.szczodrzynski.edziennik.ext.onChange
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.setOnSelectedListener
import pl.szczodrzynski.edziennik.ui.base.dialog.ConfigDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
class GradesConfigDialog(
activity: AppCompatActivity,
reloadOnDismiss: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : ConfigDialog<DialogConfigGradesBinding>(
activity,
reloadOnDismiss,
onShowListener,
onDismissListener,
) {
override val TAG = "GradesConfigDialog"
) : ConfigDialog<DialogConfigGradesBinding>(activity, reloadOnDismiss) {
override fun getTitleRes() = R.string.menu_grades_config
override fun inflate(layoutInflater: LayoutInflater) =
@ -155,11 +146,11 @@ class GradesConfigDialog(
}
b.averageWithoutWeightHelp.onClick {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.grades_config_average_without_weight)
.setMessage(R.string.grades_config_average_without_weight_message)
.setPositiveButton(R.string.ok, null)
.show()
SimpleDialog<Unit>(activity) {
title(R.string.grades_config_average_without_weight)
message(R.string.grades_config_average_without_weight_message)
positive(R.string.ok)
}.show()
}
}
}

View File

@ -13,16 +13,7 @@ import pl.szczodrzynski.edziennik.ui.base.dialog.ConfigDialog
class MessagesConfigDialog(
activity: AppCompatActivity,
reloadOnDismiss: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : ConfigDialog<MessagesConfigDialogBinding>(
activity,
reloadOnDismiss,
onShowListener,
onDismissListener,
) {
override val TAG = "MessagesConfigDialog"
) : ConfigDialog<MessagesConfigDialogBinding>(activity, reloadOnDismiss) {
override fun getTitleRes() = R.string.menu_messages_config
override fun inflate(layoutInflater: LayoutInflater) =

View File

@ -15,11 +15,7 @@ import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
class MiniMenuConfigDialog(
activity: AppCompatActivity,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<NavTarget>(activity, onShowListener, onDismissListener) {
override val TAG = "BellSyncTimeChooseDialog"
) : BaseDialog<NavTarget>(activity) {
override fun getTitleRes() = R.string.settings_theme_mini_drawer_buttons_dialog_title
override fun getMessageRes() = R.string.settings_theme_mini_drawer_buttons_dialog_text
@ -39,8 +35,6 @@ class MiniMenuConfigDialog(
override fun getDefaultSelectedItems() = app.config.ui.miniMenuButtons
override suspend fun onShow() = Unit
override suspend fun onPositiveClick(): Boolean {
app.config.ui.miniMenuButtons = getMultiSelection()
if (activity is MainActivity) {

View File

@ -5,19 +5,15 @@
package pl.szczodrzynski.edziennik.ui.dialogs.settings
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.enums.NotificationType
import pl.szczodrzynski.edziennik.ext.resolveString
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
class NotificationFilterDialog(
activity: AppCompatActivity,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<NotificationType>(activity, onShowListener, onDismissListener) {
override val TAG = "NotificationFilterDialog"
) : BaseDialog<NotificationType>(activity) {
override fun getTitleRes() = R.string.dialog_notification_filter_title
override fun getMessageRes() = R.string.dialog_notification_filter_text
@ -33,8 +29,6 @@ class NotificationFilterDialog(
.filter { it.enabledByDefault != null && it !in app.profile.config.sync.notificationFilter }
.toSet()
override suspend fun onShow() = Unit
override suspend fun onPositiveClick(): Boolean {
val enabledTypes = getMultiSelection()
val disabledTypes = NotificationType.values()
@ -43,15 +37,15 @@ class NotificationFilterDialog(
if (disabledTypes.any { it.enabledByDefault == true }) {
// warn user when he tries to disable some notifications
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.are_you_sure)
.setMessage(R.string.notification_filter_warning)
.setPositiveButton(R.string.ok) { _, _ ->
SimpleDialog<Unit>(activity) {
title(R.string.are_you_sure)
message(R.string.notification_filter_warning)
positive(R.string.ok) {
app.profile.config.sync.notificationFilter = disabledTypes
dismiss()
this@NotificationFilterDialog.dismiss()
}
.setNegativeButton(R.string.cancel, null)
.show()
negative(R.string.cancel)
}.show()
return NO_DISMISS
}

View File

@ -22,11 +22,7 @@ class ProfileConfigDialog(
activity: MainActivity,
private val profile: Profile,
private val onProfileSaved: ((profile: Profile) -> Unit)? = null,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogProfileConfigBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "ProfileConfigDialog"
) : BindingDialog<DialogProfileConfigBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -48,7 +44,7 @@ class ProfileConfigDialog(
R.attr.alertDialogStyle,
R.style.MaterialAlertDialog_Material3
)
val surface = MaterialColors.getColor(activity, R.attr.colorSurface, TAG)
val surface = MaterialColors.getColor(activity, R.attr.colorSurface, 0)
shape.setCornerSize(18.dp.toFloat())
shape.initializeElevationOverlay(activity)
shape.fillColor = ColorStateList.valueOf(surface)
@ -79,12 +75,12 @@ class ProfileConfigDialog(
b.logoutButton.onClick {
ProfileRemoveDialog(activity, profile.id, profile.name) {
profileRemoved = true
dialog.dismiss()
dismiss()
}.show()
}
}
override fun onDismiss() {
override suspend fun onDismiss() {
if (!profileRemoved && profileChanged) {
app.profileSave(profile)
onProfileSaved?.invoke(profile)

View File

@ -4,66 +4,39 @@
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 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.ext.resolveString
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import pl.szczodrzynski.edziennik.utils.models.Time
import kotlin.coroutines.CoroutineContext
class QuietHoursConfigDialog(
val activity: AppCompatActivity,
activity: AppCompatActivity,
val onChangeListener: (() -> Unit)? = null,
val onShowListener: ((tag: String) -> Unit)? = null,
val onDismissListener: ((tag: String) -> Unit)? = null
) : CoroutineScope {
) : BaseDialog<Int>(activity) {
companion object {
private const val TAG = "QuietHoursConfigDialog"
}
private lateinit var app: App
private lateinit var dialog: AlertDialog
override fun getTitleRes() = R.string.settings_sync_quiet_hours_dialog_title
override fun getNegativeButtonText() = R.string.cancel
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun getItems(): Map<CharSequence, Int> = mapOf(
R.string.settings_sync_quiet_hours_set_beginning.resolveString(activity) to 0,
R.string.settings_sync_quiet_hours_set_end.resolveString(activity) to 1,
)
// 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()
}}
override suspend fun onItemClick(item: Int): Boolean {
when (item) {
0 -> configStartTime()
1 -> configEndTime()
}
return NO_DISMISS
}
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)
@ -78,14 +51,9 @@ class QuietHoursConfigDialog(
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)
@ -100,8 +68,5 @@ class QuietHoursConfigDialog(
app.config.sync.quietHoursEnd = Time(picker.hour, picker.minute, 0)
onChangeListener?.invoke()
}
picker.addOnDismissListener {
onDismissListener?.invoke(TAG + "End")
}
}
}

View File

@ -4,9 +4,7 @@
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
@ -17,6 +15,8 @@ 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 pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
import kotlin.coroutines.CoroutineContext
@ -24,15 +24,10 @@ class RegistrationConfigDialog(
val activity: AppCompatActivity,
val profile: Profile,
val onChangeListener: (suspend (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 lateinit var dialog: BaseDialog<*>
private val job = Job()
override val coroutineContext: CoroutineContext
@ -47,75 +42,55 @@ class RegistrationConfigDialog(
}}
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) { _, _ ->
dialog = SimpleDialog<Unit>(activity) {
title(R.string.registration_config_event_sharing_title)
message(R.string.registration_config_event_sharing_text)
positive(R.string.i_agree) {
enableRegistration()
}
.setNegativeButton(R.string.cancel, null)
.setOnDismissListener {
onDismissListener?.invoke(TAG + "EventShare")
}
.show()
negative(R.string.cancel)
}.show()
}
fun showNoteShareDialog() {
onShowListener?.invoke(TAG + "NoteShare")
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.registration_config_note_sharing_title)
.setMessage(R.string.registration_config_note_sharing_text)
.setPositiveButton(R.string.i_agree) { _, _ ->
dialog = SimpleDialog<Unit>(activity) {
title(R.string.registration_config_note_sharing_title)
message(R.string.registration_config_note_sharing_text)
positive(R.string.i_agree) {
enableRegistration()
}
.setNegativeButton(R.string.cancel, null)
.setOnDismissListener {
onDismissListener?.invoke(TAG + "NoteShare")
}
.show()
negative(R.string.cancel)
}.show()
}
fun showEnableDialog() {
onShowListener?.invoke(TAG + "Enable")
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.registration_config_title)
.setMessage(BetterHtml.fromHtml(activity, R.string.registration_config_enable_text))
.setPositiveButton(R.string.i_agree) { _, _ ->
dialog = SimpleDialog<Unit>(activity) {
title(R.string.registration_config_title)
message(BetterHtml.fromHtml(activity, R.string.registration_config_enable_text))
positive(R.string.i_agree) {
enableRegistration()
}
.setNegativeButton(R.string.i_disagree, null)
.setOnDismissListener {
onDismissListener?.invoke(TAG + "Enable")
}
.show()
negative(R.string.i_disagree)
}.show()
}
fun showDisableDialog() {
onShowListener?.invoke(TAG + "Disable")
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.registration_config_title)
.setMessage(R.string.registration_config_disable_text)
.setPositiveButton(R.string.ok) { _, _ ->
dialog = SimpleDialog<Unit>(activity) {
title(R.string.registration_config_title)
message(R.string.registration_config_disable_text)
positive(R.string.ok) {
disableRegistration()
}
.setNegativeButton(R.string.cancel, null)
.setOnDismissListener {
onDismissListener?.invoke(TAG + "Disable")
}
.show()
negative(R.string.cancel)
}.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()
dialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(R.string.registration_config_enable_progress_text)
cancelable(false)
}.show()
withContext(Dispatchers.Default) {
profile.registration = Profile.REGISTRATION_ENABLED
@ -140,15 +115,11 @@ class RegistrationConfigDialog(
}
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()
dialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(R.string.registration_config_disable_progress_text)
cancelable(false)
}.show()
withContext(Dispatchers.Default) {
profile.registration = Profile.REGISTRATION_DISABLED

View File

@ -6,42 +6,27 @@ package pl.szczodrzynski.edziennik.ui.dialogs.settings
import android.text.InputType
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.ext.input
import pl.szczodrzynski.edziennik.ext.takeValue
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
class StudentNumberDialog(
val activity: AppCompatActivity,
val profile: Profile,
val onShowListener: ((tag: String) -> Unit)? = null,
val onDismissListener: ((tag: String) -> Unit)? = null
) {
companion object {
private const val TAG = "StudentNumberDialog"
}
activity: AppCompatActivity,
val profile: Profile,
) : BaseDialog<Unit>(activity) {
init { run {
if (activity.isFinishing)
return@run
onShowListener?.invoke(TAG)
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.card_lucky_number_set_title)
.input(
message = activity.getString(R.string.card_lucky_number_set_text),
type = InputType.TYPE_CLASS_NUMBER,
hint = null,
value = if (profile.studentNumber == -1) null else profile.studentNumber.toString(),
positiveButton = R.string.ok,
positiveListener = { _, input ->
profile.studentNumber = input.toIntOrNull() ?: -1
true
}
)
.setNegativeButton(R.string.cancel, null)
.setOnDismissListener {
onDismissListener?.invoke(TAG)
}
.show()
}}
override fun getTitleRes() = R.string.card_lucky_number_set_title
override fun getMessageRes() = R.string.card_lucky_number_set_text
override fun getPositiveButtonText() = R.string.ok
override fun getNegativeButtonText() = R.string.cancel
override fun getInputType() = InputType.TYPE_CLASS_NUMBER
override fun getInputValue() = profile.studentNumber.takeValue()?.toString()
override suspend fun onPositiveClick(): Boolean {
profile.studentNumber = getInput()?.text?.toString()?.toIntOrNull() ?: -1
app.profileSave(profile)
return DISMISS
}
}

View File

@ -14,11 +14,7 @@ import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
class SyncIntervalDialog(
activity: AppCompatActivity,
private val onChangeListener: (() -> Unit)? = null,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<Any>(activity, onShowListener, onDismissListener) {
override val TAG = "SyncIntervalDialog"
) : BaseDialog<Any>(activity) {
override fun getTitleRes() = R.string.settings_sync_sync_interval_dialog_title
override fun getMessageRes() = R.string.settings_sync_sync_interval_dialog_text
@ -39,8 +35,6 @@ class SyncIntervalDialog(
override fun getDefaultSelectedItem() = app.config.sync.interval.toLong()
override suspend fun onShow() = Unit
override suspend fun onPositiveClick(): Boolean {
val interval = getSingleSelection() as? Long ?: return DISMISS
app.config.sync.interval = interval.toInt()

View File

@ -11,11 +11,7 @@ import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
class ThemeChooserDialog(
activity: AppCompatActivity,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<Theme>(activity, onShowListener, onDismissListener) {
override val TAG = "ThemeChooserDialog"
) : BaseDialog<Theme>(activity) {
override fun getTitleRes() = R.string.settings_theme_theme_text
override fun getPositiveButtonText() = R.string.ok
@ -26,8 +22,6 @@ class ThemeChooserDialog(
override fun getDefaultSelectedItem() = app.uiManager.themeColor
override suspend fun onShow() = Unit
override suspend fun onPositiveClick(): Boolean {
val themeColor = getSingleSelection() ?: return DISMISS
if (app.uiManager.themeColor != themeColor) {

View File

@ -15,16 +15,7 @@ import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment
class TimetableConfigDialog(
activity: AppCompatActivity,
reloadOnDismiss: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : ConfigDialog<TimetableConfigDialogBinding>(
activity,
reloadOnDismiss,
onShowListener,
onDismissListener,
) {
override val TAG = "TimetableConfigDialog"
) : ConfigDialog<TimetableConfigDialogBinding>(activity, reloadOnDismiss) {
override fun getTitleRes() = R.string.menu_timetable_config
override fun inflate(layoutInflater: LayoutInflater) =

View File

@ -19,11 +19,7 @@ import pl.szczodrzynski.edziennik.utils.Utils
class RegisterUnavailableDialog(
activity: AppCompatActivity,
private val status: RegisterAvailabilityStatus,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogRegisterUnavailableBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "RegisterUnavailableDialog"
) : BindingDialog<DialogRegisterUnavailableBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -43,8 +39,6 @@ class RegisterUnavailableDialog(
activity = activity,
update = update,
mandatory = update != null && update.versionCode >= status.minVersionCode,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
return false
}

View File

@ -12,16 +12,9 @@ class ServerMessageDialog(
activity: AppCompatActivity,
private val titleText: String,
private val messageText: CharSequence,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<Any>(activity, onShowListener, onDismissListener) {
override val TAG = "ServerMessageDialog"
) : BaseDialog<Any>(activity) {
override fun getTitle() = titleText
override fun getTitleRes(): Int? = null
override fun getMessage() = messageText
override fun getPositiveButtonText() = R.string.close
override suspend fun onShow() = Unit
}

View File

@ -19,11 +19,7 @@ import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment
class SyncViewListDialog(
activity: MainActivity,
private val currentNavTarget: NavTarget,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<FeatureType>(activity, onShowListener, onDismissListener) {
override val TAG = "SyncViewListDialog"
) : BaseDialog<FeatureType>(activity) {
override fun getTitleRes() = R.string.dialog_sync_view_list_title
override fun getPositiveButtonText() = R.string.ok
@ -44,8 +40,6 @@ class SyncViewListDialog(
else -> currentNavTarget.featureType?.let { setOf(it) } ?: getMultiChoiceItems().values.toSet()
}
override suspend fun onShow() = Unit
@Suppress("UNCHECKED_CAST")
override suspend fun onPositiveClick(): Boolean {
val selected = getMultiSelection()

View File

@ -18,11 +18,7 @@ class UpdateAvailableDialog(
activity: AppCompatActivity,
private val update: Update?,
private val mandatory: Boolean = update?.updateMandatory ?: false,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<Any>(activity, onShowListener, onDismissListener) {
override val TAG = "UpdateAvailableDialog"
) : BaseDialog<Any>(activity) {
override fun getTitleRes() = R.string.update_available_title
override fun getMessageFormat(): Pair<Int, List<CharSequence>> {
@ -40,8 +36,6 @@ class UpdateAvailableDialog(
override fun getPositiveButtonText() = R.string.update_available_button
override fun getNeutralButtonText() = if (mandatory) null else R.string.update_available_later
override suspend fun onShow() = Unit
override suspend fun onPositiveClick(): Boolean {
if (update == null || update.isOnGooglePlay)
Utils.openGooglePlay(activity)

View File

@ -9,7 +9,6 @@ import android.database.CursorIndexOutOfBoundsException
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
import kotlinx.coroutines.Job
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@ -26,11 +25,7 @@ class UpdateProgressDialog(
activity: AppCompatActivity,
private val update: Update,
private val downloadId: Long,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<UpdateProgressDialogBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "UpdateProgressDialog"
) : BindingDialog<UpdateProgressDialogBinding>(activity) {
override fun getTitleRes() = R.string.notification_downloading_update
override fun inflate(layoutInflater: LayoutInflater) =
@ -39,8 +34,6 @@ class UpdateProgressDialog(
override fun isCancelable() = false
override fun getNegativeButtonText() = R.string.cancel
private var timerJob: Job? = null
override suspend fun onShow() {
EventBus.getDefault().register(this)
b.update = update
@ -49,8 +42,7 @@ class UpdateProgressDialog(
val downloadManager = app.getSystemService<DownloadManager>() ?: return
val query = DownloadManager.Query().setFilterById(downloadId)
timerJob?.cancel()
timerJob = startCoroutineTimer(repeatMillis = 100L) {
startCoroutineTimer(repeatMillis = 100L) {
try {
val cursor = downloadManager.query(query)
cursor.moveToFirst()
@ -65,11 +57,6 @@ class UpdateProgressDialog(
}
}
override fun onDismiss() {
EventBus.getDefault().unregister(this)
timerJob?.cancel()
}
override suspend fun onNegativeClick(): Boolean {
val downloadManager = app.getSystemService<DownloadManager>() ?: return NO_DISMISS
downloadManager.remove(downloadId)

View File

@ -11,24 +11,38 @@ import android.provider.CalendarContract.Events
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.databinding.DialogEventDetailsBinding
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.data.enums.NavTarget
import pl.szczodrzynski.edziennik.databinding.DialogEventDetailsBinding
import pl.szczodrzynski.edziennik.ext.Bundle
import pl.szczodrzynski.edziennik.ext.asColoredSpannable
import pl.szczodrzynski.edziennik.ext.attachToastHint
import pl.szczodrzynski.edziennik.ext.concat
import pl.szczodrzynski.edziennik.ext.isNotNullNorBlank
import pl.szczodrzynski.edziennik.ext.onChange
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.putExtras
import pl.szczodrzynski.edziennik.ext.resolveAttr
import pl.szczodrzynski.edziennik.ext.setText
import pl.szczodrzynski.edziennik.ext.setTintColor
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.BindingDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.notes.setupNotesButton
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment
import pl.szczodrzynski.edziennik.utils.BetterLink
@ -40,11 +54,7 @@ class EventDetailsDialog(
// this event is observed for changes
private var event: EventFull,
private val showNotes: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogEventDetailsBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "EventDetailsDialog"
) : BindingDialog<DialogEventDetailsBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -53,7 +63,6 @@ class EventDetailsDialog(
override fun getPositiveButtonText() = R.string.close
override fun getNeutralButtonText() = if (event.addedManually) R.string.remove else null
private var removeEventDialog: AlertDialog? = null
private val eventShared = event.sharedBy != null
private val eventOwn = event.sharedBy == "self"
private val manager
@ -63,18 +72,13 @@ class EventDetailsDialog(
SzkolnyApi(app)
}
private var progressDialog: AlertDialog? = null
private var progressDialog: BaseDialog<*>? = null
override suspend fun onNeutralClick(): Boolean {
showRemoveEventDialog()
return NO_DISMISS
}
override suspend fun onBeforeShow(): Boolean {
EventBus.getDefault().register(this)
return true
}
override suspend fun onShow() {
// watch the event for changes
app.db.eventDao().getById(event.profileId, event.id).observe(activity) {
@ -83,8 +87,7 @@ class EventDetailsDialog(
}
}
override fun onDismiss() {
EventBus.getDefault().unregister(this@EventDetailsDialog)
override suspend fun onDismiss() {
progressDialog?.dismiss()
}
@ -150,22 +153,22 @@ class EventDetailsDialog(
b.checkDoneButton.onChange { _, isChecked ->
if (isChecked && !event.isDone) {
b.checkDoneButton.isChecked = false
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.event_mark_as_done_title)
.setMessage(R.string.event_mark_as_done_text)
.setPositiveButton(R.string.ok) { _, _ ->
event.isDone = isChecked
launch(Dispatchers.Default) {
app.db.eventDao().replace(event)
}
update()
b.checkDoneButton.isChecked = true
SimpleDialog<Unit>(activity) {
title(R.string.event_mark_as_done_title)
message(R.string.event_mark_as_done_text)
positive(R.string.ok) {
event.isDone = true
withContext(Dispatchers.IO) {
app.db.eventDao().replace(event)
}
.setNegativeButton(R.string.cancel, null)
.show()
update()
b.checkDoneButton.isChecked = true
}
negative(R.string.cancel)
}.show()
}
else if (!isChecked && event.isDone) {
event.isDone = isChecked
event.isDone = false
launch(Dispatchers.Default) {
app.db.eventDao().replace(event)
}
@ -183,15 +186,13 @@ class EventDetailsDialog(
editingEvent = event,
onSaveListener = {
if (it == null) {
dialog.dismiss()
dismiss()
return@EventManualDialog
}
// this should not be needed as the event is observed by the ID
// event = it
// update()
},
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
}
b.editButton.attachToastHint(R.string.hint_edit_event)
@ -204,7 +205,7 @@ class EventDetailsDialog(
// GO TO TIMETABLE
b.goToTimetableButton.onClick {
dialog.dismiss()
dismiss()
val dateStr = event.date.stringY_m_d
val intent =
@ -235,13 +236,13 @@ class EventDetailsDialog(
}
b.downloadButton.attachToastHint(R.string.hint_download_again)
BetterLink.attach(b.topic, onActionSelected = dialog::dismiss)
BetterLink.attach(b.topic, onActionSelected = ::dismiss)
event.teacherName?.let { name ->
BetterLink.attach(
b.teacherName,
teachers = mapOf(event.teacherId to name),
onActionSelected = dialog::dismiss
onActionSelected = ::dismiss
)
}
@ -260,7 +261,7 @@ class EventDetailsDialog(
b.bodyTitle.isVisible = true
b.bodyProgressBar.isVisible = false
b.body.isVisible = true
BetterLink.attach(b.body, onActionSelected = dialog::dismiss)
BetterLink.attach(b.body, onActionSelected = ::dismiss)
}
if (event.attachmentIds.isNullOrEmpty() || event.attachmentNames.isNullOrEmpty()) {
@ -281,8 +282,6 @@ class EventDetailsDialog(
b.notesButton.setupNotesButton(
activity = activity,
owner = event,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
)
}
@ -299,11 +298,11 @@ class EventDetailsDialog(
return
}
progressDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.please_wait)
.setMessage(R.string.event_removing_text)
.setCancelable(false)
.show()
progressDialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(R.string.event_removing_text)
cancelable(false)
}.show()
}
private fun showRemoveEventDialog() {
@ -312,22 +311,14 @@ class EventDetailsDialog(
eventShared && !eventOwn -> "\n\n"+activity.getString(R.string.dialog_event_manual_remove_shared)
else -> ""
}
removeEventDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.are_you_sure)
.setMessage(activity.getString(R.string.dialog_register_event_manual_remove_confirmation)+shareNotice)
.setPositiveButton(R.string.yes, null)
.setNegativeButton(R.string.no) { dialog, _ -> dialog.dismiss() }
.create()
.apply {
setOnShowListener { dialog ->
val positiveButton = (dialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
positiveButton?.setOnClickListener {
removeEvent()
}
}
show()
}
SimpleDialog<Unit>(activity) {
title(R.string.are_you_sure)
message(activity.getString(R.string.dialog_register_event_manual_remove_confirmation) + shareNotice)
positive(R.string.yes) {
removeEvent()
}
negative(R.string.no)
}.show()
}
private fun removeEvent() {
@ -364,8 +355,7 @@ class EventDetailsDialog(
}
}
removeEventDialog?.dismiss()
dialog.dismiss()
dismiss()
Toast.makeText(activity, R.string.removed, Toast.LENGTH_SHORT).show()
}

View File

@ -8,33 +8,32 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.jaredrummler.android.colorpicker.ColorPickerDialog
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.config.AppData
import pl.szczodrzynski.edziennik.core.manager.TextStylingManager.HtmlMode.SIMPLE
import pl.szczodrzynski.edziennik.core.manager.TextStylingManager.StylingConfigBase
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskFinishedEvent
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
import pl.szczodrzynski.edziennik.data.config.AppData
import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Subject
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.data.enums.MetadataType
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.data.enums.MetadataType
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
import pl.szczodrzynski.edziennik.ext.JsonObject
import pl.szczodrzynski.edziennik.ext.appendView
@ -44,13 +43,13 @@ import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.removeFromParent
import pl.szczodrzynski.edziennik.ext.setText
import pl.szczodrzynski.edziennik.ext.setTintColor
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.BindingDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.RegistrationConfigDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.base.views.TimeDropdown.Companion.DISPLAY_LESSONS
import pl.szczodrzynski.edziennik.ui.dialogs.settings.RegistrationConfigDialog
import pl.szczodrzynski.edziennik.utils.Anim
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
import pl.szczodrzynski.edziennik.core.manager.TextStylingManager.HtmlMode.SIMPLE
import pl.szczodrzynski.edziennik.core.manager.TextStylingManager.StylingConfigBase
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
@ -64,11 +63,7 @@ class EventManualDialog(
private val defaultType: Long? = null,
private val editingEvent: EventFull? = null,
private val onSaveListener: ((event: EventFull?) -> Unit)? = null,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogEventManualV2Binding>(activity, onShowListener, onDismissListener) {
override val TAG = "EventManualDialog"
) : BindingDialog<DialogEventManualV2Binding>(activity) {
override fun getTitleRes() = R.string.dialog_event_manual_title
override fun inflate(layoutInflater: LayoutInflater) =
@ -94,10 +89,10 @@ class EventManualDialog(
SzkolnyApi(app)
}
private var enqueuedWeekDialog: AlertDialog? = null
private var enqueuedWeekDialog: BaseDialog<*>? = null
private var enqueuedWeekStart = Date.getToday()
private var progressDialog: AlertDialog? = null
private var progressDialog: BaseDialog<*>? = null
override suspend fun onPositiveClick(): Boolean {
saveEvent()
@ -109,13 +104,7 @@ class EventManualDialog(
return NO_DISMISS
}
override suspend fun onBeforeShow(): Boolean {
EventBus.getDefault().register(this@EventManualDialog)
return true
}
override fun onDismiss() {
EventBus.getDefault().unregister(this@EventManualDialog)
override suspend fun onDismiss() {
enqueuedWeekDialog?.dismiss()
progressDialog?.dismiss()
}
@ -145,8 +134,6 @@ class EventManualDialog(
activity = activity,
textLayout = b.topicLayout,
textEdit = b.topic,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
)
stylingConfig = StylingConfigBase(editText = b.topic, htmlMode = SIMPLE)
@ -187,11 +174,11 @@ class EventManualDialog(
return
}
val weekStart = date.weekStart
enqueuedWeekDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.please_wait)
.setMessage(R.string.timetable_syncing_text)
.setCancelable(false)
.show()
enqueuedWeekDialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(R.string.timetable_syncing_text)
cancelable(false)
}.show()
enqueuedWeekStart = weekStart
@ -209,11 +196,11 @@ class EventManualDialog(
return
}
progressDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.please_wait)
.setMessage(R.string.event_sharing_text)
.setCancelable(false)
.show()
progressDialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(R.string.event_sharing_text)
cancelable(false)
}.show()
}
private fun showRemovingProgressDialog() {
@ -221,11 +208,11 @@ class EventManualDialog(
return
}
progressDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.please_wait)
.setMessage(R.string.event_removing_text)
.setCancelable(false)
.show()
progressDialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(R.string.event_removing_text)
cancelable(false)
}.show()
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -399,22 +386,14 @@ class EventManualDialog(
editingShared && !editingOwn -> "\n\n"+activity.getString(R.string.dialog_event_manual_remove_shared)
else -> ""
}
removeEventDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.are_you_sure)
.setMessage(activity.getString(R.string.dialog_register_event_manual_remove_confirmation)+shareNotice)
.setPositiveButton(R.string.yes, null)
.setNegativeButton(R.string.no) { dialog, _ -> dialog.dismiss() }
.create()
.apply {
setOnShowListener { dialog ->
val positiveButton = (dialog as AlertDialog).getButton(BUTTON_POSITIVE)
positiveButton?.setOnClickListener {
removeEvent()
}
}
show()
}
SimpleDialog<Unit>(activity) {
title(R.string.are_you_sure)
message(activity.getString(R.string.dialog_register_event_manual_remove_confirmation) + shareNotice)
positive(R.string.yes) {
removeEvent()
}
negative(R.string.no)
}.show()
}
private fun saveEvent() {

View File

@ -24,11 +24,7 @@ class GradeDetailsDialog(
activity: AppCompatActivity,
private val grade: GradeFull,
private val showNotes: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogGradeDetailsBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "GradeDetailsDialog"
) : BindingDialog<DialogGradeDetailsBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -67,7 +63,7 @@ class GradeDetailsDialog(
BetterLink.attach(
b.teacherName,
teachers = mapOf(grade.teacherId to name),
onActionSelected = dialog::dismiss
onActionSelected = ::dismiss
)
}
@ -98,8 +94,6 @@ class GradeDetailsDialog(
b.notesButton.setupNotesButton(
activity = activity,
owner = grade,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
)
b.legend.isVisible = showNotes
if (showNotes)

View File

@ -45,7 +45,7 @@ class GradesListFragment : BaseFragment<GradesListFragmentBinding, MainActivity>
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
GradesConfigDialog(activity, true, null, null).show()
GradesConfigDialog(activity, true).show()
},
)

View File

@ -14,14 +14,14 @@ import com.daimajia.swipe.SwipeLayout
import com.mikepenz.iconics.view.IconicsImageView
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.ui.grades.editor.GradesEditorFragment.Companion.modifyGradeChooser
import pl.szczodrzynski.edziennik.utils.Colors.gradeNameToColor
import java.text.DecimalFormat
class GradesEditorAdapter(
private val mContext: Context,
private val gradeList: List<GradesEditorFragment.EditorGrade>,
private val listener: OnGradeActionListener
private val fragment: GradesEditorFragment,
private val listener: OnGradeActionListener,
) : RecyclerView.Adapter<GradesEditorAdapter.ViewHolder>() {
interface OnGradeActionListener {
@ -94,7 +94,7 @@ class GradesEditorAdapter(
holder.buttonRemove.setOnClickListener { listener.onClickRemove(editorGrade.id) }
holder.buttonEdit.setOnClickListener { v -> modifyGradeChooser(v, editorGrade) { listener.onClickEdit(editorGrade.id) } }
holder.buttonEdit.setOnClickListener { v -> fragment.modifyGradeChooser(v, editorGrade) { listener.onClickEdit(editorGrade.id) } }
}
override fun getItemCount(): Int {

View File

@ -8,7 +8,6 @@ import android.view.View
import androidx.appcompat.widget.PopupMenu
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
@ -21,7 +20,7 @@ import pl.szczodrzynski.edziennik.databinding.FragmentGradesEditorBinding
import pl.szczodrzynski.edziennik.ext.getFloat
import pl.szczodrzynski.edziennik.ext.getInt
import pl.szczodrzynski.edziennik.ext.getLong
import pl.szczodrzynski.edziennik.ext.input
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.base.fragment.BaseFragment
import pl.szczodrzynski.edziennik.utils.Colors
import timber.log.Timber
@ -59,11 +58,13 @@ class GradesEditorFragment : BaseFragment<FragmentGradesEditorBinding, MainActiv
semester = arguments.getInt("semester", 1)
if (subjectId == -1L) {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.error_occured)
.setMessage(R.string.error_no_subject_id)
.setPositiveButton(R.string.ok) { _, _ -> activity.navigateUp() }
.show()
SimpleDialog<Unit>(activity) {
title(R.string.error_occured)
message(R.string.error_no_subject_id)
positive(R.string.ok) {
activity.navigateUp()
}
}.show()
return
}
@ -78,7 +79,7 @@ class GradesEditorFragment : BaseFragment<FragmentGradesEditorBinding, MainActiv
b.listView.setHasFixedSize(false)
b.listView.isNestedScrollingEnabled = false
b.listView.layoutManager = LinearLayoutManager(context)
b.listView.adapter = GradesEditorAdapter(context!!, editorGrades, object : GradesEditorAdapter.OnGradeActionListener {
b.listView.adapter = GradesEditorAdapter(requireContext(), editorGrades, this, object : GradesEditorAdapter.OnGradeActionListener {
override fun onClickRemove(gradeId: Long) {
gradeSumSemester = 0f
gradeCountSemester = 0f
@ -179,11 +180,13 @@ class GradesEditorFragment : BaseFragment<FragmentGradesEditorBinding, MainActiv
app.db.subjectDao().getById(App.profileId, subjectId).observe(this, Observer { subject ->
if (subject == null || subject.id == -1L) {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.error_occured)
.setMessage(R.string.error_no_subject_id)
.setPositiveButton(R.string.ok) { _, _ -> activity.navigateUp() }
.show()
SimpleDialog<Unit>(activity) {
title(R.string.error_occured)
message(R.string.error_no_subject_id)
positive(R.string.ok) {
activity.navigateUp()
}
}.show()
return@Observer
}
@ -248,98 +251,92 @@ class GradesEditorFragment : BaseFragment<FragmentGradesEditorBinding, MainActiv
var weight: Float
)
companion object {
fun modifyGradeChooser(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
val popup = PopupMenu(v.context, v)
popup.menu.add(0, 0, 0, R.string.grades_editor_change_grade)
popup.menu.add(0, 1, 1, R.string.grades_editor_change_weight)
fun modifyGradeChooser(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
val popup = PopupMenu(v.context, v)
popup.menu.add(0, 0, 0, R.string.grades_editor_change_grade)
popup.menu.add(0, 1, 1, R.string.grades_editor_change_weight)
popup.setOnMenuItemClickListener { item ->
if (item.itemId == 0) {
modifyGradeName(v, editorGrade, callback)
}
if (item.itemId == 1) {
modifyGradeWeight(v, editorGrade, callback)
}
true
popup.setOnMenuItemClickListener { item ->
if (item.itemId == 0) {
modifyGradeName(v, editorGrade, callback)
}
popup.show()
}
fun addGradeHandler(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
modifyGradeName(v, editorGrade) {
if (item.itemId == 1) {
modifyGradeWeight(v, editorGrade, callback)
}
true
}
fun modifyGradeName(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
val popup = PopupMenu(v.context, v)
popup.menu.add(0, 75, 0, "1-")
popup.menu.add(0, 100, 1, "1")
popup.menu.add(0, 150, 2, "1+")
popup.menu.add(0, 175, 3, "2-")
popup.menu.add(0, 200, 4, "2")
popup.menu.add(0, 250, 5, "2+")
popup.menu.add(0, 275, 6, "3-")
popup.menu.add(0, 300, 7, "3")
popup.menu.add(0, 350, 8, "3+")
popup.menu.add(0, 375, 9, "4-")
popup.menu.add(0, 400, 10, "4")
popup.menu.add(0, 450, 11, "4+")
popup.menu.add(0, 475, 12, "5-")
popup.menu.add(0, 500, 13, "5")
popup.menu.add(0, 550, 14, "5+")
popup.menu.add(0, 575, 15, "6-")
popup.menu.add(0, 600, 16, "6")
popup.menu.add(0, 650, 17, "6+")
popup.menu.add(0, 0, 18, "0")
popup.show()
}
popup.setOnMenuItemClickListener { item ->
editorGrade.name = item.title.toString()
editorGrade.value = item.itemId.toFloat() / 100
callback()
true
}
popup.show()
}
fun modifyGradeWeight(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
val popup = PopupMenu(v.context, v)
for (i in 0..6) {
popup.menu.add(0, i, i, v.context.getString(R.string.grades_editor_weight_format, DecimalFormat("#.##").format(i.toLong())))
}
popup.menu.add(1, 100, 100, v.context.getString(R.string.grades_editor_weight_other))
popup.setOnMenuItemClickListener { item ->
if (item.itemId == 100) {
MaterialAlertDialogBuilder(v.context)
.setTitle(R.string.grades_editor_add_grade_title)
.input(
message = v.context.getString(R.string.grades_editor_add_grade_weight),
type = InputType.TYPE_NUMBER_FLAG_SIGNED,
positiveButton = R.string.ok,
positiveListener = { _, input ->
try {
editorGrade.weight = input.toFloat()
callback()
} catch (e: Exception) {
Timber.e(e)
}
true
}
)
.setNegativeButton(R.string.cancel, null)
.show()
} else {
editorGrade.weight = item.itemId.toFloat()
callback()
}
true
}
popup.show()
fun addGradeHandler(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
modifyGradeName(v, editorGrade) {
modifyGradeWeight(v, editorGrade, callback)
}
}
fun modifyGradeName(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
val popup = PopupMenu(v.context, v)
popup.menu.add(0, 75, 0, "1-")
popup.menu.add(0, 100, 1, "1")
popup.menu.add(0, 150, 2, "1+")
popup.menu.add(0, 175, 3, "2-")
popup.menu.add(0, 200, 4, "2")
popup.menu.add(0, 250, 5, "2+")
popup.menu.add(0, 275, 6, "3-")
popup.menu.add(0, 300, 7, "3")
popup.menu.add(0, 350, 8, "3+")
popup.menu.add(0, 375, 9, "4-")
popup.menu.add(0, 400, 10, "4")
popup.menu.add(0, 450, 11, "4+")
popup.menu.add(0, 475, 12, "5-")
popup.menu.add(0, 500, 13, "5")
popup.menu.add(0, 550, 14, "5+")
popup.menu.add(0, 575, 15, "6-")
popup.menu.add(0, 600, 16, "6")
popup.menu.add(0, 650, 17, "6+")
popup.menu.add(0, 0, 18, "0")
popup.setOnMenuItemClickListener { item ->
editorGrade.name = item.title.toString()
editorGrade.value = item.itemId.toFloat() / 100
callback()
true
}
popup.show()
}
fun modifyGradeWeight(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
val popup = PopupMenu(v.context, v)
for (i in 0..6) {
popup.menu.add(0, i, i, v.context.getString(R.string.grades_editor_weight_format, DecimalFormat("#.##").format(i.toLong())))
}
popup.menu.add(1, 100, 100, v.context.getString(R.string.grades_editor_weight_other))
popup.setOnMenuItemClickListener { item ->
if (item.itemId == 100) {
SimpleDialog<Unit>(activity) {
title(R.string.grades_editor_add_grade_title)
message(R.string.grades_editor_add_grade_weight)
input(InputType.TYPE_NUMBER_FLAG_SIGNED)
positive(R.string.ok) {
try {
editorGrade.weight = getInput()?.text?.toString()?.toFloat() ?: 0.0f
callback()
} catch (e: Exception) {
Timber.e(e)
}
}
negative(R.string.cancel)
}.show()
} else {
editorGrade.weight = item.itemId.toFloat()
callback()
}
true
}
popup.show()
}
}

View File

@ -10,11 +10,11 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.GradesItemStatsBinding
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
import pl.szczodrzynski.edziennik.ui.grades.GradesAdapter
import pl.szczodrzynski.edziennik.ui.grades.models.GradesStats
@ -95,11 +95,11 @@ class StatsViewHolder(
b.disclaimer.isVisible = !b.noData.isVisible
b.helpButton.onClick {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.grades_stats_help_title)
.setMessage(R.string.grades_stats_help_text)
.setPositiveButton(R.string.ok, null)
.show()
SimpleDialog<Unit>(activity) {
title(R.string.grades_stats_help_title)
message(R.string.grades_stats_help_text)
positive(R.string.ok)
}.show()
}
b.customValueDivider.isVisible = manager.dontCountEnabled || manager.plusValue != null || manager.minusValue != null

View File

@ -18,11 +18,7 @@ import pl.szczodrzynski.edziennik.ui.home.HomeCard.Companion.CARD_TIMETABLE
class HomeConfigDialog(
activity: AppCompatActivity,
private val reloadOnDismiss: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BaseDialog<Any>(activity, onShowListener, onDismissListener) {
override val TAG = "HomeConfigDialog"
) : BaseDialog<Any>(activity) {
override fun getTitleRes() = R.string.home_configure_add_remove
override fun getPositiveButtonText() = R.string.ok
@ -42,8 +38,6 @@ class HomeConfigDialog(
.map { it.cardId }
.toSet()
override suspend fun onShow() = Unit
private var configChanged = false
override suspend fun onPositiveClick(): Boolean {
@ -59,11 +53,11 @@ class HomeConfigDialog(
return DISMISS
}
override suspend fun onMultiSelectionChanged(items: Set<Any>) {
override suspend fun onMultiSelectionChanged(item: Any, isChecked: Boolean) {
configChanged = true
}
override fun onDismiss() {
override suspend fun onDismiss() {
if (configChanged && reloadOnDismiss && activity is MainActivity)
activity.reloadTarget()
}

View File

@ -91,9 +91,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding, MainActivity>(
.withIcon(SzkolnyFont.Icon.szf_clipboard_list_outline)
.withOnClickListener {
activity.bottomSheet.close()
StudentNumberDialog(activity, app.profile) {
app.profileSave()
}
StudentNumberDialog(activity, app.profile).show()
},
BottomSheetSeparatorItem(true),
BottomSheetPrimaryItem(true)

View File

@ -9,16 +9,21 @@ import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.plusAssign
import androidx.core.view.setMargins
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.enums.NavTarget
import pl.szczodrzynski.edziennik.databinding.CardHomeArchiveBinding
import pl.szczodrzynski.edziennik.ext.dp
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.setMessage
import pl.szczodrzynski.edziennik.ext.setText
import pl.szczodrzynski.edziennik.data.enums.NavTarget
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.home.HomeCard
import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter
import pl.szczodrzynski.edziennik.ui.home.HomeFragment
@ -61,14 +66,17 @@ class HomeArchiveCard(
}
}
if (profile == null) {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.home_archive_close_no_target_title)
.setMessage(R.string.home_archive_close_no_target_text, this@HomeArchiveCard.profile.name)
.setPositiveButton(R.string.ok) { _, _ ->
activity.drawer.profileSelectionOpen()
activity.drawer.open()
}
.show()
SimpleDialog<Unit>(activity) {
title(R.string.home_archive_close_no_target_title)
message(
R.string.home_archive_close_no_target_text,
this@HomeArchiveCard.profile.name
)
positive(R.string.ok) {
activity.drawer.profileSelectionOpen()
activity.drawer.open()
}
}.show()
return@launch
}
activity.navigate(profile = profile)

View File

@ -31,6 +31,7 @@ import pl.szczodrzynski.edziennik.ui.home.HomeCard
import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter
import pl.szczodrzynski.edziennik.ui.home.HomeFragment
import pl.szczodrzynski.edziennik.utils.models.Date
import timber.log.Timber
import kotlin.coroutines.CoroutineContext
class HomeLuckyNumberCard(
@ -101,14 +102,14 @@ class HomeLuckyNumberCard(
})
holder.root.onClick {
StudentNumberDialog(activity, profile, onDismissListener = {
app.profileSave(profile)
this@HomeLuckyNumberCard.launch {
StudentNumberDialog(activity, profile).showModal()
val newSubTextRes = if (profile.studentNumber == -1)
R.string.home_lucky_number_details_click_to_set
else
R.string.home_lucky_number_details
b.subText.setText(newSubTextRes, profile.studentNumber)
})
}
}
}}

View File

@ -10,7 +10,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavOptions
import androidx.navigation.Navigation
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -20,6 +19,7 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.databinding.LoginActivityBinding
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.main.ErrorSnackbar
import kotlin.coroutines.CoroutineContext
@ -72,15 +72,15 @@ class LoginActivity : AppCompatActivity(), CoroutineScope {
return
}
if (destination.id == R.id.loginSummaryFragment) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.are_you_sure)
.setMessage(R.string.login_cancel_confirmation)
.setPositiveButton(R.string.yes) { _, _ ->
setResult(Activity.RESULT_CANCELED)
finish()
}
.setNegativeButton(R.string.no, null)
.show()
SimpleDialog<Unit>(this) {
title(R.string.are_you_sure)
message(R.string.login_cancel_confirmation)
positive(R.string.yes) {
setResult(Activity.RESULT_CANCELED)
finish()
}
negative(R.string.no)
}.show()
return
}
nav.navigateUp()

View File

@ -16,25 +16,31 @@ import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.Animation
import android.view.animation.RotateAnimation
import android.widget.TextView
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.core.manager.AvailabilityManager.Error.Type
import pl.szczodrzynski.edziennik.data.enums.LoginMode
import pl.szczodrzynski.edziennik.data.enums.LoginType
import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.ext.Bundle
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.resolveColor
import pl.szczodrzynski.edziennik.ext.setText
import pl.szczodrzynski.edziennik.ext.setTintColor
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog
import pl.szczodrzynski.edziennik.ui.feedback.FeedbackActivity
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
import pl.szczodrzynski.edziennik.core.manager.AvailabilityManager.Error.Type
import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.coroutines.CoroutineContext
@ -252,19 +258,15 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
}
if (!app.config.privacyPolicyAccepted) {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.privacy_policy)
.setMessage(BetterHtml.fromHtml(activity, R.string.privacy_policy_dialog_html))
.setPositiveButton(R.string.i_agree) { _, _ ->
SimpleDialog<Unit>(activity) {
title(R.string.privacy_policy)
message(BetterHtml.fromHtml(activity, R.string.privacy_policy_dialog_html))
positive(R.string.i_agree) {
app.config.privacyPolicyAccepted = true
onLoginModeClicked(loginType, loginMode)
}
.setNegativeButton(R.string.i_disagree, null)
.show()
.also { dialog ->
dialog.findViewById<TextView>(android.R.id.message)?.movementMethod =
BetterLinkMovementMethod.getInstance()
}
negative(R.string.i_disagree)
}.show()
return
}
@ -273,14 +275,14 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
return@launch
if (loginMode.isTesting || loginMode.isDevOnly) {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.login_chooser_testing_title)
.setMessage(R.string.login_chooser_testing_text)
.setPositiveButton(R.string.ok) { _, _ ->
navigateToLoginMode(loginType, loginMode)
}
.setNegativeButton(R.string.cancel, null)
.show()
SimpleDialog<Unit>(activity) {
title(R.string.login_chooser_testing_title)
message(R.string.login_chooser_testing_text)
positive(R.string.ok) {
navigateToLoginMode(loginType, loginMode)
}
negative(R.string.cancel)
}.show()
return@launch
}

View File

@ -5,13 +5,11 @@
package pl.szczodrzynski.edziennik.ui.login
import android.os.Bundle
import android.os.Process
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import coil.load
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -20,8 +18,9 @@ import pl.szczodrzynski.edziennik.BuildConfig
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.LoginPrizeFragmentBinding
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.dialogs.RestartDialog
import kotlin.coroutines.CoroutineContext
import kotlin.system.exitProcess
class LoginPrizeFragment : Fragment(), CoroutineScope {
companion object {
@ -50,29 +49,20 @@ class LoginPrizeFragment : Fragment(), CoroutineScope {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
b.button.load("https://szkolny.eu/game/button.png")
b.button.onClick {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.are_you_sure)
.setMessage(R.string.dev_mode_enable_warning)
.setPositiveButton(R.string.yes) { _, _ ->
app.config.devMode = true
App.devMode = true
MaterialAlertDialogBuilder(activity)
.setTitle("Restart")
.setMessage("Wymagany restart aplikacji")
.setPositiveButton(R.string.ok) { _, _ ->
Process.killProcess(Process.myPid())
Runtime.getRuntime().exit(0)
exitProcess(0)
}
.setCancelable(false)
.show()
}
.setNegativeButton(R.string.no) { _, _ ->
app.config.devMode = BuildConfig.DEBUG
App.devMode = BuildConfig.DEBUG
activity.finish()
}
.show()
SimpleDialog<Unit>(activity) {
title(R.string.are_you_sure)
message(R.string.dev_mode_enable_warning)
positive(R.string.yes) {
app.config.devMode = true
App.devMode = true
RestartDialog(activity).show()
}
negative(R.string.no) {
app.config.devMode = BuildConfig.DEBUG
App.devMode = BuildConfig.DEBUG
activity.finish()
}
}.show()
}
}
}

View File

@ -9,7 +9,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -19,6 +18,7 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.core.manager.UserActionManager
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUIRES_USER_ACTION
import pl.szczodrzynski.edziennik.data.api.LOGIN_NO_ARGUMENTS
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
@ -32,7 +32,7 @@ import pl.szczodrzynski.edziennik.data.enums.LoginType
import pl.szczodrzynski.edziennik.databinding.LoginProgressFragmentBinding
import pl.szczodrzynski.edziennik.ext.getEnum
import pl.szczodrzynski.edziennik.ext.joinNotNullStrings
import pl.szczodrzynski.edziennik.core.manager.UserActionManager
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import kotlin.coroutines.CoroutineContext
import kotlin.math.max
@ -101,12 +101,14 @@ class LoginProgressFragment : Fragment(), CoroutineScope {
fun onFirstLoginFinishedEvent(event: FirstLoginFinishedEvent) {
EventBus.getDefault().removeStickyEvent(event)
if (event.profileList.isEmpty()) {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.login_account_no_students)
.setMessage(R.string.login_account_no_students_text)
.setPositiveButton(R.string.ok, null)
.setOnDismissListener { nav.navigateUp() }
.show()
SimpleDialog<Unit>(activity) {
title(R.string.login_account_no_students)
message(R.string.login_account_no_students_text)
positive(R.string.ok) {
nav.navigateUp()
}
cancelable(false)
}.show()
return
}

View File

@ -10,15 +10,16 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.LoginSummaryFragmentBinding
import pl.szczodrzynski.edziennik.ext.Bundle
import pl.szczodrzynski.edziennik.ext.onChange
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import kotlin.coroutines.CoroutineContext
@ -64,12 +65,14 @@ class LoginSummaryFragment : Fragment(), CoroutineScope {
b.registerMeSwitch.onChange { _, isChecked ->
if (isChecked)
return@onChange
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.login_summary_unregister_title)
.setMessage(R.string.login_summary_unregister_text)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel) { _, _ -> b.registerMeSwitch.isChecked = true }
.show()
SimpleDialog<Unit>(activity) {
title(R.string.login_summary_unregister_title)
message(R.string.login_summary_unregister_text)
positive(R.string.ok)
negative(R.string.cancel) {
b.registerMeSwitch.isChecked = true
}
}.show()
}
b.anotherButton.onClick {

View File

@ -9,21 +9,37 @@ import android.graphics.drawable.BitmapDrawable
import android.text.style.AbsoluteSizeSpan
import android.text.style.ForegroundColorSpan
import android.widget.Toast
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import androidx.appcompat.app.AppCompatActivity
import com.hootsuite.nachos.ChipConfiguration
import com.hootsuite.nachos.NachoTextView
import com.hootsuite.nachos.chip.ChipInfo
import com.hootsuite.nachos.chip.ChipSpan
import com.hootsuite.nachos.chip.ChipSpanChipCreator
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.ext.asSpannable
import pl.szczodrzynski.edziennik.ext.concat
import pl.szczodrzynski.edziennik.ext.dp
import pl.szczodrzynski.edziennik.ext.resolveAttr
import pl.szczodrzynski.edziennik.ext.toColorStateList
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.messages.MessagesUtils
import pl.szczodrzynski.edziennik.utils.Colors
import pl.szczodrzynski.navlib.elevateSurface
import kotlin.collections.List
import kotlin.collections.firstOrNull
import kotlin.collections.forEach
import kotlin.collections.listOf
import kotlin.collections.listOfNotNull
import kotlin.collections.mutableListOf
import kotlin.collections.mutableMapOf
import kotlin.collections.mutableSetOf
import kotlin.collections.plusAssign
import kotlin.collections.set
import kotlin.collections.sortedBy
class MessagesComposeChipCreator(
private val context: Context,
private val activity: AppCompatActivity,
private val nacho: NachoTextView,
private val teacherList: List<Teacher>,
) : ChipSpanChipCreator() {
@ -69,14 +85,12 @@ class MessagesComposeChipCreator(
else
adapter.originalList
val category = mutableListOf<Teacher>()
val categoryNames = mutableListOf<CharSequence>()
val categoryCheckedItems = mutableListOf<Boolean>()
val multiChoiceItems = mutableMapOf<CharSequence, Teacher>()
val defaultSelectedItems = mutableSetOf<Teacher>()
teachers.forEach { teacher ->
if (!teacher.isType(type))
return@forEach
category += teacher
val name = teacher.fullName
val description = when (type) {
Teacher.TYPE_TEACHER -> null
@ -94,7 +108,7 @@ class MessagesComposeChipCreator(
Teacher.TYPE_SPECIALIST -> null
else -> teacher.typeDescription
}
categoryNames += listOfNotNull(
val displayName = listOfNotNull(
name.asSpannable(
ForegroundColorSpan(textColorPrimary)
),
@ -103,21 +117,19 @@ class MessagesComposeChipCreator(
AbsoluteSizeSpan(14.dp)
)
).concat("\n")
multiChoiceItems[displayName] = teacher
// check the teacher if already added as a recipient
categoryCheckedItems += nacho.allChips.firstOrNull { it.data == teacher } != null
if (nacho.allChips.firstOrNull { it.data == teacher } != null)
defaultSelectedItems += teacher
}
MaterialAlertDialogBuilder(context)
.setTitle("Dodaj odbiorców - " + Teacher.typeName(context, type))
//.setMessage(getString(R.string.messages_compose_recipients_text_format, Teacher.typeName(activity, type)))
.setPositiveButton("OK", null)
.setNeutralButton("Anuluj", null)
.setMultiChoiceItems(
categoryNames.toTypedArray(),
categoryCheckedItems.toBooleanArray()
) { _, which, isChecked ->
val teacher = category[which]
SimpleDialog<Teacher>(activity) {
title("Dodaj odbiorców - " + Teacher.typeName(context, type))
message(R.string.messages_compose_recipients_text_format, Teacher.typeName(activity, type))
positive(R.string.ok)
negative(R.string.cancel)
multi(multiChoiceItems, defaultSelectedItems) { teacher, isChecked ->
if (isChecked) {
val chipInfoList = mutableListOf<ChipInfo>()
teacher.image =
@ -131,13 +143,13 @@ class MessagesComposeChipCreator(
}
}
}
.show()
}.show()
return null
}
override fun configureChip(chip: ChipSpan, chipConfiguration: ChipConfiguration) {
super.configureChip(chip, chipConfiguration)
chip.setBackgroundColor(elevateSurface(context, 8).toColorStateList())
chip.setTextColor(android.R.attr.textColorPrimary.resolveAttr(context))
chip.setBackgroundColor(elevateSurface(activity, 8).toColorStateList())
chip.setTextColor(android.R.attr.textColorPrimary.resolveAttr(activity))
}
}

View File

@ -4,20 +4,20 @@
package pl.szczodrzynski.edziennik.ui.messages.compose
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import com.hootsuite.nachos.NachoTextView
import com.hootsuite.nachos.chip.ChipSpan
import com.hootsuite.nachos.tokenizer.SpanChipTokenizer
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
class MessagesComposeChipTokenizer(
context: Context,
activity: AppCompatActivity,
nacho: NachoTextView,
teacherList: List<Teacher>,
) : SpanChipTokenizer<ChipSpan>(
context,
activity,
MessagesComposeChipCreator(
context = context,
activity = activity,
nacho = nacho,
teacherList = teacherList
),

View File

@ -12,7 +12,6 @@ import android.widget.ScrollView
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -39,6 +38,7 @@ import pl.szczodrzynski.edziennik.data.enums.NavTarget
import pl.szczodrzynski.edziennik.databinding.MessagesComposeFragmentBinding
import pl.szczodrzynski.edziennik.ext.Bundle
import pl.szczodrzynski.edziennik.ext.DAY
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.base.fragment.BaseFragment
import pl.szczodrzynski.edziennik.ui.dialogs.settings.MessagesConfigDialog
import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment
@ -75,7 +75,7 @@ class MessagesComposeFragment : BaseFragment<MessagesComposeFragmentBinding, Mai
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
MessagesConfigDialog(activity, false, null, null).show()
MessagesConfigDialog(activity, false).show()
}
)
@ -251,18 +251,18 @@ class MessagesComposeFragment : BaseFragment<MessagesComposeFragmentBinding, Mai
}
private fun saveDraftDialog() {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.messages_compose_save_draft_title)
.setMessage(R.string.messages_compose_save_draft_text)
.setPositiveButton(R.string.save) { _, _ ->
SimpleDialog<Unit>(activity) {
title(R.string.messages_compose_save_draft_title)
message(R.string.messages_compose_save_draft_text)
positive(R.string.save) {
saveDraft()
MessagesFragment.pageSelection = Message.TYPE_DRAFT
activity.navigate(navTarget = NavTarget.MESSAGES, skipBeforeNavigate = true)
}
.setNegativeButton(R.string.discard) { _, _ ->
negative(R.string.discard) {
activity.resumePausedNavigation()
}
.show()
}.show()
}
private fun saveDraft() {
@ -279,19 +279,21 @@ class MessagesComposeFragment : BaseFragment<MessagesComposeFragmentBinding, Mai
}
private fun discardDraftDialog() {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.messages_compose_discard_draft_title)
.setMessage(R.string.messages_compose_discard_draft_text)
.setPositiveButton(R.string.remove) { _, _ ->
launch {
if (draftMessageId != null)
manager.deleteDraft(App.profileId, draftMessageId!!)
Toast.makeText(activity, R.string.messages_compose_draft_discarded, Toast.LENGTH_SHORT).show()
activity.navigateUp(skipBeforeNavigate = true)
}
SimpleDialog<Unit>(activity) {
title(R.string.messages_compose_discard_draft_title)
message(R.string.messages_compose_discard_draft_text)
positive(R.string.remove) {
if (draftMessageId != null)
manager.deleteDraft(App.profileId, draftMessageId!!)
Toast.makeText(
activity,
R.string.messages_compose_draft_discarded,
Toast.LENGTH_SHORT
).show()
activity.navigateUp(skipBeforeNavigate = true)
}
.setNegativeButton(R.string.cancel, null)
.show()
negative(R.string.cancel)
}.show()
}
@SuppressLint("SetTextI18n")
@ -389,14 +391,15 @@ class MessagesComposeFragment : BaseFragment<MessagesComposeFragmentBinding, Mai
activity.bottomSheet.hideKeyboard()
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.messages_compose_confirm_title)
.setMessage(R.string.messages_compose_confirm_text)
.setPositiveButton(R.string.send) { _, _ ->
EdziennikTask.messageSend(App.profileId, recipients, subject.trim(), body).enqueue(activity)
}
.setNegativeButton(R.string.cancel, null)
.show()
SimpleDialog<Unit>(activity) {
title(R.string.messages_compose_confirm_title)
message(R.string.messages_compose_confirm_text)
positive(R.string.send) {
EdziennikTask.messageSend(App.profileId, recipients, subject.trim(), body)
.enqueue(activity)
}
negative(R.string.cancel)
}
}
override fun onResume() {

View File

@ -33,7 +33,7 @@ class MessagesFragment : PagerFragment<BasePagerFragmentBinding, MainActivity>(
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
MessagesConfigDialog(activity, false, null, null).show()
MessagesConfigDialog(activity, false).show()
}
)

View File

@ -8,7 +8,6 @@ import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.core.view.isVisible
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
@ -28,6 +27,7 @@ import pl.szczodrzynski.edziennik.ext.attachToastHint
import pl.szczodrzynski.edziennik.ext.get
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.base.fragment.BaseFragment
import pl.szczodrzynski.edziennik.ui.dialogs.settings.MessagesConfigDialog
import pl.szczodrzynski.edziennik.ui.messages.MessagesUtils
@ -51,7 +51,7 @@ class MessageFragment : BaseFragment<MessageFragmentBinding, MainActivity>(
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
MessagesConfigDialog(activity, false, null, null).show()
MessagesConfigDialog(activity, false).show()
}
)
@ -91,18 +91,20 @@ class MessageFragment : BaseFragment<MessageFragmentBinding, MainActivity>(
))
}
b.deleteButton.onClick {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.messages_delete_confirmation)
.setMessage(R.string.messages_delete_confirmation_text)
.setPositiveButton(R.string.ok) { _, _ ->
launch {
manager.markAsDeleted(message)
Toast.makeText(activity, "Wiadomość przeniesiona do usuniętych", Toast.LENGTH_SHORT).show()
activity.navigateUp()
}
}
.setNegativeButton(R.string.cancel, null)
.show()
SimpleDialog<Unit>(activity) {
title(R.string.messages_delete_confirmation)
message(R.string.messages_delete_confirmation_text)
positive(R.string.ok) {
manager.markAsDeleted(message)
Toast.makeText(
activity,
"Wiadomość przeniesiona do usuniętych",
Toast.LENGTH_SHORT
).show()
activity.navigateUp()
}
negative(R.string.cancel)
}.show()
}
b.downloadButton.isVisible = App.devMode
b.downloadButton.onClick {
@ -209,8 +211,6 @@ class MessageFragment : BaseFragment<MessageFragmentBinding, MainActivity>(
b.notesButton.setupNotesButton(
activity = activity,
owner = message,
onShowListener = null,
onDismissListener = null,
)
}

View File

@ -20,11 +20,7 @@ class NoteDetailsDialog(
activity: AppCompatActivity,
private val owner: Noteable?,
private var note: Note,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<NoteDetailsDialogBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "NoteDetailsDialog"
) : BindingDialog<NoteDetailsDialogBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -41,8 +37,6 @@ class NoteDetailsDialog(
activity = activity,
owner = owner,
editingNote = note,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
return NO_DISMISS
}

View File

@ -4,10 +4,9 @@
package pl.szczodrzynski.edziennik.ui.notes
import android.content.DialogInterface.BUTTON_POSITIVE
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@ -21,11 +20,11 @@ import pl.szczodrzynski.edziennik.databinding.NoteEditorDialogBinding
import pl.szczodrzynski.edziennik.ext.isNotNullNorBlank
import pl.szczodrzynski.edziennik.ext.resolveString
import pl.szczodrzynski.edziennik.ext.toDrawable
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.BindingDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.RegistrationConfigDialog
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class NoteEditorDialog(
activity: AppCompatActivity,
@ -35,11 +34,7 @@ class NoteEditorDialog(
owner?.getNoteOwnerProfileId()
?: editingNote?.profileId
?: 0,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<NoteEditorDialogBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "NoteEditorDialog"
) : BindingDialog<NoteEditorDialogBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -57,7 +52,7 @@ class NoteEditorDialog(
private val textStylingManager
get() = app.textStylingManager
private var progressDialog: AlertDialog? = null
private var progressDialog: BaseDialog<*>? = null
override suspend fun onPositiveClick(): Boolean {
val profile = withContext(Dispatchers.IO) {
@ -75,14 +70,16 @@ class NoteEditorDialog(
}
if (note.isShared || editingNote?.isShared == true) {
progressDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.please_wait)
.setMessage(when (note.isShared) {
true -> R.string.notes_editor_progress_sharing
false -> R.string.notes_editor_progress_unsharing
})
.setCancelable(false)
.show()
progressDialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(
when (note.isShared) {
true -> R.string.notes_editor_progress_sharing
false -> R.string.notes_editor_progress_unsharing
}
)
cancelable(false)
}.show()
}
val success = manager.saveNote(
@ -98,25 +95,21 @@ class NoteEditorDialog(
override suspend fun onNeutralClick(): Boolean {
// editingNote cannot be null, as the button is visible
val confirmation = suspendCoroutine<Boolean> { cont ->
var result = false
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.are_you_sure)
.setMessage(R.string.notes_editor_confirmation_text)
.setPositiveButton(R.string.yes) { _, _ -> result = true }
.setNegativeButton(R.string.no, null)
.setOnDismissListener { cont.resume(result) }
.show()
}
if (!confirmation)
val confirmation = SimpleDialog<Unit>(activity) {
title(R.string.are_you_sure)
message(R.string.notes_editor_confirmation_text)
positive(R.string.yes)
negative(R.string.no)
}.showModal().getButton()
if (confirmation != BUTTON_POSITIVE)
return NO_DISMISS
if (editingNote?.isShared == true) {
progressDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.please_wait)
.setMessage(R.string.notes_editor_progress_unsharing)
.setCancelable(false)
.show()
progressDialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(R.string.notes_editor_progress_unsharing)
cancelable(false)
}.show()
}
val success = manager.deleteNote(activity, editingNote ?: return NO_DISMISS)
@ -154,15 +147,11 @@ class NoteEditorDialog(
activity = activity,
textLayout = b.topicLayout,
textEdit = b.topic,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
)
textStylingManager.attachToField(
activity = activity,
textLayout = b.bodyLayout,
textEdit = b.body,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
)
}

View File

@ -17,11 +17,7 @@ import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
class NoteListDialog(
activity: AppCompatActivity,
private val owner: Noteable,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<NoteListDialogBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "NoteListDialog"
) : BindingDialog<NoteListDialogBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -40,8 +36,6 @@ class NoteListDialog(
activity = activity,
owner = owner,
editingNote = null,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
return NO_DISMISS
}
@ -56,8 +50,6 @@ class NoteListDialog(
activity = activity,
owner = owner,
note = it,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
},
onNoteEditClick = {
@ -65,8 +57,6 @@ class NoteListDialog(
activity = activity,
owner = owner,
editingNote = it,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
},
)

View File

@ -21,8 +21,6 @@ import pl.szczodrzynski.edziennik.ext.toDrawable
fun MaterialButton.setupNotesButton(
activity: AppCompatActivity,
owner: Noteable,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) {
if (!isVisible)
return
@ -41,8 +39,6 @@ fun MaterialButton.setupNotesButton(
NoteListDialog(
activity = activity,
owner = owner,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
}
}

View File

@ -141,7 +141,7 @@ class SettingsSyncCard(util: SettingsUtil) : SettingsCard(util) {
item.subTextChecked = getQuietHours()
item.isChecked = configGlobal.sync.quietHoursEnabled
util.refresh()
})
}).show()
}
).also {
it.subTextChecked = getQuietHours()

View File

@ -5,9 +5,9 @@
package pl.szczodrzynski.edziennik.ui.settings.cards
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.AppLanguageDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.MiniMenuConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ThemeChooserDialog
@ -92,14 +92,12 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
setHeaderBackground()
return@createActionItem
}
MaterialAlertDialogBuilder(activity)
.setItems(
arrayOf(
activity.getString(R.string.settings_theme_drawer_header_dialog_set),
activity.getString(R.string.settings_theme_drawer_header_dialog_restore)
)
) { _, which ->
when (which) {
SimpleDialog<Int>(activity) {
itemsRes(
R.string.settings_theme_drawer_header_dialog_set to 0,
R.string.settings_theme_drawer_header_dialog_restore to 1,
) {
when (it) {
0 -> setHeaderBackground()
1 -> {
app.config.ui.headerBackground = null
@ -108,8 +106,8 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
}
}
}
.setNegativeButton(R.string.cancel, null)
.show()
negative(R.string.cancel)
}.show()
},
util.createActionItem(
@ -121,14 +119,12 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
setAppBackground()
return@createActionItem
}
MaterialAlertDialogBuilder(activity)
.setItems(
arrayOf(
activity.getString(R.string.settings_theme_app_background_dialog_set),
activity.getString(R.string.settings_theme_app_background_dialog_restore)
)
) { _, which ->
when (which) {
SimpleDialog<Int>(activity) {
itemsRes(
R.string.settings_theme_app_background_dialog_set to 0,
R.string.settings_theme_app_background_dialog_restore to 1,
) {
when (it) {
0 -> setAppBackground()
1 -> {
app.config.ui.appBackground = null
@ -136,8 +132,8 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
}
}
}
.setNegativeButton(R.string.cancel, null)
.show()
negative(R.string.cancel)
}.show()
},
util.createPropertyItem(

View File

@ -1,10 +1,8 @@
package pl.szczodrzynski.edziennik.ui.settings.contributors
import android.os.Bundle
import android.os.Process
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
@ -14,8 +12,9 @@ import pl.szczodrzynski.edziennik.databinding.ContributorsFragmentBinding
import pl.szczodrzynski.edziennik.ext.Bundle
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.onLongClick
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.base.fragment.PagerFragment
import kotlin.system.exitProcess
import pl.szczodrzynski.edziennik.ui.dialogs.RestartDialog
class ContributorsFragment : PagerFragment<ContributorsFragmentBinding, MainActivity>(
inflater = ContributorsFragmentBinding::inflate,
@ -77,28 +76,19 @@ class ContributorsFragment : PagerFragment<ContributorsFragmentBinding, MainActi
}
b.glove.onClick {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.are_you_sure)
.setMessage(R.string.dev_mode_enable_warning)
.setPositiveButton(R.string.yes) { _, _ ->
SimpleDialog<Unit>(activity) {
title(R.string.are_you_sure)
message(R.string.dev_mode_enable_warning)
positive(R.string.yes) {
app.config.devMode = true
App.devMode = true
MaterialAlertDialogBuilder(activity)
.setTitle("Restart")
.setMessage("Wymagany restart aplikacji")
.setPositiveButton(R.string.ok) { _, _ ->
Process.killProcess(Process.myPid())
Runtime.getRuntime().exit(0)
exitProcess(0)
}
.setCancelable(false)
.show()
RestartDialog(activity).show()
}
.setNegativeButton(R.string.no) { _, _ ->
negative(R.string.no) {
app.config.devMode = false
App.devMode = false
}
.show()
}.show()
}
contributors = contributors ?: SzkolnyApi(app).runCatching(activity.errorSnackbar) {

View File

@ -29,13 +29,8 @@ import pl.szczodrzynski.edziennik.ui.base.dialog.ViewDialog
class TemplateDialog(
activity: AppCompatActivity,
private val onActionPerformed: (() -> Unit)? = null,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogTemplateBinding>(activity, onShowListener, onDismissListener) {
) : BindingDialog<DialogTemplateBinding>(activity) {
override val TAG = "TemplateDialog"
override fun getTitle(): CharSequence = "Template"
override fun getTitleRes() = R.string.menu_template
override fun inflate(layoutInflater: LayoutInflater) =
DialogTemplateBinding.inflate(layoutInflater)
@ -62,8 +57,6 @@ class TemplateDialog(
// to convert a map of StringIDs to CharSequences
// .mapKeys { (resId, _) -> activity.getString(resId) }
override suspend fun onShow() = Unit
// local variables go here
// onPositiveClick

View File

@ -7,50 +7,62 @@ package pl.szczodrzynski.edziennik.ui.timetable
import android.content.ContentResolver
import android.content.ContentValues
import android.content.Intent
import android.graphics.*
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.DashPathEffect
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.Typeface
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.View.MeasureSpec
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskFinishedEvent
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.databinding.DialogGenerateBlockTimetableBinding
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.ext.JsonObject
import pl.szczodrzynski.edziennik.ext.asStrikethroughSpannable
import pl.szczodrzynski.edziennik.ext.dp
import pl.szczodrzynski.edziennik.ext.getSchoolYearConstrains
import pl.szczodrzynski.edziennik.ext.setText
import pl.szczodrzynski.edziennik.ui.base.dialog.BaseDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.BindingDialog
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
import pl.szczodrzynski.edziennik.utils.models.Week
import timber.log.Timber
import java.io.File
import kotlin.coroutines.CoroutineContext
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
import kotlin.math.roundToInt
class GenerateBlockTimetableDialog(
val activity: AppCompatActivity,
val onShowListener: ((tag: String) -> Unit)? = null,
val onDismissListener: ((tag: String) -> Unit)? = null
) : CoroutineScope {
activity: AppCompatActivity,
) : BindingDialog<DialogGenerateBlockTimetableBinding>(activity) {
companion object {
const val TAG = "GenerateBlockTimetableDialog"
private const val TAG = "GenerateBlockTimetableDialog"
private const val WIDTH_CONSTANT = 70
private const val WIDTH_WEEKDAY = 285
private const val WIDTH_SPACING = 15
@ -59,64 +71,45 @@ class GenerateBlockTimetableDialog(
private const val HEIGHT_FOOTER = 40
}
override fun getTitleRes() = R.string.timetable_generate_range
override fun inflate(layoutInflater: LayoutInflater) =
DialogGenerateBlockTimetableBinding.inflate(layoutInflater)
override fun getPositiveButtonText() = R.string.save
override fun getNegativeButtonText() = R.string.cancel
private val heightProfileName by lazy { if (showProfileName) 100 else 0 }
private val app by lazy { activity.application as App }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private lateinit var dialog: AlertDialog
private lateinit var b: DialogGenerateBlockTimetableBinding
private var showProfileName: Boolean = false
private var showTeachersNames: Boolean = true
private var noColors: Boolean = false
private var enqueuedWeekDialog: AlertDialog? = null
private var enqueuedWeekDialog: BaseDialog<*>? = null
private var enqueuedWeekStart = Date.getToday()
private var enqueuedWeekEnd = Date.getToday()
init { run {
if (activity.isFinishing)
return@run
onShowListener?.invoke(TAG)
EventBus.getDefault().register(this)
val weekCurrentStart = Week.getWeekStart()
val weekCurrentEnd = Week.getWeekEnd()
val weekNextStart = weekCurrentEnd.clone().stepForward(0, 0, 1)
val weekNextEnd = weekNextStart.clone().stepForward(0, 0, 6)
b = DialogGenerateBlockTimetableBinding.inflate(activity.layoutInflater)
private val weekCurrentStart = Week.getWeekStart()
private val weekCurrentEnd = Week.getWeekEnd()
private val weekNextStart = weekCurrentEnd.clone().stepForward(0, 0, 1)
private val weekNextEnd = weekNextStart.clone().stepForward(0, 0, 6)
override suspend fun onShow() {
b.withChangesCurrentWeekRadio.setText(R.string.timetable_generate_current_week_format, weekCurrentStart.formattedStringShort, weekCurrentEnd.formattedStringShort)
b.withChangesNextWeekRadio.setText(R.string.timetable_generate_next_week_format, weekNextStart.formattedStringShort, weekCurrentEnd.formattedStringShort)
b.showProfileNameCheckbox.setOnCheckedChangeListener { _, isChecked -> showProfileName = isChecked }
b.showTeachersNamesCheckbox.setOnCheckedChangeListener { _, isChecked -> showTeachersNames = isChecked }
b.noColorsCheckbox.setOnCheckedChangeListener { _, isChecked -> noColors = isChecked }
}
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.timetable_generate_range)
.setView(b.root)
.setNeutralButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
.setPositiveButton(R.string.save, null)
.setOnDismissListener {
onDismissListener?.invoke(TAG)
EventBus.getDefault().unregister(this@GenerateBlockTimetableDialog)
}
.show()
dialog.getButton(AlertDialog.BUTTON_POSITIVE)?.onClick {
when (b.weekSelectionRadioGroup.checkedRadioButtonId) {
R.id.withChangesCurrentWeekRadio -> generateBlockTimetable(weekCurrentStart, weekCurrentEnd)
R.id.withChangesNextWeekRadio -> generateBlockTimetable(weekNextStart, weekNextEnd)
R.id.forSelectedWeekRadio -> selectDate()
}
override suspend fun onPositiveClick(): Boolean {
when (b.weekSelectionRadioGroup.checkedRadioButtonId) {
R.id.withChangesCurrentWeekRadio -> generateBlockTimetable(weekCurrentStart, weekCurrentEnd)
R.id.withChangesNextWeekRadio -> generateBlockTimetable(weekNextStart, weekNextEnd)
R.id.forSelectedWeekRadio -> selectDate()
}
}}
return NO_DISMISS
}
private fun selectDate() {
MaterialDatePicker.Builder.datePicker()
@ -146,7 +139,7 @@ class GenerateBlockTimetableDialog(
@Subscribe(threadMode = ThreadMode.MAIN)
fun onApiTaskErrorEvent(event: ApiTaskErrorEvent) {
dialog.dismiss()
dismiss()
enqueuedWeekDialog?.dismiss()
}
@ -191,11 +184,11 @@ class GenerateBlockTimetableDialog(
if (enqueuedWeekDialog != null) {
return@launch
}
enqueuedWeekDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.please_wait)
.setMessage(R.string.timetable_syncing_text)
.setCancelable(false)
.show()
enqueuedWeekDialog = SimpleDialog<Unit>(activity) {
title(R.string.please_wait)
message(R.string.timetable_syncing_text)
cancelable(false)
}.show()
enqueuedWeekStart = weekStart
enqueuedWeekEnd = weekEnd
@ -210,10 +203,11 @@ class GenerateBlockTimetableDialog(
return@launch
}
val progressDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.timetable_generate_progress_title)
.setMessage(R.string.timetable_generate_progress_text)
.show()
val progressDialog = SimpleDialog<Unit>(activity) {
title(R.string.timetable_generate_progress_title)
message(R.string.timetable_generate_progress_text)
cancelable(false)
}.show()
if (minTime == null) {
progressDialog.dismiss()
@ -221,8 +215,6 @@ class GenerateBlockTimetableDialog(
return@launch
}
dialog.dismiss()
val uri = withContext(Dispatchers.Default) {
val diff = Time.diff(maxTime, minTime)
@ -402,26 +394,28 @@ class GenerateBlockTimetableDialog(
}
progressDialog.dismiss()
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.timetable_generate_success_title)
.setMessage(R.string.timetable_generate_success_text)
.setPositiveButton(R.string.share) { dialog, _ ->
dialog.dismiss()
val intent = Intent(Intent.ACTION_SEND)
intent.setDataAndType(null, "image/*")
intent.putExtra(Intent.EXTRA_STREAM, uri)
activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.share_intent)))
}
.setNegativeButton(R.string.open) { dialog, _ ->
dialog.dismiss()
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(uri, "image/*")
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
activity.startActivity(intent)
}
.setNeutralButton(R.string.do_nothing) { dialog, _ -> dialog.dismiss() }
.show()
SimpleDialog<Unit>(activity) {
title(R.string.timetable_generate_success_title)
message(R.string.timetable_generate_success_text)
positive(R.string.share) {
val intent = Intent(Intent.ACTION_SEND)
intent.setDataAndType(null, "image/*")
intent.putExtra(Intent.EXTRA_STREAM, uri)
activity.startActivity(
Intent.createChooser(
intent,
activity.getString(R.string.share_intent)
)
)
}
negative(R.string.open) {
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(uri, "image/*")
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
activity.startActivity(intent)
}
neutral(R.string.do_nothing)
}.showModal()
dismiss()
}}
}

View File

@ -36,11 +36,7 @@ class LessonDetailsDialog(
private val lesson: LessonFull,
private val attendance: AttendanceFull? = null,
private val showNotes: Boolean = true,
onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<DialogLessonDetailsBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "LessonDetailsDialog"
) : BindingDialog<DialogLessonDetailsBinding>(activity) {
override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) =
@ -60,8 +56,6 @@ class LessonDetailsDialog(
activity,
lesson.profileId,
defaultLesson = lesson,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
return NO_DISMISS
}
@ -114,7 +108,7 @@ class LessonDetailsDialog(
}
}
b.shiftedGoTo.setOnClickListener {
dialog.dismiss()
dismiss()
val dateStr = otherLessonDate?.stringY_m_d ?: return@setOnClickListener
val intent = Intent(TimetableFragment.ACTION_SCROLL_TO_DATE).apply {
putExtra("timetableDate", dateStr)
@ -168,8 +162,6 @@ class LessonDetailsDialog(
AttendanceDetailsDialog(
activity = activity,
attendance = attendance,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
).show()
}
}
@ -186,8 +178,6 @@ class LessonDetailsDialog(
EventDetailsDialog(
activity,
it,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
},
onEventEditClick = {
@ -195,8 +185,6 @@ class LessonDetailsDialog(
activity,
it.profileId,
editingEvent = it,
onShowListener = onShowListener,
onDismissListener = onDismissListener
).show()
}
)
@ -236,12 +224,12 @@ class LessonDetailsDialog(
BetterLink.attach(
b.teacherNameView,
teachers = mapOf(lesson.displayTeacherId!! to name),
onActionSelected = dialog::dismiss
onActionSelected = ::dismiss
)
BetterLink.attach(
b.oldTeacherNameView,
teachers = mapOf(lesson.displayTeacherId!! to name),
onActionSelected = dialog::dismiss
onActionSelected = ::dismiss
)
}
@ -250,8 +238,6 @@ class LessonDetailsDialog(
b.notesButton.setupNotesButton(
activity = activity,
owner = lesson,
onShowListener = onShowListener,
onDismissListener = onDismissListener,
)
b.legend.isVisible = showNotes
if (showNotes)

View File

@ -109,7 +109,7 @@ class TimetableFragment : PagerFragment<FragmentTimetableV2Binding, MainActivity
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
TimetableConfigDialog(activity, false, null, null).show()
TimetableConfigDialog(activity, false).show()
}
)

View File

@ -9,40 +9,37 @@ import android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.ext.Intent
import pl.szczodrzynski.edziennik.data.enums.NavTarget
import pl.szczodrzynski.edziennik.ext.Intent
import pl.szczodrzynski.edziennik.ext.app
import pl.szczodrzynski.edziennik.ui.timetable.LessonDetailsDialog
import kotlin.coroutines.CoroutineContext
class LessonDialogActivity : AppCompatActivity(), CoroutineScope {
companion object {
private const val TAG = "LessonDialogActivity"
}
private lateinit var job: Job
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private val shownDialogs = hashSetOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.setBackgroundDrawable(ColorDrawable(0))
job = Job()
app.uiManager.applyTheme(this, noDisplay = true)
val app = application as App
launch {
val deferred = async(Dispatchers.Default) {
val lesson = withContext(Dispatchers.IO) {
val extras = intent?.extras
val profileId = extras?.getInt("profileId") ?: return@async null
val profileId = extras?.getInt("profileId") ?: return@withContext null
if (extras.getBoolean("separatorItem", false)) {
val i = Intent(
@ -53,28 +50,16 @@ class LessonDialogActivity : AppCompatActivity(), CoroutineScope {
).addFlags(FLAG_ACTIVITY_REORDER_TO_FRONT or FLAG_ACTIVITY_NEW_TASK)
app.startActivity(i)
finish()
return@async null
return@withContext null
}
val lessonId = extras.getLong("lessonId")
app.db.timetableDao().getByIdNow(profileId, lessonId)
}
val lesson = deferred.await()
lesson?.let {
LessonDetailsDialog(
this@LessonDialogActivity,
lesson,
onShowListener = { tag ->
shownDialogs.add(tag)
},
onDismissListener = { tag ->
shownDialogs.remove(tag)
if (shownDialogs.isEmpty())
finish()
}
).show()
}
} ?: return@launch
LessonDetailsDialog(this@LessonDialogActivity, lesson).showModal()
finish()
}
}
}

View File

@ -4,21 +4,12 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="?attr/dialogPreferredPadding"
android:paddingTop="8dp"
android:paddingEnd="?attr/dialogPreferredPadding">
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
tools:text="This is a custom message of the dialog." />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/text_input_layout"
style="?textInputOutlinedStyle"