I tried to follow solid principles and want to make my code better. So I want to separate the function that may not be used in some problems.
this is the code that I already to separate but still redundant
private lateinit var dialogView : View
private lateinit var b : AlertDialog
override fun modalDialog(
view:Int,
listener: bodyModalDialog, submitButtonModalDialog: submitButtonModalDialog,
btnSubmit:Int,
btnCancel:Int) {
val dialogBuilder = AlertDialog.Builder(this, android.R.style.Theme_DeviceDefault_Light_Dialog_Alert)
val inflater = this.layoutInflater
dialogView = inflater.inflate(view, null)
dialogBuilder.setView(dialogView)
dialogBuilder.setCancelable(false)
var uiSubmitButton = dialogView.findViewById<View>(btnSubmit)
var uiCancelButton = dialogView.findViewById<View>(btnCancel)
listener.bodyDialog(dialogView)
uiSubmitButton.setOnClickListener {
submitButtonModalDialog.submitButton(dialogView)
b.cancel()
}
uiCancelButton.setOnClickListener {
b.cancel()
}
b = dialogBuilder.create()
b.window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
b.show()
}
override fun modalDialogNoBody(
view:Int,
listener: submitButtonModalDialog,
btnSubmit:Int,
btnCancel:Int) {
val dialogBuilder = AlertDialog.Builder(this, android.R.style.Theme_DeviceDefault_Light_Dialog_Alert)
val inflater = this.layoutInflater
dialogView = inflater.inflate(view, null)
dialogBuilder.setView(dialogView)
dialogBuilder.setCancelable(false)
var uiSubmitButton = dialogView.findViewById<View>(btnSubmit)
var uiCancelButton = dialogView.findViewById<View>(btnCancel)
uiSubmitButton.setOnClickListener {
listener.submitButton(dialogView)
b.cancel()
}
uiCancelButton.setOnClickListener {
b.cancel()
}
b = dialogBuilder.create()
b.window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
b.show()
}
from that code I tried to separate when the problem need the body and some of them not. So if i let them can access the body it will be just empty so I separate like that. But, the code are redundant becouse it write the same code with one of them there is no body. So i tried to make one of them just take the other code and add body procedure, but I have no idea how to do that. I tried to make an object so when it called true then means there is no body and if false there is body like this code
object Modal{
fun isNoBody(view:Int,
listener: submitButtonModalDialog,
btnSubmit:Int,
btnCancel:Int):Boolean{
val dialogBuilder = AlertDialog.Builder(this, android.R.style.Theme_DeviceDefault_Light_Dialog_Alert)
val inflater = this.layoutInflater
dialogView = inflater.inflate(view, null)
dialogBuilder.setView(dialogView)
dialogBuilder.setCancelable(false)
var uiSubmitButton = dialogView.findViewById<View>(btnSubmit)
var uiCancelButton = dialogView.findViewById<View>(btnCancel)
uiSubmitButton.setOnClickListener {
listener.submitButton(dialogView)
b.cancel()
}
uiCancelButton.setOnClickListener {
b.cancel()
}
b = dialogBuilder.create()
b.window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
b.show()
return true
}
}
but it won't work because AlertDialog and View can't be called there. even if I change them to be public. please help
I got my answer. So what I do is I make button and body with two different interfaces. and because if want to use body you need button automatically so I just make it call when it needed only like this
override fun modalDialog(view:Int,
listener: SubmitButtonModalDialog,
btnSubmit:Int,
btnCancel:Int) {
val dialogBuilder = AlertDialog.Builder(this, android.R.style.Theme_DeviceDefault_Light_Dialog_Alert)
val inflater = this.layoutInflater
dialogView = inflater.inflate(view, null)
dialogBuilder.setView(dialogView)
dialogBuilder.setCancelable(false)
var uiSubmitButton = dialogView.findViewById<View>(btnSubmit)
var uiCancelButton = dialogView.findViewById<View>(btnCancel)
uiSubmitButton.setOnClickListener {
listener.submitButton(dialogView)
b.cancel()
}
uiCancelButton.setOnClickListener {
b.cancel()
}
b = dialogBuilder.create()
b.window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
b.show()
}
override fun modalDialogBody(listener: BodyModalDialog) {
listener.bodyDialog(dialogView)
}
Related
I have a function :
fun showDialogWindow(){
val builder = AlertDialog.Builder(this)
val inflater = layoutInflater
val dialogLayout = inflater.inflate(R.layout.dialog_window, null)
val editText = dialogLayout.findViewById<EditText>(R.id.change_balance_edittext)
with(builder) {
setPositiveButton("Ok"){dialog, which ->
Values.balance = editText.text.toString().toFloat()
}
setNegativeButton("Cancel"){dialog, which ->
}
setView(dialogLayout)
show()
}
}
I want to create it in separate Class, when i try to do it, i have some mistakes: in line 2 'this' is not defined in this context,in line 3 Unresolved reference: layoutInflater and in line 13 Overload resolution ambiguity. Within the MainActivity fun is working. How can i solve it?
First I would try to look at how the language works and where you can call variables.
Per example, the "this" error is because when you are calling "this" in the MainActivity, it gets the activity type, probably "AppCompatActivity". When calling in a new file, you need to pass the value "this" as a parameter in the funtion.
fun showDialogWindow(mainActivity : Context){
val builder = AlertDialog.Builder(mainActivity )
val inflater = layoutInflater
val dialogLayout = inflater.inflate(R.layout.dialog_window, null)
val editText = dialogLayout.findViewById<EditText>(R.id.change_balance_edittext)
with(builder) {
setPositiveButton("Ok"){dialog, which ->
Values.balance = editText.text.toString().toFloat()
}
setNegativeButton("Cancel"){dialog, which ->
}
setView(dialogLayout)
show()
}
}
I have a custom dialog in my android project and it was working fine. After I removed kotlin extension from the project, I have modified my code as follows but there is some issue with the Views in the custom dialog. Codes etTitle.visibility = View.GONE and val newRequest = etDetail.text.toString() didn't work as I expected. It didn't hide the view etTitle and the value in the EditText etDetail is not picked also, it always returns emplty even when there is some value.
private lateinit var bindingDialogLayout: CustomDialogBinding
fun specialRequestDialog(currentRequest: String?) {
bindingDialogLayout = CustomDialogBinding.inflate(layoutInflater)
val dialogLayout = layoutInflater.inflate(R.layout.custom_dialog, null)
val etTitle = bindingDialogLayout.etTitle
val etDetail = bindingDialogLayout.etDetails
etTitle.visibility = View.GONE
etDetail.setText(currentRequest)
MaterialAlertDialogBuilder(this)
.setTitle("What is your special request?")
.setCancelable(false)
.setPositiveButton("Save") { dialog, which ->
val newRequest = etDetail.text.toString()
if (newRequest.isEmpty()) {
showErrorSnackBar("Type in if you have any special request, else hit cancel", true)
} else {
addButton.visibility = View.GONE
deleteButton.visibility = View.VISIBLE
}
}
.setNegativeButton("Cancel") { dialog, which ->
dialog?.dismiss()
}
.setView(dialogLayout)
.show()
}
You set the wrong view to the dialog.
Use this instead:
.setView(bindingDialogLayout.root)
Updating value of recyclerview but unable to update corresponding data in model class
Model classes
#Parcelize
class GetStockListData : ArrayList<GetStockListDataItem>(), Parcelable
#Parcelize
data class GetStockListDataItem(
var Qty:#RawValue Double,
var selectedQty: Double
): Parcelable
able to change recyclerview element using alertbox as follows
private fun showAlertDialog(stockListData: GetStockListData, position: Int) {
val layoutInflater = LayoutInflater.from(context)
val customView =
layoutInflater.inflate(R.layout.change_qty_dialog, null)
val myBox: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder(context)
myBox.setView(customView)
val dialog = myBox.create()
dialog.show()
val etQuantity = customView.findViewById<AppCompatEditText>(R.id.et_quantity)
if (stockListData[position].Qty < args.getListDetailsByRNumberModelItem.ReqQty) {
val df = DecimalFormat("#.##")
df.roundingMode = RoundingMode.CEILING
etQuantity.setText(df.format(stockListData[position].Qty).toString())
} else
etQuantity.setText(args.getListDetailsByRNumberModelItem.ReqQty.toString())
etQuantity.setSelection(etQuantity.text.toString().length)
etQuantity.requestFocus()
requireContext().showKeyboard()
customView.findViewById<Button>(R.id.btnDone).setOnClickListener {
if(!etQuantity.text.isNullOrEmpty()) {
val qtyStr = etQuantity.text.toString().trim()
var qtyDouble = qtyStr.toDouble()
stockListData[position].selectedQty = qtyDouble
adapter.notifyDataSetChanged()
dialog.dismiss()
}
}
}
for (i in 0 until stockListData.size){
sum += stockListData[i].selectedQty
}
here if user edit Recyclerview list item multiple times, each value added to list. Finally if i try to retrieve sum of all recyclerview elements getting wrong value because in model class values are added when i try to replace element.
Instead of passing whole list as parameter to showAlertDialog() method, you could just pass single item which has to be updated. And one more thing, you should not call adapter.notifyDataSetChanged() for single item updation, rather call adapter.notifyItemChanged(position). Look at below code, I am getting correct sum :
private fun showRecipeMeasureDialog(recipeItem: RecipeItem?,position: Int){
val dialogView = LayoutInflater.from(context).inflate(R.layout.add_recipe_measure_dialog, null)
val dialog = AlertDialog.Builder(context, R.style.RoundedCornersDialog).setView(dialogView).show()
dialog.setCancelable(false)
val displayRectangle = Rect()
val window = activity?.window
window?.decorView?.getWindowVisibleDisplayFrame(displayRectangle)
dialog.window?.setLayout(
(displayRectangle.width() * 0.5f).toInt(),
dialog.window!!.attributes.height
)
context?.resources?.let {
dialogView.findViewById<TextView>(R.id.recipe_measure_title).text = java.lang.String.format(it.getString(R.string.addRecipeMeasure), unitsArray[currentMeasurementUnits - 1])
}
val doneBtn = dialogView.findViewById<ImageButton>(R.id.recipe_measure_done_btn)
val closeBtn = dialogView.findViewById<ImageButton>(R.id.close_btn_add_recipe)
val conversionEditText = dialogView.findViewById<ClearFocusEditText>(R.id.recipe_conversion_tie)
doneBtn.isEnabled = false
if (recipeItem != null ){
conversionEditText.setText("${recipeItem.conversionRatio}")
}
closeBtn.setOnClickListener {
context?.hideKeyboard(it)
dialog.dismiss() }
doneBtn.setOnClickListener {
context?.hideKeyboard(it)
val conversionRatio = conversionEditText.text.toString().toFloat()
if (recipeItem != null){
recipeItem.conversionRatio = conversionRatio
recipeItemList[position] = recipeItem
recipeAdapter.notifyItemChanged(position)
}else{
recipeItemList.add(0,RecipeItem(0,0,conversionRatio,0)) // Use your data class in place of RecipeItem
recipeAdapter.notifyItemInserted(0) // new Item is added to index zero, so adapter has to be updated at index zero
}
// calculating sum
val sum = recipeItemList.map { it.conversionRatio }.sum()
Log.d("tisha==>>","Conversion ratio sum = $sum")
dialog.cancel()
}
}
I've a mutableLiveData of list of items in my fragment and I have a custom dialog that I pass a single item from this list to it . this is my code:
adapter.itemPosPriceListener.observe(this, Observer { pos ->
activity?.let { act ->
val dialog = DialogRoomPrices(act)
dialog.item.value = it.get(pos)
}
})
this is my dialog :
class DialogRoomPrices(act: Activity) {
private var dialog: Dialog
private var act: Activity
val item = MutableLiveData<RoomItem>()
init {
dialog = Dialog(act, R.style.DialogAnimation)
dialog.setContentView(R.layout.dialog_room_prices)
this.act = act
makeDialog()
val lp = WindowManager.LayoutParams()
lp.copyFrom(dialog.window?.attributes)
lp.width = WindowManager.LayoutParams.MATCH_PARENT
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
dialog.getWindow()?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
dialog.show()
dialog.window?.attributes = lp
}
private fun makeDialog() {
item?.value?.let { row ->
dialog.et_roomp_price_paye.setText(row.price_paye)
dialog.et_roomp_price_akhathafte.setText(row.price_akhathafte)
////and 10 more rows of these
}
dialog.bt_next.setOnClickListener {
/////need to update the item and observe it in my fragment
dialog.dismiss()
}
}
as you can see ,dialog has a form and after filling the data and clicking on submit button , I need to update my item in fragment class .
the question is , how can I update the this item and notify my fragment's item about it ?
I don't see the whole code, but such communication can be done simply with a callback.
Solution will look like
class DialogRoomPrices(act: Activity) {
interface Listener() {
fun onNext(data: SomeData)
}
private var listener: Listener?
private var dialog: Dialog
private var act: Activity
val item = MutableLiveData<RoomItem>()
...
dialog.bt_next.setOnClickListener {
val dataToBeSetToHostingFragment = getData()
listener?.onNext(dataToBeSetToHostingFragment)
dialog.dismiss()
}
In the Fragment
class HostingFragment(): Listener {
adapter.itemPosPriceListener.observe(this, Observer { pos ->
activity?.let { act ->
val dialog = DialogRoomPrices(act)
dialog.item.value = it.get(pos)
dialog.listener = object : DialogRoomPrices.Listener {
override onNext(data: SomeData) {
// Assign data to your liveData, force update recycler view or do any other action you want to
}
}
}
})
ImageView in first alert dialog opens second dialog to change an imageResource of the ImageView in the first dialog. However I don't know how to make connection between two alert dialogs
Both have different xml layouts, so I assume that in second dialog I should make a reference to the layout of the first dialog
private fun editItemDialog() {
val dialogBuilder1 = AlertDialog.Builder(this)
val inflater = this.layoutInflater
val dialogView = inflater.inflate(R.layout.edit_dialog, null)
dialogBuilder1.setView(dialogView)
var editIconButton = dialogView.findViewById<View>(R.id.editIcon) as ImageView
editIconButton.setOnClickListener{
showIconDialog()
}
dialogBuilder1.setTitle("Edit mode")
dialogBuilder1.setPositiveButton("Save") { _, _ ->
//sth
}
dialogBuilder1.setNegativeButton("Cancel") { _, _ ->
//sth
}
val b = dialogBuilder1.create()
b.show()
}
private fun showIconDialog() {
val dialogBuilder = AlertDialog.Builder(this)
val inflater = this.layoutInflater
val dialogView = inflater.inflate(R.layout.icons, null)
dialogBuilder.setView(dialogView)
//examplary two icons to select
var travelRB = dialogView.findViewById<View>(R.id.travel) as RadioButton
var travRB = dialogView.findViewById<View>(R.id.travel) as RadioButton
dialogBuilder.setTitle("Icon dialog")
dialogBuilder.setMessage("Select an icon")
dialogBuilder.setPositiveButton("Save") { _, _ ->
//here I would like to change an icon of the ImageView, for example:
editIconButton.setImageResource(R.id.travel)
dialogBuilder.setNegativeButton("Cancel") { _, _ ->
//sth
}
val b = dialogBuilder.create()
b.show()
}
You can add a callback to the second dialog
fun showIconDialog(callback : (Drawable) -> Unit) {
//code
callback.invoke(someDrawable)
}
And on the first one you just do this:
showIconDialog() { someDrawable ->
//code to change the layout src icon
}