Problem with saving data of a profile in Firebase database - android

I want to create a profile in my app, where I can edit or add some information when logged in. It already works with the checkbox but not with the other editText items. Also I want to show the saved information after I closed the app in the profile. Any idea how I could do this? Like changing an editText to a textView or is there any other way?
Here is my code of the fragment Profile:
(I tried several options to save data in the firebase database)
package com.example.discoverme
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.ContentValues.TAG
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.*
import android.widget.*
import androidx.fragment.app.Fragment
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.UserProfileChangeRequest
import com.google.firebase.database.*
import java.util.*
import java.util.Calendar.*
class ProfilFoto : Fragment() {
lateinit var mDatabase : DatabaseReference
var mAuth = FirebaseAuth.getInstance()
var user = FirebaseAuth.getInstance().currentUser
var DISPLAY_NAME : String? = null
#SuppressLint("SetTextI18n", "ResourceType")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// setContentView(R.layout.fragment_notifications)
val rootView: View = inflater.inflate(R.layout.fragment_profil_foto, container, false)
Toast.makeText(this.requireContext(), "Profil", Toast.LENGTH_LONG)
Log.e("Halllo", "Hat toll geklapptttt")
val telefon = rootView.findViewById<View>(R.id.telnummer) as EditText
val geburtstag = rootView.findViewById<View>(R.id.geburtsdatum) as EditText
val location = rootView.findViewById<View>(R.id.locationPerson) as EditText
val stundenlohn = rootView.findViewById<View>(R.id.stundenlohn) as EditText
var tele = telefon.text.toString()
var gebi = geburtstag.text.toString()
var loc = location.text.toString()
var stundenl = stundenlohn.text.toString()
val nameTxt: TextView = rootView.findViewById(R.id.textName1)
val emailTxt: TextView = rootView.findViewById(R.id.emailemail)
val spezi = rootView.findViewById<TextView>(R.id.spezialisierungen)
var uid = user!!.uid
val userHashMap = HashMap<String, Any>()
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
val speicherButton = rootView.findViewById<Button>(R.id.speichern)
speicherButton.setOnClickListener {
Log.e("Speichern", "speichert")
Log.e("Telefon", tele)
//userHashMap["Telefon"] = tele
//mDatabase.child("Telefon").setValue(tele)
mDatabase.child("Telefon").setValue(tele)
.addOnSuccessListener {
Log.e("Telefon", tele)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
if (!gebi.isEmpty()) {
Log.e("Geburtstag", gebi)
userHashMap["Geburtsdatum"] = gebi
// mDatabase.updateChildren(userHashMap)
}
if (!loc.isEmpty()) {
userHashMap["Adresse"] = loc
// mDatabase.updateChildren(userHashMap)
}
if (!stundenl.isEmpty()) {
userHashMap["Stundenlohn"] = stundenl
// mDatabase.updateChildren(userHashMap)
}
mDatabase.updateChildren(userHashMap)
}
mDatabase.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onDataChange(snapshot: DataSnapshot) {
nameTxt.text = snapshot.child("Name").value.toString()
emailTxt.text = snapshot.child("Email").value.toString()
if (snapshot.child("Spezialisierung").exists()) {
Log.e("Spez", "Ist anscheinend da")
spezi.text = snapshot.child("Spezialisierung").value.toString()
}
/* if (snapshot.child("Telefon").exists()) {
telefon.text = snapshot.child("Telefon").value.toString()
}
*/
}
})
val buttonSignOut : ImageButton? = rootView.findViewById(R.id.signOut_button1)
if (buttonSignOut != null) {
buttonSignOut.setOnClickListener{
mAuth.signOut()
Toast.makeText(this.context, "Signed Out", Toast.LENGTH_LONG).show()
startActivity(Intent(this.context, Start::class.java))
}
}
val buttonspezi = rootView.findViewById<Button>(R.id.buttonspez)
buttonspezi.setOnClickListener { view ->
var dialog: AlertDialog
// Initialize an array of colors
val arrayColors = arrayOf("Hochzeit", "Portrait", "Familien", "Architektur", "Passfotos", "Lebensmittel", "Film", "Interior", " Kinder/Babies", "Landschaft", "Mode", "People und Lifestyle", "Werbung", "Sport", "Produkte", "Akt")
// Initialize a boolean array of checked items
val arrayChecked = booleanArrayOf(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false)
var stringArray = arrayOf<String>()
// Initialize a new instance of alert dialog builder object
val builder = AlertDialog.Builder(this.context)
// Set a title for alert dialog
builder.setTitle("Gib seine Spezialisierung an.")
// Define multiple choice items for alert dialog
builder.setMultiChoiceItems(arrayColors, arrayChecked) { dialog, which, isChecked ->
// Update the clicked item checked status
arrayChecked[which] = isChecked
// Get the clicked item
val color = arrayColors[which]
}
// Set the positive/yes button click listener
builder.setPositiveButton("OK") { _, _ ->
// Do something when click positive button
spezi.text = "Deine Spezialisierungen sind.. \n"
for (i in 0 until arrayColors.size) {
val checked = arrayChecked[i]
if (checked) {
stringArray += arrayOf(arrayColors[i])
spezi.text = "${spezi.text}" + stringArray.toString()
}
}
userHashMap["Spezialisierung"] = stringArray.asList()
Log.e("Liste", stringArray.asList().toString())
mDatabase.updateChildren(userHashMap)
}
// Initialize the AlertDialog using builder object
dialog = builder.create()
// Finally, display the alert dialog
dialog.show()
}
return rootView
}
// Method to show an alert dialog with multiple choice list items
// Extension function to show toast message
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
and here is the xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/profil_foto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffff"
android:orientation="vertical"
tools:context=".ProfilFoto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="259dp"
android:background="#9C27B0"
android:orientation="vertical"
android:visibility="visible">
<ImageButton
android:id="#+id/signOut_button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="320dp"
android:layout_marginLeft="350dp"
android:background="#9C27B0"
android:contentDescription="TODO"
android:paddingTop="20dp"
android:paddingEnd="20dp"
android:paddingRight="20dp"
android:src="#drawable/ic_baseline_logout_24"
android:title="#string/sign_out"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:showAsAction="ifRoom"
app:tint="#FFFFFF"
tools:ignore="RtlSymmetry"
tools:visibility="visible" />
<ImageView
android:id="#+id/logo4"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_gravity="center"
android:layout_margin="10dp"
android:contentDescription="#string/todo"
android:src="#drawable/ic_profil_wei_" />
<TextView
android:id="#+id/textName1"
android:layout_width="wrap_content"
android:layout_height="39dp"
android:layout_gravity="center_horizontal"
android:textColor="#fff"
android:textSize="21sp"
android:textStyle="bold" />
<Space
android:layout_width="match_parent"
android:layout_height="50dp" />
</LinearLayout>
<LinearLayout
android:layout_width="360dp"
android:layout_height="700dp"
android:layout_gravity="center"
android:layout_marginTop="45dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="25dp">
<EditText
android:id="#+id/infotext"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:hint="Erzähle etwas über dich..."
android:paddingLeft="20dp">
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:src="#drawable/ic_baseline_location_on_24"
app:tint="#9C27B0" />
<EditText
android:id="#+id/locationPerson"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:hint="Adresse"
android:paddingLeft="20dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:background="#00FFFFFF"
android:src="#drawable/ic_baseline_cake_24"
app:tint="#9C27B0" />
<EditText
android:id="#+id/geburtsdatum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:hint="Geburtsdatum"
android:paddingLeft="20dp" />
</LinearLayout>
<EditText
android:id="#+id/telnummer"
android:layout_width="300dp"
android:layout_height="35dp"
android:background="#drawable/button_register_background"
android:drawableLeft="#drawable/ic_baseline_call_24"
android:drawablePadding="10dp"
android:ems="10"
android:hint="Telefonnummer"
android:paddingLeft="20dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:src="#drawable/ic_mail_full"
app:tint="#9C27B0" />
<TextView
android:id="#+id/emailemail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="20dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<Button
android:id="#+id/buttonspez"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Spezialisierungen"
android:textAllCaps="false"
android:background="#drawable/buttom_rounded_corner_lila"
android:textColor="#FFFFFF"
android:layout_gravity="center_vertical|center_horizontal"
android:gravity="center"
/>
<TextView
android:id="#+id/spezialisierungen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/Base.TextAppearance.AppCompat.Large"
android:layout_margin="25dp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:orientation="horizontal"
android:paddingLeft="25dp">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
android:src="#drawable/ic_baseline_attach_money_24"
app:tint="#9C27B0" />
<EditText
android:id="#+id/stundenlohn"
android:hint="Stundenlohn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="20dp" />
</LinearLayout>
<Button
android:id="#+id/speichern"
android:layout_width="160dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="25dp"
android:background="#drawable/buttom_rounded_corner_lila"
android:text="Änderungen speichern"
android:textColor="#FFFFFF"
app:cornerRadius="20dp">
</Button>
</LinearLayout>
<Space
android:layout_width="match_parent"
android:layout_height="17dp" />
</LinearLayout>
</ScrollView>

I solved it. I just had to move the findViewById declaration inside the setOnClickListener and not only in the onCreate. Now I'm getting the ediText information and can save it in my firebase database.
Like so:
class ProfilFoto : Fragment() {
lateinit var mDatabase : DatabaseReference
var mAuth = FirebaseAuth.getInstance()
var user = FirebaseAuth.getInstance().currentUser
var DISPLAY_NAME : String? = null
#SuppressLint("SetTextI18n", "ResourceType")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// setContentView(R.layout.fragment_notifications)
val rootView: View = inflater.inflate(R.layout.fragment_profil_foto, container, false)
Toast.makeText(this.requireContext(), "Profil", Toast.LENGTH_LONG)
Log.e("Halllo", "Hat toll geklapptttt")
val nameTxt: TextView = rootView.findViewById(R.id.textName1)
val emailTxt: TextView = rootView.findViewById(R.id.emailemail)
val spezi = rootView.findViewById<TextView>(R.id.spezialisierungen)
var uid = user!!.uid
val userHashMap = HashMap<String, Any>()
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
val speicherButton = rootView.findViewById<Button>(R.id.speichern)
speicherButton.setOnClickListener {
val telefon = rootView.findViewById<View>(R.id.telnummer) as EditText
val geburtstag = rootView.findViewById<View>(R.id.geburtsdatum) as EditText
val location = rootView.findViewById<View>(R.id.locationPerson) as EditText
val stundenlohn = rootView.findViewById<View>(R.id.stundenlohn) as EditText
val tele = telefon.text.toString()
val gebi = geburtstag.text.toString()
val loc = location.text.toString()
val stundenl = stundenlohn.text.toString()
Log.e("Speichern", "speichert")
if (!gebi.isEmpty()) {
Log.e("Telefon", tele)
//userHashMap["Telefon"] = tele
//mDatabase.child("Telefon").setValue(tele)
mDatabase.child("Telefon").setValue(tele)
.addOnSuccessListener {
Log.e("Telefon", tele)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
}
if (!gebi.isEmpty()) {
Log.e("Geburtstag", gebi)
//userHashMap["Geburtsdatum"] = gebi
mDatabase.child("Geburtstag").setValue(gebi)
.addOnSuccessListener {
Log.e("Telefon", gebi)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
if (!loc.isEmpty()) {
Log.e("Location", loc)
//userHashMap["Adresse"] = loc
mDatabase.child("Adresse").setValue(loc)
.addOnSuccessListener {
Log.e("Telefon", loc)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
if (!stundenl.isEmpty()) {
// userHashMap["Stundenlohn"] = stundenl
mDatabase.child("Stundenlohn").setValue(stundenl)
.addOnSuccessListener {
Log.e("Telefon", stundenl)
}
.addOnFailureListener {
Log.e("Telefon2", "failed")
}
// mDatabase.updateChildren(userHashMap)
}
}
mDatabase.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onDataChange(snapshot: DataSnapshot) {
nameTxt.text = snapshot.child("Name").value.toString()
emailTxt.text = snapshot.child("Email").value.toString()
if (snapshot.child("Spezialisierung").exists()) {
Log.e("Spez", "Ist anscheinend da")
spezi.text = snapshot.child("Spezialisierung").value.toString()
}
/* if (snapshot.child("Telefon").exists()) {
telefon.text = snapshot.child("Telefon").value.toString()
}
*/
}
})
val buttonSignOut : ImageButton? = rootView.findViewById(R.id.signOut_button1)
if (buttonSignOut != null) {
buttonSignOut.setOnClickListener{
mAuth.signOut()
Toast.makeText(this.context, "Signed Out", Toast.LENGTH_LONG).show()
startActivity(Intent(this.context, Start::class.java))
}
}
I just need to figure out how to show the saved information, in the profile after saving it once.

Related

Create a popup menu with edit/delete functions using recycler view

So I want to make a function which opens a popup menu using Recycler view, I've got the card and icons ready but im not sure how to implement into my
StudentAdapter.kt class.
Im new to Kotlin so popup windows are new to me.
I have the code to edit/delete but first of all how do I get the popup menu to work in my recyclerview?
card_items_rec (row for recyclerview)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:padding="1dp"
android:layout_margin="1dp"
android:weightSum="1">
<TextView
android:id="#+id/tvId"
android:layout_width="wrap_content"
android:layout_height="1dp"
tools:text="Id"
tools:visibility="invisible"
tools:ignore="MissingConstraints" />
<TextView
android:id="#+id/tvEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:textAlignment="center"
android:textSize="17dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/tvBuyAmount"
app:layout_constraintHorizontal_bias="0.135"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.533"
tools:text="Date" />
<TextView
android:id="#+id/tvName"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="4dp"
android:textAlignment="center"
android:textSize="17dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/tvBuyAmount"
app:layout_constraintHorizontal_bias="0.94"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Name" />
<TextView
android:id="#+id/tvBuyAmount"
android:layout_width="59dp"
android:layout_height="wrap_content"
android:padding="7dp"
android:textAlignment="center"
android:textSize="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/tvUseAmount"
app:layout_constraintHorizontal_bias="0.885"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="aaa" />
<TextView
android:id="#+id/tvUseAmount"
android:layout_width="49dp"
android:layout_height="wrap_content"
android:layout_marginStart="248dp"
android:padding="7dp"
android:textAlignment="center"
android:textSize="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/deleteBtn"
app:layout_constraintHorizontal_bias="0.269"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="aaa" />
<ImageView
android:id="#+id/popupButton"
android:layout_width="67dp"
android:layout_height="28dp"
android:layout_marginStart="28dp"
android:src="#drawable/ic_menu_more"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="#+id/tvUseAmount"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/deleteBtn"
android:layout_width="67dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="削除"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.982"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
show_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/editText"
android:title="編集"
android:icon="#drawable/ic_edit" />
<item
android:id="#+id/delete"
android:title="削除"
android:icon="#drawable/ic_delete" />
</menu>
Student.adapter.kt
class StudentAdapter: RecyclerView.Adapter<StudentAdapter.StudentViewHolder>() {
private var stdList: ArrayList<StudentModel> = ArrayList()
private var onClickItem: ((StudentModel) -> Unit)?=null
private var onClickDeleteItem: ((StudentModel) -> Unit)?=null
fun addItems(items: ArrayList<StudentModel>){
this.stdList=items
notifyDataSetChanged()
}
fun setOnClickItem(callback:(StudentModel)->Unit){
this.onClickItem = callback
}
fun setOnClickDeleteItem(callback: (StudentModel) -> Unit){
this.onClickDeleteItem = callback
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)= StudentViewHolder (
LayoutInflater.from(parent.context).inflate(R.layout.card_items_rec,parent,false)
)
override fun onBindViewHolder(holder: StudentViewHolder, position: Int) {
val std = stdList[position]
holder.bindView(std)
holder.itemView.setOnClickListener{onClickItem?.invoke(std)}
holder.btnDelete.setOnClickListener{onClickDeleteItem?.invoke(std)}
}
override fun getItemCount(): Int {
return stdList.size
}
class StudentViewHolder(var view: View):RecyclerView.ViewHolder(view){
var id:TextView = view.findViewById<TextView>(R.id.tvId)
var name:TextView = view.findViewById<TextView>(R.id.tvName)
var email:TextView = view.findViewById<TextView>(R.id.tvEmail)
var buyAmount:TextView = view.findViewById<TextView>(R.id.tvBuyAmount)
var useAmount:TextView = view.findViewById<TextView>(R.id.tvUseAmount)
var btnDelete:Button = view.findViewById<Button>(R.id.deleteBtn)
var popupButton: ImageView = view.findViewById(R.id.popupButton)
fun bindView(std:StudentModel){
id.text = std.id.toString()
name.text = std.name
email.text = std.email
buyAmount.text = std.buyamount.toString()
useAmount.text = std.useamount.toString()
}
}
}
allRecordPage.kt
class allRecordpage : AppCompatActivity() {
private lateinit var edName: EditText
private lateinit var edEmail: Button
private lateinit var edBuyAmount: EditText
private lateinit var edUseAmount: EditText
private lateinit var edReason: EditText
private lateinit var btnAdd: Button
private lateinit var btnView: Button
private lateinit var btnUpdate: Button
private lateinit var sqLiteHelper: SQLiteHelper
private lateinit var recyclerView: RecyclerView
private var adapter: StudentAdapter?=null
private var std:StudentModel?=null
val dataHolder = "DataHolder"
#RequiresApi(Build.VERSION_CODES.N)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_all_recordpage)
val textView: TextView =findViewById(R.id.DateText)
val simpleDateFormat= SimpleDateFormat("yyyy/MM/dd\n HH:mm", Locale.getDefault()).format(
Date()
)
val currentDateAndTime: String = simpleDateFormat.format(Date())
textView.text = currentDateAndTime
val button = findViewById<Button>(R.id.goBackToHome)
button.setOnClickListener{
val intent = Intent(this,MainMenu::class.java)
startActivity(intent)
}
initView()
initRecyclerView()
sqLiteHelper= SQLiteHelper(this)
//Show recycler view
val stdList = sqLiteHelper.getAllStudent()
Log.e("おっけ","${stdList.size}")
adapter?.setOnClickItem {
//購入・使用編集画面に遷移
if(it.buyamount > 0){
val intent = Intent(this,buyDetailsScreen::class.java)
intent.putExtra("date",it.email)
intent.putExtra("name", it.name)
intent.putExtra("buyAmount", it.buyamount)
startActivity(intent)
}else if (it.useamount > 0){
val intent = Intent(this,useDetailsScreen::class.java)
intent.putExtra("date",it.email)
intent.putExtra("name",it.name)
intent.putExtra("useAmount",it.useamount)
intent.putExtra("reason",it.reason)
startActivity(intent)
}else{
Toast.makeText(this,"エラーが発生しました",Toast.LENGTH_LONG).show()
}
}
adapter?.addItems(stdList)
adapter?.setOnClickDeleteItem{
deleteStudent(it.id)
}
}
private fun deleteStudent(id:Int){
val builder = AlertDialog.Builder(this)
builder.setMessage("データを削除してよろしいですか")
builder.setCancelable(true)
builder.setNegativeButton("いいえ"){dialog, _ ->
dialog.dismiss()
}
builder.setPositiveButton("はい"){dialog, _ ->
sqLiteHelper.deleteStudentById(id)
getStudents()
dialog.dismiss()
}
val alert = builder.create()
alert.show()
}
private fun updateStudent(){
val name = edName.text.toString()
val email = edEmail.text.toString()
val buyAmount = edBuyAmount.text.toString().toInt()
val useAmount = edUseAmount.text.toString().toInt()
val reason = edReason.text.toString()
//Check record not changed
if(name == std?.name && email == std?.email && buyAmount == std?.buyamount && useAmount == std?.useamount && reason == std?.reason){
Toast.makeText(this,"データが変更されてない", Toast.LENGTH_SHORT).show()
return
}
if(std == null) return
val std = StudentModel(id=std!!.id,name = name,email = email, buyamount = buyAmount, useamount = useAmount, reason = reason)
val status = sqLiteHelper.updateStudent(std)
if(status > -1){
clearEditText()
getStudents()
}else{
Toast.makeText(this,"更新失敗した", Toast.LENGTH_SHORT).show()
}
}
private fun getStudents(){
val stdList = sqLiteHelper.getAllStudent()
Log.e("おっけ","${stdList.size}")
adapter?.addItems(stdList)
}
private fun addStudent(){
val name = edName.text.toString()
val email = edEmail.text.toString()
val buyAmount = edBuyAmount.text.toString().toInt()
val useAmount = edUseAmount.text.toString().toInt()
val reason = edReason.text.toString()
if(name.isEmpty()||email.isEmpty()|| buyAmount.toString().isEmpty() ||useAmount.toString().isEmpty() || reason.toString().isEmpty()){
Toast.makeText(this,"データを入力してください", Toast.LENGTH_SHORT).show()
}else{
val std = StudentModel(name = name, email=email, buyamount=buyAmount, useamount=useAmount, reason = reason)
val status = sqLiteHelper.insertStudent(std)
//Check Insert success or not success
if(status > -2){
Toast.makeText(this,"データを追加しました。", Toast.LENGTH_SHORT).show()
clearEditText()
}else{
Toast.makeText(this,"データが保存されてないようです。", Toast.LENGTH_SHORT).show()
}
}
}
private fun clearEditText(){
edName.setText("")
edEmail.text = ""
edBuyAmount.setText("")
edUseAmount.setText("")
edReason.setText("")
edName.requestFocus()
}
private fun initRecyclerView(){
recyclerView.layoutManager=LinearLayoutManager(this)
adapter = StudentAdapter()
recyclerView.adapter=adapter
}
private fun initView(){
recyclerView=findViewById(R.id.recyclerView)
}
}
I have the code to edit/delete but first of all how do I get the popup menu to work in my recyclerview?

Trying to display an entire collection from my Firestore database using RecyclerView and Fragments - Kotlin

I have tried many different tutorials and haven't been able to relate any to my application. My application in a gist displays a user's medication that they are taking. Here is my data class...
import java.util.HashMap
class LocalMedication {
var m_medicationName: String? = null
var m_medicationQty: String? = null
var m_medicationType: String? = null
var m_medicationExpDate: String? = null
var m_medicationStatus: Boolean = false
constructor() {}
constructor(medicationName: String, medicationQty: String, medicationType: String, medicationExpDat : String, medicationStatus : Boolean) {
this.m_medicationName = medicationName
this.m_medicationType = medicationType
this.m_medicationQty = medicationQty
this.m_medicationExpDate = medicationExpDat
this.m_medicationStatus = medicationStatus
}
fun toMap(): Map<String, Any> {
val result = HashMap<String, Any>()
result.put("medicationName", m_medicationName!!)
result.put("medicationType", m_medicationType!!)
result.put("medicationQty", m_medicationQty!!)
result.put("medicationExpDate", m_medicationExpDate!!)
result.put("medicationStatus", m_medicationStatus!!)
return result
}
}
Here is my view holder class
package com.example.home_med.viewHolder
import android.view.View
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.home_med.R
class medicationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var medicationName: TextView
var medicationType: TextView
var medicationQty: TextView
init {
medicationName = view.findViewById(R.id.rv_medicationName)
medicationType = view.findViewById(R.id.rv_medicationType)
medicationQty = view.findViewById(R.id.rv_medicationQty)
}
}
Here is my fragment
class LocalMedication : Fragment() {
private var adapter: FirestoreRecyclerAdapter<LocalMedication, medicationViewHolder>? = null
private var firestoreDB: FirebaseFirestore? = null
private var firestoreListener: ListenerRegistration? = null
private var medList = mutableListOf<LocalMedication>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_main)
firestoreDB = FirebaseFirestore.getInstance()
val recyclerView = recyclerview as? RecyclerView
val mLayoutManager = LinearLayoutManager(context)
recyclerView?.layoutManager = mLayoutManager
recyclerView?.itemAnimator = DefaultItemAnimator()
loadMedication()
firestoreListener = firestoreDB!!.collection("notes")
.addSnapshotListener(EventListener { documentSnapshots, e ->
if (e != null) {
Log.e(TAG, "Listen failed!", e)
return#EventListener
}
medList = mutableListOf()
if (documentSnapshots != null) {
for (doc in documentSnapshots) {
val note = doc.toObject(LocalMedication::class.java)
note.m_medicationName = doc.id
medList.add(note)
}
}
adapter!!.notifyDataSetChanged()
recyclerView?.adapter = adapter
})
}
override fun onDestroy() {
super.onDestroy()
firestoreListener!!.remove()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val binding: FragmentLocalMedicationBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_local_medication, container, false)
binding.viewMedicationButton.setOnClickListener { v: View ->
v.findNavController().navigate(LocalMedicationDirections.actionLocalMedicationToViewMedication())
}
binding.addMedicationButton.setOnClickListener { v: View ->
v.findNavController().navigate(LocalMedicationDirections.actionLocalMedicationToAddMedication())
}
binding.homeButton.setOnClickListener { v: View ->
v.findNavController().navigate(LocalMedicationDirections.actionLocalMedicationToHome2())
}
setHasOptionsMenu(true)
return binding.root
}
private fun loadMedication() {
val query = firestoreDB!!.collection("notes")
val response = FirestoreRecyclerOptions.Builder<LocalMedication>()
.setQuery(query, LocalMedication::class.java)
.build()
adapter = object : FirestoreRecyclerAdapter<LocalMedication, medicationViewHolder>(response) {
override fun onBindViewHolder(holder: medicationViewHolder, position: Int, model: LocalMedication) {
val note = medList[position]
holder.medicationName.text = note.m_medicationName
holder.medicationType.text = note.m_medicationType
holder.medicationQty.text = note.m_medicationQty
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): medicationViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.recyclerview_item, parent, false)
return medicationViewHolder(view)
}
override fun onError(e: FirebaseFirestoreException) {
Log.e("error", e!!.message)
}
}
adapter!!.notifyDataSetChanged()
recyclerview?.adapter = adapter
}
public override fun onStart() {
super.onStart()
adapter!!.startListening()
}
public override fun onStop() {
super.onStop()
adapter!!.stopListening()
}
}
Here is my recyclerViewItem XML file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/rv_medicationName"
style="#style/word_title"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="#android:color/holo_orange_light"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/rv_medicationQty"
style="#style/word_title"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="#android:color/holo_orange_light"
app:layout_constraintStart_toEndOf="#+id/rv_medicationName"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/rv_medicationType"
style="#style/word_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:background="#android:color/holo_orange_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/rv_medicationQty"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
Here is my localMedications XML file
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".LocalMedication">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="32dp"
android:text="LOCAL MEDICATION"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.478"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="543dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="#android:color/darker_gray"
app:layout_constraintBottom_toTopOf="#+id/homeButton"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView"
tools:listitem="#layout/recyclerview_item" />
<Button
android:id="#+id/viewMedicationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="100dp"
android:layout_marginBottom="100dp"
android:text="View Med"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Button
android:id="#+id/addMedicationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginBottom="100dp"
android:text="Add Medication"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/homeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="59dp"
android:layout_marginEnd="30dp"
android:layout_marginBottom="103dp"
android:text="Home"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/viewMedicationButton"
app:layout_constraintStart_toEndOf="#+id/addMedicationButton"
app:layout_constraintTop_toBottomOf="#+id/addMedicationButton"
app:layout_constraintVertical_bias="0.972" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Here is what my database looks like...
Datatbase
Any help or guidance would be great. It runs the application, but in the Logs, it says "RecyclerView: No adapter attached; skipping layout"
The problem in your code lies in the fact that the names of the fields in your LocalMedication class are different than the name of the properties in your database. You have in your LocalMedication class a field named m_medicationName while in your database I see it as medicationName and this is not correct. The names must match. Behind the scene, Kotlin is creating a Java class with a getter named getM_medicationName() so Firebase is looking in the database for a field named m_medicationName and not medicationName.
There are two ways in which you can solve this problem. The first one would be to remove the data in your database and add it again using field names (m_medicationName, m_medicationQty etc) that exist in your LocalMedication class.
If you are not allowed to use the first solution, then the second approach will be to use annotations in front of your public fields. So you should use the PropertyName annotation in front of every field. So in your LocalMedication class, a field should look like this:
#get:PropertyName("medicationName")
#set:PropertyName("medicationName")
public var m_medicationName: String? = null
As explained in my answer from the following post:
I am trying to get the correct reference to my Firebase Database child and set the values in my RecyclerView but I am having some issues
It's for Firebase realtime database but the same rules apply to Cloud Firestore.

Kotlin - custom dialog in Android

I want to create a custom dialog in Kotlin. I looked through questions on this theme on Stack Overflow, but I could not find any useful information. How can I do it?
You can use below code for a custom Dialog. It's my working code.
private fun showDialog(title: String) {
val dialog = Dialog(activity)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(false)
dialog.setContentView(R.layout.custom_layout)
val body = dialog.findViewById(R.id.body) as TextView
body.text = title
val yesBtn = dialog.findViewById(R.id.yesBtn) as Button
val noBtn = dialog.findViewById(R.id.noBtn) as Button
yesBtn.setOnClickListener {
dialog.dismiss()
}
noBtn.setOnClickListener {
dialog.dismiss()
}
dialog.show()
}
custom_dialog.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/fitsdk_white_rectangle"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="30dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="30dp"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/error_timeout_title"
android:textColor="#color/black" />
<TextView
android:id="#+id/tvBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="#string/error_timeout_body"
android:textColor="#color/black" />
<Button
android:id="#+id/btn_yes"
android:layout_width="100dp"
android:layout_height="30dp"
android:background="#android:color/white"
android:clickable="true"
android:text="Yes"
android:textColor="#5DBCD2"
android:textStyle="bold" />
</LinearLayout>
</FrameLayout>
CustomDialogClass.kt
class CustomDialogClass(context: Context) : Dialog(context) {
init {
setCancelable(false)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.custom_dialog)
}
}
Below my solution as a kind of "message box".
I have not implemented an "OK" button. The message box should close after clicking on it.
Here the layout element (*/layout/message_box.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:orientation="vertical">
<TextView
android:id="#+id/message_box_header"
android:layout_width="match_parent"
android:layout_height="30dp"
android:textAlignment="center"
android:textSize="20sp" />
<TextView
android:id="#+id/message_box_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
This function I've implement in a Fragment class. It is written in Kotlin.
fun showMessageBox(text: String){
//Inflate the dialog as custom view
val messageBoxView = LayoutInflater.from(activity).inflate(R.layout.message_box, null)
//AlertDialogBuilder
val messageBoxBuilder = AlertDialog.Builder(activity).setView(messageBoxView)
//setting text values
messageBoxView.message_box_header.text = "This is message header"
messageBoxView.message_box_content.text = "This is message content"
//show dialog
val messageBoxInstance = messageBoxBuilder.show()
//set Listener
messageBoxView.setOnClickListener(){
//close dialog
messageBoxInstance.dismiss()
}
}
you have a clean codes on an extension function of context in kotlin and use it on
all of your codes
fun Context.showDialog(
title: String,
description: String,
titleOfPositiveButton: String? = null,
titleOfNegativeButton: String? = null,
positiveButtonFunction: (() -> Unit)? = null,
negativeButtonFunction: (() -> Unit)? = null
) {
val dialog = Dialog(this, R.style.Theme_Dialog)
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) // if you have blue line on top of your dialog, you need use this code
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.setCancelable(false)
dialog.setContentView(R.layout.dialog_custom_layout)
val dialogTitle = dialog.findViewById(R.id.title) as TextView
val dialogDescription = dialog.findViewById(R.id.description) as TextView
val dialogPositiveButton = dialog.findViewById(R.id.positiveButton) as TextView
val dialogNegativeButton = dialog.findViewById(R.id.negativeButton) as TextView
dialogTitle.text = title
dialogDescription.text = description
titleOfPositiveButton?.let { dialogPositiveButton.text = it } ?: dialogPositiveButton.makeGone()
titleOfNegativeButton?.let { dialogNegativeButton.text = it } ?: dialogNegativeButton.makeGone()
dialogPositiveButton.setOnClickListener {
positiveButtonFunction?.invoke()
dialog.dismiss()
}
dialogNegativeButton.setOnClickListener {
negativeButtonFunction?.invoke()
dialog.dismiss()
}
dialog.show()
}
and this is a sample of use this function
requireContext().showDialog(
title = "Your Title",
description = "Your Description",
titleOfPositiveButton = "yes",
titleOfNegativeButton = "No",
positiveButtonFunction = { // Run codes after click on positive button },
negativeButtonFunction = { // Run codes after click on negative button }
)
and you need to have style for constant with on design of your dialog
<style name="Theme_Dialog" parent="android:Theme.Holo.Dialog">
<item name="android:windowMinWidthMajor">90%</item>
<item name="android:windowMinWidthMinor">90%</item>
</style>
This is the way by which you can create your own dialog with custom layout.
val dialogBuilder = AlertDialog.Builder(context, R.style.AlertDialogTheme)
val inflater = this.layoutInflater
val dialogView = inflater.inflate(R.layout.layout_chat_type_selection, null)
dialogBuilder.setView(dialogView)
val radioGroupChat = dialogView.radio_group_chat
dialogView.radioButton_user_chat.isChecked = true
dialogBuilder.setPositiveButton(getString(R.string.ok_text), object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, id: Int) {
when (radioGroupChat.checkedRadioButtonId) {
R.id.radioButton_user_chat -> {
(activity as HomeActivity).replaceFragment(MySkippersFragment.getInstance(isFromChat = true))
}
R.id.radioButton_circle_chat -> {
(activity as HomeActivity).replaceFragment(PickCircleFragment.getInstance(
PickCircleFragment.NEW_CIRCLE_CHAT), true)
}
}
}
})
dialogBuilder.setNegativeButton(getString(R.string.cancel_text), object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface?, which: Int) {
}
})
val alertDialog = dialogBuilder.create()
alertDialog.show()
Works fine. You can also customize it the way you want.
Main class:
class CustomAlertDialogOneButton( activity: Activity?,
private val alertOneButtonClickListener: OnAlertOneButtonClickListener):Dialog(activity!!) {
private var title = ""
private var text = ""
private var dialogId = -1
private var buttonName = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.custom_alert_one_button_dialog)
setCancelable(false)
this.window?.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
viewsClickListenerInit()
}
override fun onStart() {
initDialog()
super.onStart()
}
private fun fillFields(title: String, text: String?, dialogId: Int, buttonName: String) {
clearDialog()
this.title = title
this.text = text ?: ""
this.dialogId = dialogId
this.buttonName = buttonName
}
private fun clearDialog() {
title = ""
text = ""
}
private fun initDialog() {
if (title.isNotBlank()) {
tvAlertTitle.text = title
}
if (text.isNotBlank()) {
tvAlertText.text = text
}
tvAlertButtonOk.text = buttonName
}
fun show(title: String, text: String?, dialogId: Int = -1, buttonName: String = ResourcesRepository.resources.getString(R.string.ok)) {
fillFields(title, text, dialogId, buttonName)
super.show()
}
private fun viewsClickListenerInit() {
tvAlertButtonOk.setOnClickListener {
alertOneButtonClickListener.okClickListener(dialogId)
dismiss()
}
}}
XML for it: name it likes - custom_alert_one_button_dialog.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="280dp"
android:layout_height="145dp"
android:background="#color/colorWhite"
android:orientation="vertical">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<TextView
android:id="#+id/tvAlertTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingTop="22dp"
android:textAlignment="center"
android:textColor="#color/colorDarkGrey"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvAlertText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingTop="13dp"
android:paddingEnd="24dp"
android:paddingBottom="10dp"
android:textColor="#color/colorGrey"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvAlertTitle" />
<TextView
android:id="#+id/tvAlertButtonOk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:paddingEnd="34dp"
android:paddingBottom="18dp"
android:text="#string/ok"
android:textColor="#color/colorDarkGrey"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
Interface for button click listener:
interface OnAlertOneButtonClickListener {
fun okClickListener(dialogId: Int = -1)}
Implementation:
class SomeActivity : AppCompatActivity(), OnAlertOneButtonClickListener {
****
private var customDialogOneButton by lazy {
CustomAlertDialogOneButton(this, this)
}
****
customDialogOneButton.show(
title = "some title",
text = "some text",
dialogId = some int constant,
buttonName = "some button name"
)
****
override fun okClickListener(dialogId: Int) {
when (dialogId) {
some int constant -> {
// call method
}
}
}
My custom dialog xml file:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/dialogWindowBackground">
<TextView
android:id="#+id/popup_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16sp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16sp"
android:layout_marginBottom="10dp"
android:text="#string/body"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<LinearLayout
android:id="#+id/linearLayoutOpt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16sp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16sp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/popup_dialog">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:orientation="horizontal">
<TextView
android:id="#+id/no_opt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingTop="8dp"
android:paddingRight="8dp"
android:paddingBottom="18dp"
android:text="No"
android:textAllCaps="false"
android:textColor="#color/colorAccent" />
<Space
android:layout_width="32sp"
android:layout_height="12sp" />
<TextView
android:id="#+id/yes_opt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingTop="8dp"
android:paddingRight="8dp"
android:paddingBottom="18dp"
android:text="Yes"
android:textAllCaps="false"
android:textColor="#color/colorAccent" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
My Kotlin code:
private fun showDialog() {
val customDialog = Dialog(requireActivity())
customDialog.setContentView(R.layout.custom_dialog)
customDialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
val yesBtn = customDialog.findViewById(R.id.yes_opt) as TextView
val noBtn = customDialog.findViewById(R.id.no_opt) as TextView
yesBtn.setOnClickListener {
//Do something here
customDialog.dismiss()
}
noBtn.setOnClickListener {
customDialog.dismiss()
}
customDialog.show()
}
If someone wants to show 2 buttons on dialog ( GENERIC SOLUTION ) KOTLIN
fun createCustomTwoButtonDialog(
msg: String, context: Context?
, positiveButtonText: String, negativeButtonText: String,
isCancellable: Boolean,
dialogListener: DialogListener
) {
context?.let { context ->
val builder =
AlertDialog.Builder(context)
builder.setTitle("Your desired title")
builder.setMessage(msg)
builder.setCancelable(isCancellable)
builder.setPositiveButton(positiveButtonText) { dialogInterface: DialogInterface?, i: Int ->
dialogListener.onPositiveClick()
dialogInterface?.dismiss()
}
builder.setNegativeButton(negativeButtonText)
{ dialogInterface: DialogInterface?, i: Int ->
dialogListener.onNegativeClick()
dialogInterface?.dismiss()
}
val alertDialog = builder.create()
alertDialog.show()
}
}
DialogListener is interface with 2 methods onNegativeClick() and onPositiveClick()
I created this Kotlin Class :
class AnimDialog(private val context: Context) {
private val dialog = Dialog(context)
fun test(s: String) {
Log.i("TAG", "test: $s")
}
init{
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
fun one(headerImage :Int?=null,
description: String,
titleOfPositiveButton: String? = null,
titleOfNegativeButton: String? = null,
positiveButtonFunction: (() -> Unit)? = null,
negativeButtonFunction: (() -> Unit)? = null
) :Dialog{
dialog.setCancelable(false)
dialog.setContentView(R.layout.dialog_one)
val dialogHeaderImage=dialog.findViewById(R.id.imageHead_dia) as ImageView
val dialogDescription = dialog.findViewById(R.id.description) as TextView
val dialogPositiveButton = dialog.findViewById(R.id.positiveButton) as Button
val dialogNegativeButton = dialog.findViewById(R.id.negativeButton) as Button
headerImage?.let { dialogHeaderImage.setImageResource(it) }
dialogHeaderImage.
startAnimation(
AnimationUtils.loadAnimation(
context,
R.anim.bounce
)
)
dialogDescription.text = description
titleOfPositiveButton?.let { dialogPositiveButton.text = it } ?: dialogPositiveButton.text
titleOfNegativeButton?.let { dialogNegativeButton.text = it } ?: dialogNegativeButton.text
dialogPositiveButton.setOnClickListener {
positiveButtonFunction?.invoke()
dialog.dismiss()
}
dialogNegativeButton.setOnClickListener {
negativeButtonFunction?.invoke()
dialog.dismiss()
}
return dialog
}
Where you must define :
1- Layout <dialog_one> include positive btn, negative btn, image view, text view
2- Animation <bounce> if you would like add anim to the header image
Now in Activity:
val animDialog = AnimDialog(this)
animDialog.one(
headerImage = android.R.drawable.ic_delete,
description = "Sometimes we looking for new dialog to fill better \n ",
titleOfPositiveButton = "Accept it",
titleOfNegativeButton = "Not now",
positiveButtonFunction = {
animDialog.test("OK")
},
negativeButtonFunction = {
animDialog.test("NO")
}).show()

How to display data in RecyclerView using Retrofit2 API?

First of all, I'm new to Android/Java/Kotlin development. I'm using Retrofit2 to retrieve data from Udacity API. I can see the response in the Logcat, but when I try to display it in RecyclerView there is just a blank screen. I think the error is in the MainActivity, but I'm still clueless and need help.
My model classes
class Course(var title: String,
var subtitle: String,
var key: String,
var instructors: List<Instructor>,
var expected_learning: String,
var required_knowledge: String)
class Instructor(var name: String,
var bio: String)
My interface
interface ApiServiceInterface {
#GET("courses")
fun list() : Call<UdacityCatalog>
}
My adapter
class CourseAdapter(val listCourses: ArrayList<Course?>, val context: Context) : RecyclerView.Adapter<CourseAdapter.CourseViewHolder>() {
class CourseViewHolder(viewItem: View) : RecyclerView.ViewHolder(viewItem) {
val courseTitle = viewItem.findViewById<TextView?>(R.id.tv_title) as TextView
val courseSubtitle = viewItem.findViewById<TextView?>(R.id.tv_subtitle) as TextView
val courseKey = viewItem.findViewById<TextView?>(R.id.tv_course_key) as TextView
val instructorName = viewItem.findViewById<TextView?>(R.id.tv_instructor_name) as TextView
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): CourseViewHolder {
val viewHolder = LayoutInflater.from(parent?.context).inflate(R.layout.activity_item_list, parent, false)
val itemViewHolder = CourseViewHolder(viewHolder)
return itemViewHolder
}
override fun onBindViewHolder(holder: CourseViewHolder?, position: Int) {
holder?.courseTitle?.text = listCourses[position].title
holder?.courseSubtitle?.text = listCourses[position].subtitle
holder?.courseKey?.text = listCourses[position].key
holder?.instructorName?.text = listCourses[position].instructors.toString()
}
override fun getItemCount(): Int = listCourses.size
}
My MainActivity -- I think the error is in here, but I haven't figured it out yet
class MainActivity : AppCompatActivity() {
internal val TAG = "Testing Retrofit2 API"
lateinit var mRecyclerView: RecyclerView
lateinit var mCourseAdapter: RecyclerView.Adapter<CourseAdapter.CourseViewHolder>
val listCourse = arrayListOf<Course?>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_recyclerview)
mRecyclerView = findViewById<RecyclerView?>(R.id.id_recycler_view) as RecyclerView
val mLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
mRecyclerView.layoutManager = mLayoutManager
mRecyclerView.setHasFixedSize(true)
mCourseAdapter = CourseAdapter(listCourse, applicationContext)
mRecyclerView.adapter = mCourseAdapter
mCourseAdapter.notifyDataSetChanged()
val call = RetrofitInitializer().createService().list()
call.enqueue(object : Callback<UdacityCatalog> {
override fun onResponse(call: Call<UdacityCatalog>, response: Response<UdacityCatalog>) {
response.body()
if (!response.isSuccessful) {
Log.i(TAG, "[ ERROR ] " + response.code())
} else {
if (listCourse.isEmpty()) {
Toast.makeText(applicationContext, "Empty list!", Toast.LENGTH_LONG).show()
} else {
Toast.makeText(applicationContext, "Full list!", Toast.LENGTH_LONG).show()
}
val catalog = response.body()
for (c in catalog!!.courses!!) {
Log.i(TAG, String.format("%s: %s", c.title, c.subtitle, c.key, c.required_knowledge, c.expected_learning))
for (i in c.instructors!!) {
Log.i(TAG, i.name)
}
Log.i(TAG, "\n****************************************************************************************************\n")
}
}
}
override fun onFailure(call: Call<UdacityCatalog>?, t: Throwable?) {
Log.d(TAG, "onFailure() : " + t?.message)
}
})
}
}
An initializer class for Retrofit instance
class RetrofitInitializer {
companion object Factory {
val BASE_URL = "https://www.udacity.com/public-api/v0/"
}
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
fun createService(): ApiServiceInterface = retrofit.create(ApiServiceInterface::class.java)
}
My RecyclerView xml file
<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
tools:context="activities.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/id_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
My CardView xml file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/udacity_catalog"
android:textAppearance="?android:textAppearanceLarge"
android:textColor="#9C27B0"
android:textStyle="bold" />
<TextView
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_title"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_subtitle"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_course_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_key"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_instructor_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_name"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
</LinearLayout>
</android.support.v7.widget.CardView>
You have an empty list of courses (listCourse) in your Activity. You pass that empty list to the adapter via it's constructor.
That list stays empty even after you fetched the courses. So the adapter / RecyclerView stays empty.
Try creating the adapter after you fetched the courses, with
mCourseAdapter = CourseAdapter(catalog!!.courses!!, applicationContext)
or have a courses property in your adapter lile
YourAdapter(...) {
var courses = listOf(Course)
}
and then in your Activity (after fetching the courses):
adapter.courses = catalog!!.courses!!
adapter.notifyDataSetChanged()

livedata recyclerview with checkbox

I am implementing android architecture component to view buyers list and select one.
Here is my Buyer entity
#Entity
data class Buyer(#PrimaryKey var id: Long = 0, var name: String = "", var photo: String = "", var address: String = "",
#Ignore var isSelected: Boolean = false,
#SerializedName("last_update_time") var lastUpdateTime: Long = 0L) {
}
I have inserted and displayed it in recyclerview.
What I want is to know how can I display particular buyer is selected, when click on one buyer.
If I click on one buyer previous selected buyer must deselect.
Please help me to implement this.
EDIT
class BuyerAdapter(private var buyers: ArrayList<Buyer>, private val listener: View.OnClickListener) : RecyclerView.Adapter<BuyerViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BuyerViewHolder {
val v = LayoutInflater.from(parent.context).inflate(
R.layout.item_buyer, parent, false)
return BuyerViewHolder(v)
}
override fun onBindViewHolder(holder: BuyerViewHolder, position: Int) {
bindView(holder, position)
}
private fun bindView(holder: BuyerViewHolder, position: Int) {
val buyer = buyers[position]
holder.setName(buyer.name)
holder.setAddress(buyer.address)
holder.loadImage(ServiceHandler.BASE_URL + buyer.photo)
if (buyer.isSelected) {
holder.setCardColor(R.color.waveBlue)
holder.setNameColor(R.color.white)
holder.setAddressColor(R.color.white)
} else {
holder.setCardColor(R.color.white)
holder.setNameColor(R.color.contentGrey)
holder.setAddressColor(R.color.contentGreyDesc)
}
holder.itemView.tag = buyer
holder.itemView.setOnClickListener(listener)
}
override fun getItemCount(): Int = buyers.size
fun refresh(newBuyers: ArrayList<Buyer>) {
this.buyers = newBuyers
notifyDataSetChanged()
}
}
And here is my adapter xml item
<?xml version="1.0" encoding="utf-8"?><!--<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"--><!--xmlns:card_view="http://schemas.android.com/apk/res-auto"--><!--android:layout_width="match_parent"--><!--android:layout_height="191dp"--><!--android:paddingTop="13dp"--><!-->-->
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/buyer_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="4dp"
android:clickable="true"
card_view:cardCornerRadius="2dp"
card_view:cardElevation="4dp"
card_view:cardPreventCornerOverlap="true">
<android.support.constraint.ConstraintLayout
android:id="#+id/rlBuyerBack"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp">
​
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/ivLogo"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="centerCrop"
android:src="#drawable/placeholder_profile_photo"
card_view:layout_constraintBottom_toBottomOf="parent"
card_view:layout_constraintLeft_toLeftOf="parent"
card_view:layout_constraintTop_toTopOf="parent" />
<in.motiontech.wave.helper.WaveTextView
android:id="#+id/tvName"
style="#style/semiBoldFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="Name"
android:textColor="#color/contentGrey"
android:textSize="#dimen/tSizeHeader"
card_view:layout_constraintLeft_toRightOf="#+id/ivLogo"
card_view:layout_constraintTop_toTopOf="#+id/ivLogo" />
<in.motiontech.wave.helper.WaveTextView
android:id="#+id/tvAddress"
style="#style/regularFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#id/tvName"
android:layout_below="#+id/tvName"
android:layout_marginLeft="8dp"
android:layout_marginTop="2dp"
android:text="Address"
android:textColor="#color/contentGrey"
android:textSize="#dimen/tSizeDesc"
card_view:layout_constraintLeft_toRightOf="#+id/ivLogo"
card_view:layout_constraintTop_toBottomOf="#+id/tvName" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
Edit 2
Here how I added data in recyclerview
viewModel.getBuyers().observe(this, Observer<List<Buyer>> {
if (it != null) {
if (it.isEmpty()) {
showProgress()
if (CommonUtils.isInNetwork(this)) {
viewModel.getBuyerList()
} else {
CommonUtils.showNoInternetDialog(this)
}
} else {
hideProgress()
buyerAdapter?.refresh(ArrayList(it))
}
}
})
What I have done is I have updated value of livedata. You can see below code:
fun selectBuyer(buyer: Buyer?) {
if (buyer == null)
return
buyers.value?.filter { it != buyer }?.forEach { it.isSelected = false }
buyers.value?.get(buyers.value!!.indexOf(buyer))?.isSelected = true
newBuyer = buyer
}
I notice there is no need to notifyupdate, as I am using observer pattern

Categories

Resources