Last active
October 26, 2020 09:10
-
-
Save Jeevuz/b406430d1addf37512135c3ca95bdef3 to your computer and use it in GitHub Desktop.
Universal DialogFragments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) {} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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