This commit is contained in:
HapeLee committed 2025-06-04 13:33:51 +08:00
1 parent b86d90021c
commit 6c0757c91b
972 files changed
+6885 -7321

No files matched your search

@@ -0,0 +1,106 @@
@file:Suppress("unused")
package io.legato.kazusa.lib.dialogs
import android.annotation.SuppressLint
import android.content.Context
import android.content.DialogInterface
import android.graphics.drawable.Drawable
import android.view.KeyEvent
import android.view.View
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import io.legato.kazusa.R
@SuppressLint("SupportAnnotationUsage")
interface AlertBuilder<out D : DialogInterface> {
val ctx: Context
fun setTitle(title: CharSequence)
fun setTitle(titleResource: Int)
fun setMessage(message: CharSequence)
fun setMessage(messageResource: Int)
fun setIcon(icon: Drawable)
fun setIcon(@DrawableRes iconResource: Int)
fun setCustomTitle(customTitle: View)
fun setCustomView(customView: View)
fun setCancelable(isCancelable: Boolean)
fun positiveButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null)
fun positiveButton(
@StringRes buttonTextResource: Int,
onClicked: ((dialog: DialogInterface) -> Unit)? = null
)
fun negativeButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null)
fun negativeButton(
@StringRes buttonTextResource: Int,
onClicked: ((dialog: DialogInterface) -> Unit)? = null
)
fun neutralButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null)
fun neutralButton(
@StringRes buttonTextResource: Int,
onClicked: ((dialog: DialogInterface) -> Unit)? = null
)
fun onCancelled(handler: (dialog: DialogInterface) -> Unit)
fun onKeyPressed(handler: (dialog: DialogInterface, keyCode: Int, e: KeyEvent) -> Boolean)
fun onDismiss(handler: (dialog: DialogInterface) -> Unit)
fun items(
items: List<CharSequence>,
onItemSelected: (dialog: DialogInterface, index: Int) -> Unit
)
fun <T> items(
items: List<T>,
onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit
)
fun multiChoiceItems(
items: Array<String>,
checkedItems: BooleanArray,
onClick: (dialog: DialogInterface, which: Int, isChecked: Boolean) -> Unit
)
fun singleChoiceItems(
items: Array<String>,
checkedItem: Int = 0,
onClick: ((dialog: DialogInterface, which: Int) -> Unit)? = null
)
fun build(): D
fun show(): D
fun customTitle(view: () -> View) {
setCustomTitle(view())
}
fun customView(view: () -> View) {
setCustomView(view())
}
fun okButton(handler: ((dialog: DialogInterface) -> Unit)? = null) =
positiveButton(android.R.string.ok, handler)
fun cancelButton(handler: ((dialog: DialogInterface) -> Unit)? = null) =
negativeButton(android.R.string.cancel, handler)
fun yesButton(handler: ((dialog: DialogInterface) -> Unit)? = null) =
positiveButton(R.string.yes, handler)
fun noButton(handler: ((dialog: DialogInterface) -> Unit)? = null) =
negativeButton(R.string.no, handler)
}
@@ -0,0 +1,171 @@
package io.legato.kazusa.lib.dialogs
import android.content.Context
import android.content.DialogInterface
import android.graphics.drawable.Drawable
import android.view.KeyEvent
import android.view.View
import androidx.appcompat.app.AlertDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import io.legato.kazusa.R
import io.legato.kazusa.help.config.AppConfig
internal class AndroidAlertBuilder(override val ctx: Context) : AlertBuilder<AlertDialog> {
private val builder = MaterialAlertDialogBuilder(ctx)
override fun setTitle(title: CharSequence) {
builder.setTitle(title)
}
override fun setTitle(titleResource: Int) {
builder.setTitle(titleResource)
}
override fun setMessage(message: CharSequence) {
builder.setMessage(message)
}
override fun setMessage(messageResource: Int) {
builder.setMessage(messageResource)
}
override fun setIcon(icon: Drawable) {
builder.setIcon(icon)
}
override fun setIcon(iconResource: Int) {
builder.setIcon(iconResource)
}
override fun setCustomTitle(customTitle: View) {
builder.setCustomTitle(customTitle)
}
override fun setCustomView(customView: View) {
builder.setView(customView)
}
override fun setCancelable(isCancelable: Boolean) {
builder.setCancelable(isCancelable)
}
override fun onCancelled(handler: (DialogInterface) -> Unit) {
builder.setOnCancelListener(handler)
}
override fun onKeyPressed(handler: (dialog: DialogInterface, keyCode: Int, e: KeyEvent) -> Boolean) {
builder.setOnKeyListener(handler)
}
override fun positiveButton(
buttonText: String,
onClicked: ((dialog: DialogInterface) -> Unit)?
) {
builder.setPositiveButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) }
}
override fun positiveButton(
buttonTextResource: Int,
onClicked: ((dialog: DialogInterface) -> Unit)?
) {
builder.setPositiveButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) }
}
override fun negativeButton(
buttonText: String,
onClicked: ((dialog: DialogInterface) -> Unit)?
) {
builder.setNegativeButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) }
}
override fun negativeButton(
buttonTextResource: Int,
onClicked: ((dialog: DialogInterface) -> Unit)?
) {
builder.setNegativeButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) }
}
override fun neutralButton(
buttonText: String,
onClicked: ((dialog: DialogInterface) -> Unit)?
) {
builder.setNeutralButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) }
}
override fun neutralButton(
buttonTextResource: Int,
onClicked: ((dialog: DialogInterface) -> Unit)?
) {
builder.setNeutralButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) }
}
override fun onDismiss(handler: (dialog: DialogInterface) -> Unit) {
builder.setOnDismissListener(handler)
}
override fun items(
items: List<CharSequence>,
onItemSelected: (dialog: DialogInterface, index: Int) -> Unit
) {
builder.setItems(Array(items.size) { i -> items[i].toString() }) { dialog, which ->
onItemSelected(dialog, which)
}
}
override fun <T> items(
items: List<T>,
onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit
) {
builder.setItems(Array(items.size) { i -> items[i].toString() }) { dialog, which ->
onItemSelected(dialog, items[which], which)
}
}
override fun multiChoiceItems(
items: Array<String>,
checkedItems: BooleanArray,
onClick: (dialog: DialogInterface, which: Int, isChecked: Boolean) -> Unit
) {
builder.setMultiChoiceItems(items, checkedItems) { dialog, which, isChecked ->
onClick(dialog, which, isChecked)
}
}
override fun singleChoiceItems(
items: Array<String>,
checkedItem: Int,
onClick: ((dialog: DialogInterface, which: Int) -> Unit)?
) {
builder.setSingleChoiceItems(items, checkedItem) { dialog, which ->
onClick?.invoke(dialog, which)
}
}
override fun build(): AlertDialog {
var dialog = builder.create()
if (AppConfig.isEInkMode) {
dialog.window?.run {
val attr = attributes
attr.dimAmount = 0f
attr.windowAnimations = 0
attributes = attr
setBackgroundDrawableResource(R.drawable.bg_eink_border_dialog)
}
}
return dialog
}
override fun show(): AlertDialog {
var dialog = builder.show()
if (AppConfig.isEInkMode) {
dialog.window?.run {
val attr = attributes
attr.dimAmount = 0f
attr.windowAnimations = 0
attributes = attr
setBackgroundDrawableResource(R.drawable.bg_eink_border_dialog)
}
}
return dialog
}
}
@@ -0,0 +1,186 @@
@file:Suppress("NOTHING_TO_INLINE", "unused", "DEPRECATION")
package io.legato.kazusa.lib.dialogs
import android.app.ProgressDialog
import android.content.Context
import android.content.DialogInterface
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
fun Context.alert(
title: CharSequence? = null,
message: CharSequence? = null,
init: (AlertBuilder<DialogInterface>.() -> Unit)? = null
): AlertDialog {
return AndroidAlertBuilder(this).apply {
if (title != null) {
this.setTitle(title)
}
if (message != null) {
this.setMessage(message)
}
if (init != null) init()
}.show()
}
inline fun Fragment.alert(
title: CharSequence? = null,
message: CharSequence? = null,
noinline init: (AlertBuilder<DialogInterface>.() -> Unit)? = null
) = requireActivity().alert(title, message, init)
fun Context.alert(
titleResource: Int? = null,
messageResource: Int? = null,
init: (AlertBuilder<DialogInterface>.() -> Unit)? = null
): AlertDialog {
return AndroidAlertBuilder(this).apply {
if (titleResource != null) {
this.setTitle(titleResource)
}
if (messageResource != null) {
this.setMessage(messageResource)
}
if (init != null) init()
}.show()
}
inline fun Fragment.alert(
titleResource: Int? = null,
messageResource: Int? = null,
noinline init: (AlertBuilder<DialogInterface>.() -> Unit)? = null
) = requireActivity().alert(titleResource, messageResource, init)
fun Context.alert(init: AlertBuilder<AlertDialog>.() -> Unit): AlertDialog =
AndroidAlertBuilder(this).apply {
init()
}.show()
inline fun Fragment.alert(noinline init: AlertBuilder<DialogInterface>.() -> Unit) =
requireContext().alert(init)
inline fun Fragment.progressDialog(
title: Int? = null,
message: Int? = null,
noinline init: (ProgressDialog.() -> Unit)? = null
) = requireActivity().progressDialog(title, message, init)
fun Context.progressDialog(
title: Int? = null,
message: Int? = null,
init: (ProgressDialog.() -> Unit)? = null
) = progressDialog(title?.let { getString(it) }, message?.let { getString(it) }, false, init)
inline fun Fragment.indeterminateProgressDialog(
title: Int? = null,
message: Int? = null,
noinline init: (ProgressDialog.() -> Unit)? = null
) = requireActivity().indeterminateProgressDialog(title, message, init)
fun Context.indeterminateProgressDialog(
title: Int? = null,
message: Int? = null,
init: (ProgressDialog.() -> Unit)? = null
) = progressDialog(title?.let { getString(it) }, message?.let { getString(it) }, true, init)
inline fun Fragment.progressDialog(
title: CharSequence? = null,
message: CharSequence? = null,
noinline init: (ProgressDialog.() -> Unit)? = null
) = requireActivity().progressDialog(title, message, init)
fun Context.progressDialog(
title: CharSequence? = null,
message: CharSequence? = null,
init: (ProgressDialog.() -> Unit)? = null
) = progressDialog(title, message, false, init)
inline fun Fragment.indeterminateProgressDialog(
title: CharSequence? = null,
message: CharSequence? = null,
noinline init: (ProgressDialog.() -> Unit)? = null
) = requireActivity().indeterminateProgressDialog(title, message, init)
fun Context.indeterminateProgressDialog(
title: CharSequence? = null,
message: CharSequence? = null,
init: (ProgressDialog.() -> Unit)? = null
) = progressDialog(title, message, true, init)
private fun Context.progressDialog(
title: CharSequence? = null,
message: CharSequence? = null,
indeterminate: Boolean,
init: (ProgressDialog.() -> Unit)? = null
) = ProgressDialog(this).apply {
isIndeterminate = indeterminate
if (!indeterminate) setProgressStyle(ProgressDialog.STYLE_HORIZONTAL)
if (message != null) setMessage(message)
if (title != null) setTitle(title)
if (init != null) init()
show()
}
typealias AlertBuilderFactory<D> = (Context) -> AlertBuilder<D>
inline fun <D : DialogInterface> Fragment.alert(
noinline factory: AlertBuilderFactory<D>,
title: String? = null,
message: String? = null,
noinline init: (AlertBuilder<D>.() -> Unit)? = null
) = activity?.alert(factory, title, message, init)
fun <D : DialogInterface> Context.alert(
factory: AlertBuilderFactory<D>,
title: String? = null,
message: String? = null,
init: (AlertBuilder<D>.() -> Unit)? = null
): AlertBuilder<D> {
return factory(this).apply {
if (title != null) {
this.setTitle(title)
}
if (message != null) {
this.setMessage(message)
}
if (init != null) init()
}
}
inline fun <D : DialogInterface> Fragment.alert(
noinline factory: AlertBuilderFactory<D>,
titleResource: Int? = null,
messageResource: Int? = null,
noinline init: (AlertBuilder<D>.() -> Unit)? = null
) = requireActivity().alert(factory, titleResource, messageResource, init)
fun <D : DialogInterface> Context.alert(
factory: AlertBuilderFactory<D>,
titleResource: Int? = null,
messageResource: Int? = null,
init: (AlertBuilder<D>.() -> Unit)? = null
): AlertBuilder<D> {
return factory(this).apply {
if (titleResource != null) {
this.setTitle(titleResource)
}
if (messageResource != null) {
this.setMessage(messageResource)
}
if (init != null) init()
}
}
inline fun <D : DialogInterface> Fragment.alert(
noinline factory: AlertBuilderFactory<D>,
noinline init: AlertBuilder<D>.() -> Unit
) = requireActivity().alert(factory, init)
fun <D : DialogInterface> Context.alert(
factory: AlertBuilderFactory<D>,
init: AlertBuilder<D>.() -> Unit
): AlertBuilder<D> = factory(this).apply { init() }
@@ -0,0 +1,90 @@
/*
* Copyright 2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("unused")
package io.legato.kazusa.lib.dialogs
import android.content.Context
import android.content.DialogInterface
fun Context.selector(
items: List<CharSequence>,
onClick: (DialogInterface, Int) -> Unit
) {
with(AndroidAlertBuilder(this)) {
items(items, onClick)
show()
}
}
fun <T> Context.selector(
items: List<T>,
onClick: (DialogInterface, T, Int) -> Unit
) {
with(AndroidAlertBuilder(this)) {
items(items, onClick)
show()
}
}
fun Context.selector(
title: CharSequence,
items: List<CharSequence>,
onClick: (DialogInterface, Int) -> Unit
) {
with(AndroidAlertBuilder(this)) {
this.setTitle(title)
items(items, onClick)
show()
}
}
fun <T> Context.selector(
title: CharSequence,
items: List<T>,
onClick: (DialogInterface, T, Int) -> Unit
) {
with(AndroidAlertBuilder(this)) {
this.setTitle(title)
items(items, onClick)
show()
}
}
fun Context.selector(
titleSource: Int,
items: List<CharSequence>,
onClick: (DialogInterface, Int) -> Unit
) {
with(AndroidAlertBuilder(this)) {
this.setTitle(titleSource)
items(items, onClick)
show()
}
}
fun <T> Context.selector(
titleSource: Int,
items: List<T>,
onClick: (DialogInterface, T, Int) -> Unit
) {
with(AndroidAlertBuilder(this)) {
this.setTitle(titleSource)
items(items, onClick)
show()
}
}
@@ -0,0 +1,13 @@
package io.legato.kazusa.lib.dialogs
@Suppress("unused")
data class SelectItem<T>(
val title: String,
val value: T
) {
override fun toString(): String {
return title
}
}