Skip to content

Instantly share code, notes, and snippets.

@Jeevuz
Last active October 26, 2020 09:10
Show Gist options
  • Save Jeevuz/b406430d1addf37512135c3ca95bdef3 to your computer and use it in GitHub Desktop.
Save Jeevuz/b406430d1addf37512135c3ca95bdef3 to your computer and use it in GitHub Desktop.
Universal DialogFragments
package ru.mobileup.businessnavigator.ui.base.dialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.support.annotation.LayoutRes
import android.support.annotation.StringRes
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatDialogFragment
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.EditText
import ru.mobileup.businessnavigator.R
/**
* Dialog to ask for string to enter
* Passed custom view must have EditText with `editText` id.
* @author Vasili Chyrvon (vasili.chyrvon@gmail.com)
*/
class EnterStringDialogFragment : AppCompatDialogFragment() {
companion object {
private val DEFAULT_TAG = "EnterStringDialogFragment"
private val ARG_TITLE = "title"
private val ARG_OK = "ok"
private val ARG_CANCEL = "cancel"
private val ARG_CUSTOM_EDIT = "custom_edit"
private val ARG_TEXT = "text"
private val ARG_CAN_BE_EMPTY = "can_by_empty"
private val ARG_DIALOG_TAG = "dialog_tag"
fun newInstance(
@StringRes titleResId: Int,
@StringRes ok: Int,
@StringRes cancel: Int,
@LayoutRes customEditResId: Int,
text: String,
canBeEmpty: Boolean = true,
dialogTag: String = DEFAULT_TAG
) = EnterStringDialogFragment().apply {
arguments = Bundle().apply {
putInt(ARG_TITLE, titleResId)
putInt(ARG_OK, ok)
putInt(ARG_CANCEL, cancel)
putInt(ARG_CUSTOM_EDIT, customEditResId)
putString(ARG_TEXT, text)
putString(ARG_DIALOG_TAG, dialogTag)
putBoolean(ARG_CAN_BE_EMPTY, canBeEmpty)
}
}
}
private val title by lazy { arguments.getInt(ARG_TITLE) }
private val ok by lazy { arguments.getInt(ARG_OK) }
private val cancel by lazy { arguments.getInt(ARG_CANCEL) }
private val customEdit by lazy { arguments.getInt(ARG_CUSTOM_EDIT) }
private val text by lazy { arguments.getString(ARG_TEXT) }
private val canBeEmpty by lazy { arguments.getBoolean(ARG_CAN_BE_EMPTY) }
private val dialogTag by lazy { arguments.getString(ARG_DIALOG_TAG) }
private lateinit var listener: Callbacks
private lateinit var editText: EditText
interface Callbacks {
fun onStringEntered(dialogTag: String, string: String)
fun formatString(dialogTag: String, string: String): String = string
}
override fun onAttach(context: Context?) {
super.onAttach(context)
if (parentFragment is Callbacks) {
listener = parentFragment as Callbacks
} else if (activity is Callbacks) {
listener = activity as Callbacks
} else {
throw IllegalStateException("Activity or parent fragment must implement Callbacks.")
}
}
override fun onStart() {
super.onStart()
if (!canBeEmpty)
setPositiveButtonEnabled(text.isNotEmpty())
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val customEdit = LayoutInflater.from(context).inflate(customEdit, null)
editText = customEdit.findViewById(R.id.editText)
with(editText) {
addTextChangedListener(textWatcher)
setText(this@EnterStringDialogFragment.text)
setSelection(text.length)
}
return AlertDialog.Builder(context)
.setTitle(title)
.setView(customEdit)
.setPositiveButton(
ok,
{ _, _ -> listener.onStringEntered(dialogTag, editText.text.toString()) }
)
.setNegativeButton(
cancel,
{ _, _ -> dismiss() }
)
.create()
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Make the keyboard visible.
dialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
return super.onCreateView(inflater, container, savedInstanceState)
}
private fun setPositiveButtonEnabled(isEnabled: Boolean) {
(dialog as? AlertDialog)?.getButton(AlertDialog.BUTTON_POSITIVE)?.isEnabled = isEnabled
}
private val textWatcher = object : TextWatcher {
private var isEditing = false
override fun afterTextChanged(s: Editable) {
if (!isEditing) {
isEditing = true
// save and remove filters
val filters = s.filters
s.filters = emptyArray()
// set formatted text
s.replaceRange(0, s.length, listener.formatString(dialogTag, s.toString()))
// restore filters
s.filters = filters
isEditing = false
}
if (!canBeEmpty)
setPositiveButtonEnabled(s.isNotEmpty())
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
}
}
package ru.mobileup.businessnavigator.ui.base.dialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatDialogFragment
/**
* Simple ok/cancel dialog (cancel is optional) with flexible settings.
* @author Vasili Chyrvon (vasili.chyrvon@gmail.com)
*/
class SimpleDialogFragment : AppCompatDialogFragment() {
companion object {
private val DEFAULT_TAG = "SimpleDialogFragment"
private val ARGS_TITLE = "args_title"
private val ARGS_MESSAGE = "args_message"
private val ARGS_OK = "args_ok"
private val ARGS_CANCEL = "args_cancel"
private val ARGS_DIALOG_TAG = "args_dialog_tag"
private val ARGS_CANCEL_ONLY_BY_BUTTONS = "args_cancellable"
private val ARGS_REQUIRES_LISTENER = "args_requires_listener"
fun newInstance(title: String? = null,
message: String,
ok: String,
cancel: String? = null,
dialogTag: String = DEFAULT_TAG,
cancelOnlyByButtons: Boolean = false,
requiresListener: Boolean = true): SimpleDialogFragment {
val args = Bundle()
args.putString(ARGS_TITLE, title)
args.putString(ARGS_MESSAGE, message)
args.putString(ARGS_OK, ok)
args.putString(ARGS_CANCEL, cancel)
args.putBoolean(ARGS_CANCEL_ONLY_BY_BUTTONS, cancelOnlyByButtons)
args.putString(ARGS_DIALOG_TAG, dialogTag)
args.putBoolean(ARGS_REQUIRES_LISTENER, requiresListener)
val fragment = SimpleDialogFragment()
fragment.arguments = args
return fragment
}
}
private val title by lazy { arguments.getString(ARGS_TITLE) }
private val message by lazy { arguments.getString(ARGS_MESSAGE) }
private val ok by lazy { arguments.getString(ARGS_OK) }
private val cancel by lazy { arguments.getString(ARGS_CANCEL) }
private val dialogTag by lazy { arguments.getString(ARGS_DIALOG_TAG) }
private val cancelOnlyByButtons by lazy { arguments.getBoolean(ARGS_CANCEL_ONLY_BY_BUTTONS) }
private val requiresListener by lazy { arguments.getBoolean(ARGS_REQUIRES_LISTENER) }
private var listener: ResponseListener? = null
interface ResponseListener {
fun onSimpleDialogResponse(tag: String, isOk: Boolean)
}
override fun onAttach(context: Context?) {
super.onAttach(context)
if (parentFragment is ResponseListener) {
listener = parentFragment as ResponseListener
} else if (activity is ResponseListener) {
listener = activity as ResponseListener
} else {
if (requiresListener)
throw IllegalStateException("Activity or parent fragment must implement ResponseListener.")
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
if (cancelOnlyByButtons) isCancelable = false
return AlertDialog.Builder(context)
.setTitle(title)
.setMessage(message)
.setPositiveButton(
ok,
{ _, _ -> listener?.onSimpleDialogResponse(dialogTag, true) }
)
.apply { // Allow omitted cancel
cancel?.let {
setNegativeButton(
cancel,
{ _, _ ->
dismiss()
listener?.onSimpleDialogResponse(dialogTag, false)
}
)
}
}
.create()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment