I am making a quiz app. My main activity has blocks. Each block has a date written over it. the date act as title while fetching information from firebase. These blocks are working perfectly fine, (fetching questions).I also have a floating action button, on clicking displays a calender and we can select date from there and access quiz for that particular day, but it is not working .
Home screen : home screen
Interface while accessing question from block : image
Interface while accessing through floating action bar :image
Main Activity:
package com.example.quiz.activities
import android.annotation.SuppressLint
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.recyclerview.widget.GridLayoutManager
import com.example.quiz.R
import com.example.quiz.adapters.QuizAdapter
import com.example.quiz.databinding.ActivityMainBinding
import com.example.quiz.models.Quiz
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.firebase.firestore.DocumentSnapshot
import com.google.firebase.firestore.FirebaseFirestore
import java.text.SimpleDateFormat
import java.util.*
class MainActivity() : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
lateinit var adapter: QuizAdapter
private var quizList = mutableListOf<Quiz>()
lateinit var firestore : FirebaseFirestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setUpViews()
}
fun setUpViews(){
setUpFirestore()
setUpDrawerLayout()
setUpRecyclerView()
setUpDatePicker()
}
#SuppressLint("SimpleDateFormat")
private fun setUpDatePicker() {
// val btnDatePicker = binding.btnDatePicker
binding.btnDatePicker.setOnClickListener{
val datePicker = MaterialDatePicker.Builder.datePicker().build()
datePicker.show(supportFragmentManager,"DatePicker")
datePicker.addOnPositiveButtonClickListener {
Log.d("DATEPICKER",datePicker.headerText)
val dateFormatter = SimpleDateFormat("dd-mm-yyyy")
val date = dateFormatter.format(Date(it))
val intent = Intent(this,QuestionActivity::class.java)
intent.putExtra("DATE",date)
startActivity(intent)
}
datePicker.addOnNegativeButtonClickListener {
Log.d("DATEPICKER",datePicker.headerText)
}
datePicker.addOnCancelListener {
Log.d("DATEPICKER","Date Picker was cancelled")
}
}
}
private fun setUpFirestore() {
firestore = FirebaseFirestore.getInstance()
val collectionReference = firestore.collection("quizzes")
collectionReference.addSnapshotListener{ value, error ->
if(value == null || error != null){
Toast.makeText(this,"Error fetching data",Toast.LENGTH_SHORT).show()
return#addSnapshotListener
}
Log.d("DATA", value.toObjects(Quiz::class.java).toString())
quizList.clear()
quizList.addAll(value.toObjects(Quiz::class.java))
adapter.notifyDataSetChanged()
}
}
private fun setUpRecyclerView(){
val quizRecyclerView = binding.quizRecyclerView
adapter = QuizAdapter(this,quizList)
quizRecyclerView.layoutManager = GridLayoutManager(this,2)
quizRecyclerView.adapter = adapter
}
private fun setUpDrawerLayout(){
val appBar = binding.appBar
val mainDrawer = binding.mainDrawer
val navigationView = binding.navigationView
setSupportActionBar(appBar)
actionBarDrawerToggle = ActionBarDrawerToggle(this,mainDrawer,
R.string.app_name,
R.string.app_name
)
actionBarDrawerToggle.syncState()
navigationView.setNavigationItemSelectedListener {
val intent = Intent(this,ProfileActivity::class.java)
startActivity(intent)
mainDrawer.closeDrawers()
true
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (actionBarDrawerToggle.onOptionsItemSelected(item)){
return true
}
return super.onOptionsItemSelected(item)
}
}
Quiz adapter
package com.example.quiz.adapters
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.RecyclerView
import com.example.quiz.R
import com.example.quiz.activities.QuestionActivity
import com.example.quiz.models.Quiz
import com.example.quiz.utils.ColorPicker
import com.example.quiz.utils.IconPicker
class QuizAdapter(val context: Context, val quizzes: List<Quiz>) :
RecyclerView.Adapter<QuizAdapter.QuizViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuizViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.quiz_item,parent,false)
return QuizViewHolder(view)
}
override fun onBindViewHolder(holder: QuizViewHolder, position: Int) {
holder.textViewTitle.text = quizzes[position].title
holder.cardContainer.setCardBackgroundColor(Color.parseColor(ColorPicker.getColor()))
holder.iconView.setImageResource(IconPicker.getIcon())
holder.itemView.setOnClickListener{
Toast.makeText(context,quizzes[position].title,Toast.LENGTH_SHORT).show()
val intent = Intent(context , QuestionActivity::class.java)
intent.putExtra("DATE",quizzes[position].title)
context.startActivity(intent)
}
}
override fun getItemCount(): Int {
return quizzes.size
}
inner class QuizViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var textViewTitle: TextView = itemView.findViewById(R.id.quizTitle)
var iconView: ImageView = itemView.findViewById(R.id.quizIcon)
var cardContainer: CardView = itemView.findViewById(R.id.cardContainer)
}
}
Question Activity
package com.example.quiz.activities
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import androidx.core.view.allViews
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.quiz.R
import com.example.quiz.adapters.OptionAdapter
import com.example.quiz.databinding.ActivityQuestionBinding
import com.example.quiz.models.Question
import com.google.firebase.firestore.FirebaseFirestore
import com.example.quiz.models.Quiz
import com.google.gson.Gson
class QuestionActivity : AppCompatActivity() {
var quizzes : MutableList<Quiz>? = null
var questions : MutableMap<String,Question>? = null
var index = 1
lateinit var firestore : FirebaseFirestore
private lateinit var binding: ActivityQuestionBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityQuestionBinding.inflate(layoutInflater)
setContentView(binding.root)
setUpFireStore()
setUpEventListener()
}
private fun setUpEventListener() {
val btnPrevious = binding.btnPrevious
val btnSubmit = binding.btnSubmit
val btnNext = binding.btnNext
btnPrevious.setOnClickListener{
index--
bindViews()
}
btnNext.setOnClickListener{
index++
bindViews()
}
btnSubmit.setOnClickListener{
Log.d("FINAL QUIZ",questions.toString())
val intent = Intent(this,ResultActivity::class.java)
val json = Gson().toJson(quizzes!![0])
intent.putExtra("QUIZ",json)
startActivity(intent)
}
}
private fun setUpFireStore() {
val firestore = FirebaseFirestore.getInstance()
var date = intent.getStringExtra("DATE")
if (date!= null){
firestore.collection("quizzes").whereEqualTo("title",date)
.get()
.addOnSuccessListener {
if (it != null && !it.isEmpty){
Log.d("DATA",it.toObjects(Quiz::class.java).toString())
quizzes = it.toObjects(Quiz::class.java)
questions = quizzes!![0].questions
bindViews()
}
else{
Toast.makeText(this,"Error Fetching data",Toast.LENGTH_SHORT).show()
}
}
}
}
private fun bindViews() {
val btnPrevious = binding.btnPrevious
val btnSubmit = binding.btnSubmit
val btnNext = binding.btnNext
val description = binding.description
val optionList = binding.optionList
btnPrevious.visibility = View.GONE
btnSubmit.visibility = View.GONE
btnNext.visibility = View.GONE
if (index == 1) {
btnNext.visibility = View.VISIBLE
}
else if(index == questions!!.size){
btnSubmit.visibility = View.VISIBLE
btnPrevious.visibility = View.VISIBLE
}
else{
btnNext.visibility = View.VISIBLE
btnPrevious.visibility = View.VISIBLE
}
val question = questions!!["question$index"]
question?.let {
description.text = it.description
val optionAdapter = OptionAdapter(this,it)
optionList.layoutManager = LinearLayoutManager(this)
optionList.adapter = optionAdapter
optionList.setHasFixedSize(true)
}
}
}
No logcat error is shown but this error is shown in run section : E/RecyclerView: No adapter attached; skipping layout
Related
I have been trying to call a function from fragment to adapter, but I can't approach it right.
I want to invisible the button present in the fragment from adapter.
**My Adapter Code:**
package com.littleboo.brandlogo.Adapters
import android.R
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.VibrationEffect
import android.os.Vibrator
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat.getSystemService
import androidx.recyclerview.widget.RecyclerView
import com.littleboo.brandlogo.Fragments.QuizFragment
import com.littleboo.brandlogo.MainActivity
import com.littleboo.brandlogo.Models.Question
import com.littleboo.brandlogo.databinding.ActivityMainBinding.inflate
import com.littleboo.brandlogo.databinding.FragmentQuizBinding
import kotlinx.coroutines.NonDisposableHandle.parent
class QuestionAdap(val context: Context, val question: Question) :
RecyclerView.Adapter<QuestionAdap.OptionViewHolder>() {
var index = 1
var score = 0
val animShake: Animation = AnimationUtils.loadAnimation(context, com.littleboo.brandlogo.R.anim.shake)
private var options: List<String> = listOf(question.option1, question.option2, question.option3, question.option4)
inner class OptionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
var optionView = itemView.findViewById<TextView>(com.littleboo.brandlogo.R.id.quiz_option)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OptionViewHolder {
val view = LayoutInflater.from(context).inflate(com.littleboo.brandlogo.R.layout.quizoptions, parent, false)
return OptionViewHolder(view)
}
override fun onBindViewHolder(holder: OptionViewHolder, position: Int) {
holder.optionView.text = options[position]
holder.itemView.setOnClickListener {
question.userAnswer = options[position]
notifyDataSetChanged()
}
if(question.userAnswer == options[position] && question.userAnswer == question.answer){
holder.itemView.setBackgroundResource(com.littleboo.brandlogo.R.drawable.option_item_selected_bg)
score += 10
Toast.makeText(context,"Score is $score", Toast.LENGTH_SHORT).show()
}
else if(question.userAnswer == options[position] && question.userAnswer != question.answer){
holder.itemView.setBackgroundResource(com.littleboo.brandlogo.R.drawable.wrong_option_item_selected_bg)
holder.itemView.startAnimation(animShake)
}
else{
holder.itemView.setBackgroundResource(com.littleboo.brandlogo.R.drawable.non_option_item_selected_bg)
}
}
override fun getItemCount(): Int {
return options.size
}
}
My Quiz Fragment Code:
package com.littleboo.brandlogo.Fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
import com.bumptech.glide.Glide
import com.google.firebase.firestore.FirebaseFirestore
import com.littleboo.brandlogo.Adapters.QuestionAdap
import com.littleboo.brandlogo.Models.Question
import com.littleboo.brandlogo.Models.quizmodel
import com.littleboo.brandlogo.R
import com.littleboo.brandlogo.databinding.FragmentQuizBinding
class QuizFragment : Fragment(){
lateinit var binding: FragmentQuizBinding
var quizzes: MutableList<quizmodel>? = null
private var questions = mutableMapOf<String, Question>()
private lateinit var mArraylist: ArrayList<Question>
var index = 1
private lateinit var mfirestore: FirebaseFirestore
private lateinit var mrecycler: RecyclerView
lateinit var myadapter: QuestionAdap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentQuizBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mrecycler = binding.optionList
mrecycler.layoutManager
myadapter = QuestionAdap(requireContext(),Question())
mArraylist = arrayListOf()
questions.map { it.key to it.value }.shuffled().toMap()
setUpFirestore()
setUpEventListener()
}
override fun onDestroy() {
super.onDestroy()
mfirestore.terminate()
// finish()
}
private fun setUpEventListener() {
binding.nextbtn.setOnClickListener {
index++
bindViews()
}
// binding.btnSubmit.setOnClickListener {
// Log.d("FINALQUIZ", questions.toString())
// val intent = Intent(this, ResultActivity::class.java)
// val json = Gson().toJson(quizzes!![0])
// intent.putExtra("QUIZ", json)
// startActivity(intent)
// finish()
// }
}
private fun setUpFirestore() {
mfirestore = FirebaseFirestore.getInstance()
val quizTitle = activity?.intent?.getStringExtra("title")
if (quizTitle != null) {
mfirestore.collection("Quizes").whereEqualTo("title", quizTitle)
.get()
.addOnSuccessListener {
if (it != null && !it.isEmpty) {
quizzes = it.toObjects(quizmodel::class.java)
questions = quizzes!![0].questions
shuffle()
bindViews()
}
}
}
}
private fun bindViews() {
// btnPrevious.visibility = View.GONE
// binding.btnSubmit.visibility = View.GONE
// binding.btnNext.visibility = View.GONE
// if (index == 1) { //first question
// binding.btnNext.visibility = View.VISIBLE
// } else if (index == questions!!.size) { // last question
// binding.btnSubmit.visibility = View.VISIBLE
//// btnPrevious.visibility = View.VISIBLE
// } else { // Middle
//// btnPrevious.visibility = View.VISIBLE
// binding.btnNext.visibility = View.VISIBLE
// }
val circularProgressDrawable = CircularProgressDrawable(requireContext())
circularProgressDrawable.strokeWidth = 8f
// circularProgressDrawable.colorFilter = ("#ac5fe1")
circularProgressDrawable.centerRadius = 30f
circularProgressDrawable.start()
val question = questions!!["question$index"]
question?.let {
Glide.with(this).load(it.imagequiz).placeholder(circularProgressDrawable).into(binding.imagequiz)
val optionAdapter = QuestionAdap(requireContext(), it)
mrecycler.layoutManager = LinearLayoutManager(requireContext())
mrecycler.adapter = optionAdapter
mrecycler.setHasFixedSize(true)
}
}
private fun shuffle() {
val keys = questions.keys.toMutableList().shuffled()
val values = questions.values.toMutableList().shuffled()
keys.forEachIndexed { index, key ->
questions[key] = values[index]
}
}
}
I tried calling fragment in adapter like:
QuizFragment().binding.btnxt.visibility = View.Visible
in BindViewHolder function.
Thank You
You can use kotlin lambda function to achieve it. Like this
class QuestionAdap(val context: Context, val question: Question, var onItemClicked: ((boolean) -> Unit))
call onItemClicked in your adapter where you want it
and in fragment
myadapter = QuestionAdap(requireContext(),Question()) { boolean ->
if (boolean) {
//hide/show
} else {
//hide/show
}
}
You can use the Callback functions of kotlin in your fragment, which will be passed into your adapter. So whenever you invoke that callback from your adapter, it will be triggered in your fragment.
Step 1: Create a method like the one below in your fragment.
private fun showHideButtonFromAdapter (
isButtonVisible: Boolean
) {
// set your button visibility according to isButtonVisible value.
}
Step 2: pass a method from your fragment to adapter as argument
val adapter = YourAdapter(::showHideButtonFromAdapter)
// set above adapter in your recycler view.
Step 3: In your adapter invoke that callback function like the one below.
class ColorPickerAdapter constructor(
private val onItemClicked: (Boolean) -> Unit
) : RecyclerView.Adapter<YourAdapter.ViewHolder>() {
// your other adapter methods here
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
onItemClicked.invoke(pass true or false as per your requirement)
// above invocation will trigger an event in the fragment.
}
}
In your adapter there need to be instance of your fragment, so change it like:
class QuestionAdap(val context: Context, val question: Question, fragment: Fragment) :
RecyclerView.Adapter<QuestionAdap.OptionViewHolder>() {
Then you can call your fragment by simply writing fragment in your adapter like:
override fun onBindViewHolder(holder: OptionViewHolder, position: Int) {
holder.optionView.text = options[position]
holder.itemView.setOnClickListener {
question.userAnswer = options[position]
notifyDataSetChanged()
}
//Example
fragment.shuffle()
And you need to send this fragment instance when you create it's adapter, so in your fragment use this:
myadapter = QuestionAdap(requireContext(),Question(), this)
I'm hoping to update a Boolean value of data that I have in the list. If checkbox is checked I would like the value to be true, but if the checkbox is unchecked, I would like it to change the value to false, and vice versa.
On clicking the checkbox, I would like it to change the value of 'favourite' in my db to either true or false, depending on whether the checkbox is checked or not. I am unsure how to update this value with a checkbox. Please help! My code is as follows:
Adapter:
package org.wit.hikingtrails.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import org.wit.hikingtrails.databinding.CardHikeBinding
import org.wit.hikingtrails.main.MainApp
import org.wit.hikingtrails.models.HikeModel
import timber.log.Timber.i
interface HikeListener {
fun onHikeClick(hike: HikeModel)
}
class HikeAdapter constructor(private var hikes: List<HikeModel>,
private val listener: HikeListener) :
RecyclerView.Adapter<HikeAdapter.MainHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainHolder {
val binding = CardHikeBinding
.inflate(LayoutInflater.from(parent.context), parent, false)
return MainHolder(binding)
}
override fun onBindViewHolder(holder: MainHolder, position: Int) {
val hike = hikes[holder.adapterPosition]
holder.bind(hike, listener)
}
override fun getItemCount(): Int = hikes.size
class MainHolder(private val binding : CardHikeBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(hike: HikeModel, listener: HikeListener) {
binding.hikeName.text = hike.name
binding.description.text = hike.description
binding.favourite.isChecked = hike.favourite
binding.favourite.setOnClickListener {
hike.favourite = binding.favourite.isChecked
listener.onHikeClick(hike)
}
if (hike.image != ""){
Picasso.get()
.load(hike.image)
.resize(200, 200)
.into(binding.imageIcon)
}
binding.root.setOnClickListener { listener.onHikeClick(hike) }
}
}
}
Presenter:
package org.wit.hikingtrails.views.hikeList
import android.content.Intent
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import com.google.firebase.auth.FirebaseAuth
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.wit.hikingtrails.main.MainApp
import org.wit.hikingtrails.models.HikeModel
import org.wit.hikingtrails.views.BasePresenter
import org.wit.hikingtrails.views.BaseView
import org.wit.hikingtrails.views.VIEW
import org.wit.hikingtrails.views.hike.HikeView
import org.wit.hikingtrails.views.map.HikeMapView
import org.wit.hikingtrails.views.signIn.SignInView
class HikeListPresenter(view: BaseView) : BasePresenter(view) {
var hike = HikeModel()
private lateinit var refreshIntentLauncher : ActivityResultLauncher<Intent>
private lateinit var editIntentLauncher : ActivityResultLauncher<Intent>
init {
registerEditCallback()
registerRefreshCallback()
}
suspend fun getHikes() = app.hikes.findAll()
fun doAddHike() {
val launcherIntent = Intent(view, HikeView::class.java)
editIntentLauncher.launch(launcherIntent)
}
fun doEditHike(hike: HikeModel) {
val launcherIntent = Intent(view, HikeView::class.java)
launcherIntent.putExtra("hike_edit", hike)
editIntentLauncher.launch(launcherIntent)
}
fun doShowHikesMap() {
val launcherIntent = Intent(view, HikeMapView::class.java)
editIntentLauncher.launch(launcherIntent)
}
fun doLogout() {
FirebaseAuth.getInstance().signOut()
val launcherIntent = Intent(view, SignInView::class.java)
editIntentLauncher.launch(launcherIntent)
}
private fun registerRefreshCallback() {
refreshIntentLauncher =
view!!.registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{
GlobalScope.launch(Dispatchers.Main){
getHikes()
}
}
}
private fun registerEditCallback() {
editIntentLauncher =
view!!.registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{ }
}
}
View:
package org.wit.hikingtrails.views.hikeList
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import org.wit.hikingtrails.R
import org.wit.hikingtrails.adapters.HikeAdapter
import org.wit.hikingtrails.adapters.HikeListener
//import org.wit.hikingtrails.databinding.ActivityHikeListBinding
import org.wit.hikingtrails.main.MainApp
import org.wit.hikingtrails.models.HikeModel
import android.content.Intent
import android.view.*
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.wit.hikingtrails.databinding.ActivityHikeListBinding
import org.wit.hikingtrails.views.BaseView
import timber.log.Timber
class HikeListView : BaseView(), HikeListener {
lateinit var app: MainApp
lateinit var binding: ActivityHikeListBinding
lateinit var presenter: HikeListPresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHikeListBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.toolbar.title = title
setSupportActionBar(binding.toolbar)
presenter = HikeListPresenter(this)
val layoutManager = LinearLayoutManager(this)
binding.recyclerView.layoutManager = layoutManager
updateRecyclerView()
}
// override fun showHikes(hikes: List<HikeModel>) {
// recyclerView.adapter = HikeAdapter(hikes, this)
// recyclerView.adapter?.notifyDataSetChanged()
// }
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onResume() {
//update the view
super.onResume()
updateRecyclerView()
binding.recyclerView.adapter?.notifyDataSetChanged()
Timber.i("recyclerView onResume")
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item?.itemId) {
R.id.item_add -> presenter.doAddHike()
R.id.item_map -> presenter.doShowHikesMap()
R.id.logout -> presenter.doLogout()
}
return super.onOptionsItemSelected(item)
}
override fun onHikeClick(hike: HikeModel) {
presenter.doEditHike(hike)
}
private fun updateRecyclerView(){
GlobalScope.launch(Dispatchers.Main){
binding.recyclerView.adapter =
HikeAdapter(presenter.getHikes(), this#HikeListView)
}
}
}
so after uploading my image from gallery my app works fine, but when i try to close and open my app again, on debug console it throws this error java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{ce75251 30290:eu.tuto.youtubeproject/u0a447} (pid=30290, uid=10447) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs here is my code
MainActivity.kt
package eu.tuto.youtubeproject
import android.annotation.SuppressLint
import android.app.Dialog
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.os.Environment.getExternalStorageDirectory
import android.util.Log
import android.view.View
import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import eu.tuto.youtubeproject.ViewModels.SplashScreenViewModel
import eu.tuto.youtubeproject.data.ListData
import eu.tuto.youtubeproject.ViewModels.VideoViewModel
import eu.tuto.youtubeproject.fragments.*
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.popup.view.*
import org.w3c.dom.Text
class MainActivity : AppCompatActivity() {
private var dialogView: View? = null
private lateinit var mUserViewModel: VideoViewModel
private val mSplashScreenViewModel: SplashScreenViewModel by viewModels()
private val getPreviewImage = //get image from gallery
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri != null) {
dialogView?.findViewById<TextView>(R.id.imageUriHolder)?.text = uri.toString() //URI holder doesn't work
dialogView?.findViewById<ImageView>(R.id.imageChange)?.setImageURI(uri) // set imageURI as Thumbnail
} else {
Log.e("MainActivity", "URI not present")
}
}
private val getPreviewVideo =//get video from gallery
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri != null) {
dialogView?.findViewById<TextView>(R.id.videoUriHolder)?.text = uri.toString() //videoURI holder doesn't work
dialogView?.findViewById<VideoView>(R.id.videoChange)?.setVideoURI(uri) // set videoURi as video
} else {
Log.e("MainActivity", "URI not present")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
installSplashScreen().apply {
setKeepOnScreenCondition {
mSplashScreenViewModel.isLoading.value
}
}
setContentView(R.layout.activity_main)
supportActionBar?.hide()
bottomNavigationView.background = null
bottomNavigationView.menu.findItem(R.id.placeholder).isEnabled = false
replaceFragment(HomeFragment()) //base fragment
popupAddButton.setOnClickListener {
showDialog()
}
bottomNavigationView.setOnItemSelectedListener { // navigation bar
when (it.itemId) {
R.id.home -> replaceFragment(HomeFragment())
R.id.player -> replaceFragment(PlayerFragment())
R.id.profile -> replaceFragment(ProfileFragment())
R.id.settings -> replaceFragment(SettingsFragment())
}
true
}
}
private fun replaceFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, fragment)
transaction.commit()
}
#SuppressLint("InflateParams", "CutPasteId")
private fun showDialog() { //this is for popupWindow
dialogView = layoutInflater.inflate(R.layout.popup, null)
mUserViewModel = ViewModelProvider(this)[VideoViewModel::class.java]
val dialog = Dialog(this)
val titleEditText = dialogView?.findViewById<EditText>(R.id.titleEdit) //popUp edit field title
val descEditText = dialogView?.findViewById<EditText>(R.id.description) //popUp edit field description
dialogView?.addImage?.setOnClickListener { //opens gallery where you can pick image
getPreviewImage.launch("image/*")
}
dialogView?.addVideo?.setOnClickListener { //opens gallery where you can pick video
getPreviewVideo.launch("video/*")
}
dialogView?.addButton?.setOnClickListener {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
if (titleEditText?.text?.isEmpty() == true || descEditText?.text?.isEmpty() == true) {
Toast.makeText(applicationContext, "add required data", Toast.LENGTH_LONG).show()
} else {
//all variables bellow add specific data to database
val addTitleToDatabase = titleEditText?.text.toString()
val addDescToDatabase = descEditText?.text.toString()
val addImageToDatabase = dialogView?.findViewById<TextView>(R.id.imageUriHolder)?.text.toString()
val addVideoToDatabase = dialogView?.findViewById<TextView>(R.id.videoUriHolder)?.text.toString()
val video = ListData(
0,
addTitleToDatabase,
addDescToDatabase,
addImageToDatabase,
addVideoToDatabase
)
mUserViewModel.addUser(video)
Toast.makeText(applicationContext, "Successfully added!", Toast.LENGTH_SHORT).show()
}
}
dialog.setContentView(dialogView!!)
dialog.show()
}
}
RecyclerAdapter.kt
package eu.tuto.youtubeproject
import android.app.VoiceInteractor
import android.content.Intent
import android.content.Intent.ACTION_OPEN_DOCUMENT
import android.net.Uri
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.app.ActivityCompat.startActivityForResult
import androidx.core.net.toUri
import androidx.recyclerview.widget.RecyclerView
import eu.tuto.youtubeproject.databinding.CardLayoutBinding
import eu.tuto.youtubeproject.data.ListData
import androidx.recyclerview.widget.DiffUtil
import kotlinx.android.synthetic.main.card_layout.view.*
const val PICK_FILE = 1
class RecyclerAdapter: RecyclerView.Adapter<RecyclerAdapter.MyViewHolder>() {
private var oldList = emptyList<ListData>()
inner class MyViewHolder(binding: CardLayoutBinding): RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(CardLayoutBinding.inflate(LayoutInflater.from(parent.context), parent,false))
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = oldList[position]
holder.itemView.tv_id.text = currentItem.id.toString()
holder.itemView.tv_title.text = currentItem.title
holder.itemView.tv_description.text = currentItem.description
holder.itemView.tv_thumbnail.setImageURI(currentItem.image.toUri())
holder.itemView.tv_Video.setVideoURI(currentItem.Video.toUri())
}
override fun getItemCount(): Int {
return oldList.size
}
fun setData(newList: List<ListData>){
val diffUtil = eu.tuto.youtubeproject.data.DiffUtil(oldList, newList)
val diffResults = DiffUtil.calculateDiff(diffUtil)
oldList = newList
diffResults.dispatchUpdatesTo(this)
}
}
I want to write a hashmap into my firebase using the click listener which I have implemented in the fragment which acts only if one of the items is selected. but I get an error that I haven't got anytime before.
The logcat shows:
java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
at java.util.ArrayList.get(ArrayList.java:437)
at com.reazon.foodrunner.adapter.MenuRecyclerAdapter$MenuViewHolder$bind$1$1.onDataChange(MenuRecyclerAdapter.kt:104)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75)
at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
this is my adapter :
package com.reazon.foodrunner.adapter
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.reazon.foodrunner.R
import com.reazon.foodrunner.fragment.CartFragment
import com.reazon.foodrunner.model.MenuItem
class MenuRecyclerAdapter(
val context: Context,
private val btnProceedToCart: Button,
private val proceedToCartPassed: RelativeLayout,
private val menuList: List<MenuItem>,
private val listener: ContentListener
) : RecyclerView.Adapter<MenuRecyclerAdapter.MenuViewHolder>() {
private var goToCart: Int = 0
private var itemSelected: Int = 0
private var itemNumber: Int = 0
private var itemSelectedId = arrayListOf<String>()
private var itemSelectedName = arrayListOf<String>()
lateinit var proceedToCartLayout: RelativeLayout
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MenuViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.recycler_menu_single_row, parent, false)
return MenuViewHolder(view)
}
override fun getItemCount(): Int {
return menuList.size
}
override fun onBindViewHolder(holder: MenuViewHolder, position: Int) {
val menuItemItem = menuList[position]
holder.menuItemName.text = menuItemItem.item.toString()
proceedToCartLayout = proceedToCartPassed
btnProceedToCart.setOnClickListener {
Toast.makeText(context, "Proceeding To Cart", Toast.LENGTH_SHORT).show()
}
holder.btnMenuItem.setOnClickListener {
if (holder.btnMenuItem.text.toString() == "Remove") {
itemSelected--
holder.btnMenuItem.text = "ADD"
itemSelectedId.remove(holder.btnMenuItem.toString())
itemSelectedName.remove(holder.menuItemName.toString())
holder.btnMenuItem.setBackgroundResource(R.drawable.btn_menu_add_background)
} else {
itemSelected++
holder.btnMenuItem.text = "Remove"
itemSelectedId.add(holder.btnMenuItem.toString())
itemSelectedName.add(holder.menuItemName.toString())
holder.btnMenuItem.setBackgroundResource(R.drawable.btn_menu_remove_background)
}
if (itemSelected > 0) {
proceedToCartLayout.visibility = View.VISIBLE
} else {
proceedToCartLayout.visibility = View.INVISIBLE
}
print("$goToCart")
holder.btnMenuItem.tag = menuItemItem.id
itemNumber = position + 1
Log.d("Restaurant", "" + holder.menuItemName.text)
}
holder.btnMenuItem.tag = menuItemItem.id.toString() + ""
holder.bind(itemSelectedId, itemSelectedName, btnProceedToCart, listener)
}
class MenuViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(menuSelectedId: List<String>, menuList: List<String>, btnProceedToCart: Button, listener: ContentListener) {
btnProceedToCart.setOnClickListener {
val mReference = FirebaseDatabase.getInstance().reference.child("Orders")
.child(FirebaseAuth.getInstance().currentUser!!.uid)
mReference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val orderHashMap = HashMap<String, Any>()
for (item in 1..menuList.size) {
orderHashMap["id"] = menuSelectedId[item]
orderHashMap["item"] = menuList[item]
orderHashMap["cost"] = 200
orderHashMap["placed"] = true
}
mReference.updateChildren(orderHashMap)
}
override fun onCancelled(error: DatabaseError) {
Log.d("MenuRecyclerAdapter", error.message)
}
})
listener.openCart()
}
}
val menuItemName: TextView = view.findViewById(R.id.menuItemName)
val btnMenuItem: Button = view.findViewById(R.id.btnMenuAdd)
}
interface ContentListener {
fun openCart()
}
}
this is my menu fragment:
package com.reazon.foodrunner.fragment
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.RelativeLayout
import androidx.core.os.bundleOf
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.database.*
import com.reazon.foodrunner.R
import com.reazon.foodrunner.adapter.MenuRecyclerAdapter
import com.reazon.foodrunner.model.MenuItem
import com.reazon.foodrunner.model.Restaurant
import kotlinx.android.synthetic.main.fragment_menu.*
import kotlinx.android.synthetic.main.recycler_home_single_row.*
import kotlinx.android.synthetic.main.recycler_menu_single_row.*
class MenuFragment : Fragment(),MenuRecyclerAdapter.ContentListener{
private var menuRecyclerAdapter: MenuRecyclerAdapter? = null
private lateinit var menuReference: DatabaseReference
private var recyclerMenu: RecyclerView? = null
internal var menuItemList: MutableList<MenuItem> = ArrayList()
private var layoutManager: RecyclerView.LayoutManager? = null
private lateinit var proceedToCartLayout:RelativeLayout
private lateinit var btnProceedToCart: Button
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_menu, container, false)
menuReference = FirebaseDatabase.getInstance().reference.child("Menu")
recyclerMenu = view.findViewById(R.id.recyclerMenu)
btnProceedToCart = view.findViewById(R.id.btnGoToCart)
proceedToCartLayout = view.findViewById(R.id.rlProceedToCart)
// val restaurant = (Restaurant::class.java)
layoutManager = LinearLayoutManager(activity)
recyclerMenu!!.layoutManager = layoutManager
retrieveMenu()
return view
}
private fun retrieveMenu() {
menuItemList.clear()
menuReference.addValueEventListener(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
Log.d("ERROR", "" + error.message)
}
override fun onDataChange(snapshot: DataSnapshot) {
for (p0 in snapshot.children) {
val menu = p0.getValue(MenuItem::class.java)
menuRecyclerAdapter = MenuRecyclerAdapter(context!!, btnProceedToCart, proceedToCartLayout,menuItemList,this#MenuFragment)//,this#MenuFragment)
recyclerMenu!!.adapter = menuRecyclerAdapter
if (menu != null) {
menuItemList.add(menu)
}
}
}
})
}
fun onBackPressed() {
when (this.fragmentManager?.findFragmentById(R.id.frame)) {
!is HomeFragment -> openHome()
}
}
private fun openHome() {
val transaction = fragmentManager?.beginTransaction()
transaction?.replace(R.id.frame, HomeFragment())
transaction?.commit()
}
override fun openCart() {
val transaction = fragmentManager?.beginTransaction()
transaction?.replace(R.id.frame, CartFragment())
transaction?.commit()
}
}
although I haven't made the cart fragment and recycler properly, this is my cart fragment:
package com.reazon.foodrunner.fragment
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.reazon.foodrunner.R
import com.reazon.foodrunner.activity.FinishActivity
import com.reazon.foodrunner.adapter.CartRecyclerAdapter
import com.reazon.foodrunner.model.Order
import kotlinx.android.synthetic.main.fragment_cart.*
class CartFragment : Fragment() {
lateinit var btnCheckout:Button
private var recyclerCart:RecyclerView? = null
private var recyclerAdapter:CartRecyclerAdapter? = null
private var layoutManager:RecyclerView.LayoutManager? = null
private var orderList:MutableList<Order> = ArrayList()
private var cartDatabaseReference:DatabaseReference? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_cart, container, false)
btnCheckout = view.findViewById(R.id.btnCheckout)
val firebaseUid = FirebaseAuth.getInstance().currentUser!!.uid
cartDatabaseReference = FirebaseDatabase.getInstance().reference.child("Orders").child(firebaseUid)
layoutManager =LinearLayoutManager(activity)
recyclerCart = view.findViewById(R.id.recyclerCart)
recyclerCart!!.layoutManager = layoutManager
btnCheckout.setOnClickListener {
val intent = Intent(activity, FinishActivity::class.java )
startActivity(intent)
}
return view
}
}
Cart adapter:
package com.reazon.foodrunner.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.reazon.foodrunner.R
import com.reazon.foodrunner.model.Order
import kotlinx.android.synthetic.*
import kotlinx.android.synthetic.main.recycler_cart_single_row.view.*
import java.util.function.ToDoubleBiFunction
class CartRecyclerAdapter(
val context: Context,
private val orderList:List<Order>
):RecyclerView.Adapter<CartRecyclerAdapter.CartViewHolder>() {
class CartViewHolder(view: View):RecyclerView.ViewHolder(view){
val txtItemName:TextView = view.findViewById(R.id.txtItemNameCart)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.recycler_cart_single_row,parent,false)
return CartViewHolder(view)
}
override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
val order = orderList[position]
holder.txtItemName.text = order.item
}
override fun getItemCount(): Int {
return orderList.size
}
}
I am unable to understand what to do here to simply upload the hash map of orders and retrieve them.
it was a simple error as I was using the index (indices) in the wrong manner as it should have been
for (item in menuList.indices) {
orderHashMap["id"] = menuSelectedId[item]
orderHashMap["item"] = menuList[item]
orderHashMap["cost"] = 200
orderHashMap["placed"] = true
}
and the list got the correct index of each element thereafter, and hashmap was written to firebase.
Hello guy i am new to Kotlin android and working on a demo in this demo i am trying to get an image from the gallery and set it in my recyclerview but i am getting the solution requesting you to please find me a solution Thanks in Advance!!
This is my CustomAdapter.kt:-
package com.example.itemgetset
import android.app.Activity
import android.app.AlertDialog
import android.content.ContentValues.TAG
import android.content.Intent
import android.os.Build
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
#Suppress("UNREACHABLE_CODE")
class CustomAdapter(
private var activity: Activity,
private val userList: ArrayList<ProductInfoGetSet>,
private var isforlist: Boolean,
) :
RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemview=
LayoutInflater.from(parent.context).inflate(R.layout.list_layout, parent, false)
return ViewHolder(itemview)
}
#RequiresApi(Build.VERSION_CODES.N)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val productInfoGetSet: ProductInfoGetSet = userList[position]
holder.image = productInfoGetSet.image
holder.txtId.text = productInfoGetSet.id
holder.txtName.text = productInfoGetSet.name
holder.txtQuantity.text = productInfoGetSet.quantity
holder.txtPrice.text = productInfoGetSet.price
val id = userList[position].id
Log.e(TAG, "List item ID: $id")
holder.buttonViewOption.setOnClickListener {
val popup = PopupMenu(activity, holder.buttonViewOption)
popup.inflate(R.menu.pop_menu)
popup.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.edit -> {
val intent = Intent(activity, AddDetails::class.java)
intent.putExtra("isFor", "Update")
intent.putExtra("id", productInfoGetSet.id)
intent.putExtra("image",productInfoGetSet.image)
intent.putExtra("name", productInfoGetSet.name)
intent.putExtra("quantity", productInfoGetSet.quantity)
intent.putExtra("price", productInfoGetSet.price)
activity.startActivity(intent)
}
R.id.delete -> {
val builder = AlertDialog.Builder(activity)
builder.setTitle("Delete")
builder.setMessage("Do you want to delete the item?")
builder.setPositiveButton("Yes") { _, _ ->
userList.removeAt(position)
notifyItemRemoved(position)
val snack = Snackbar
.make(
holder.linearly,
"Item was removed from the list.",
Snackbar.LENGTH_SHORT
)
snack.show()
}
builder.setNegativeButton("No") { _, _ ->
}
val dialog: AlertDialog = builder.create()
dialog.show()
}
}
false
}
popup.show()
}
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemCount(): Int {
return userList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val txtName = itemView.findViewById(R.id.txt_name) as TextView
val txtId = itemView.findViewById(R.id.txt_id) as TextView
var image = itemView.findViewById(R.id.imageView2) as ImageView
val txtQuantity = itemView.findViewById(R.id.txt_quantity) as TextView
val txtPrice = itemView.findViewById(R.id.txt_price) as TextView
val linearly: LinearLayout = itemView.findViewById(R.id.linearlayout)
val buttonViewOption = itemView.findViewById<View>(R.id.txt_Options) as TextView
}
}
in this adapter i gent and error on holder.image = productInfoGetSet.image this line and not get solved.
This is my AddDeatils.kt:-
package com.example.itemgetset
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle
import android.os.Message
import android.provider.MediaStore
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.add_item.*
import kotlinx.android.synthetic.main.list_layout.*
class AddDetails : AppCompatActivity() {
private lateinit var btnSubmit: Button
private lateinit var edtName: EditText
private lateinit var edtQuantity: EditText
private lateinit var edtPrice: EditText
private lateinit var imageview: ImageView
companion object {
private const val IMAGE_PICK_CODE = 1000
private const val PERMISSION_CODE = 1001
}
#SuppressLint("SetTextI18n", "ResourceType")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.add_item)
supportActionBar?.hide()
findViewById()
onclick()
if (intent.getStringExtra("isFor").equals("Update")) {
intent.getStringExtra("image")?.toInt()?.let { imageview.setImageResource(it) }
edtName.setText(intent.getStringExtra("name"))
edtQuantity.setText(intent.getStringExtra("quantity"))
edtPrice.setText(intent.getStringExtra("price"))
}
}
private fun findViewById() {
btnSubmit = findViewById(R.id.btn_submit)
edtName = findViewById(R.id.edt_name)
edtQuantity = findViewById(R.id.edt_quantity)
edtPrice = findViewById(R.id.edt_price)
imageview = findViewById(R.id.image_view)
}
#SuppressLint("ResourceType")
private fun onclick() {
btnSubmit.setOnClickListener {
when {
edtName.text.trim().isEmpty() -> {
edtName.error = "Please Enter Product Name"
Toast.makeText(
applicationContext,
"Please Enter Product Name",
Toast.LENGTH_SHORT
)
.show()
}
edtQuantity.text.trim().isEmpty() -> {
edtQuantity.error = "Please Enter Product Quantity"
Toast.makeText(
applicationContext,
"Please Enter Product Quantity",
Toast.LENGTH_SHORT
).show()
}
edtPrice.text.trim().isEmpty() -> {
edtPrice.error = "Please Enter Product Price"
Toast.makeText(
applicationContext,
"Please Enter Product Price",
Toast.LENGTH_SHORT
)
.show()
}
else -> {
Toast.makeText(
applicationContext,
"Product Added Successfully ",
Toast.LENGTH_SHORT
).show()
val temp = Temp()
temp.image = imageview.toString()
temp.name = edtName.text.toString()
temp.quantity = edtQuantity.text.toString()
temp.price = edtPrice.text.toString()
if (intent.getStringExtra("isFor").equals("Update")) {
temp.id = intent.getStringExtra("id").toString()
}
val message: Message = Message.obtain()
message.what = 111
message.obj = temp
MainActivity.handler.sendMessage(message)
finish()
}
}
}
imageview.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) ==
PackageManager.PERMISSION_DENIED
) {
val permissions = arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE)
requestPermissions(permissions, PERMISSION_CODE)
} else {
pickImageFromGallery()
}
} else {
pickImageFromGallery()
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
when (requestCode) {
PERMISSION_CODE -> {
if (grantResults.isNotEmpty() && grantResults[0] ==
PackageManager.PERMISSION_GRANTED
) {
pickImageFromGallery()
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
private fun pickImageFromGallery() {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, IMAGE_PICK_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && requestCode == IMAGE_PICK_CODE) {
imageview.setImageURI(data?.data)
super.onActivityResult(requestCode, resultCode, data)
}
}
}
And this is my MainActivity.kt:-
package com.example.itemgetset
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.GridView
import android.widget.LinearLayout
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
#Suppress("DEPRECATION")
class MainActivity : AppCompatActivity() {
lateinit var activity: Activity
val userList = ArrayList<ProductInfoGetSet>()
private lateinit var btnProductAdd: Button
lateinit var llEmptyView: LinearLayout
lateinit var llMain: LinearLayout
private var listView: ListView? = null
private var gridView: GridView? = null
lateinit var recyclerView: RecyclerView
private lateinit var llFab: LinearLayout
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var gridLayoutManager: GridLayoutManager
private lateinit var adapter: CustomAdapter
private var isforlist = true
companion object {
var handler: Handler = Handler()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
activity = this
initView()
onClicks()
setUpData()
handler = #SuppressLint("HandlerLeak")
object : Handler() {
override fun handleMessage(msg: Message) {
if (msg.what == 111) {
val temp: Temp = msg.obj as Temp
if (temp.id == "") {
userList.add(
ProductInfoGetSet(
(userList.size + 1).toString(),
temp.image,
temp.name,
temp.quantity,
temp.price,
)
)
adapter = CustomAdapter(activity, userList, isforlist)
recyclerView.adapter = adapter
} else {
for (i in userList.indices) {
if (userList[i].id == temp.id) {
userList[i].id = temp.id
userList[i].image = temp.image
userList[i].name = temp.name
userList[i].quantity = temp.quantity
userList[i].price = temp.price
}
}
adapter.notifyDataSetChanged()
}
}
if (userList.size > 0) {
llEmptyView.visibility = View.GONE
llMain.visibility = View.VISIBLE
} else {
llEmptyView.visibility = View.VISIBLE
llMain.visibility = View.GONE
}
}
}
}
private fun changeLayoutManager() {
if (recyclerView.layoutManager == linearLayoutManager) {
recyclerView.layoutManager = gridLayoutManager
} else {
recyclerView.layoutManager = linearLayoutManager
}
}
private fun initView() {
btnProductAdd = findViewById(R.id.btn_product_add)
llFab = findViewById(R.id.ll_fab)
llEmptyView = findViewById(R.id.llEmptyView)
listView = findViewById(R.id.list_product)
gridView = findViewById(R.id.list_productGV)
llMain = findViewById(R.id.llMain)
recyclerView = findViewById(R.id.recycler_view)
recyclerView.layoutManager = LinearLayoutManager(this)
linearLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
gridLayoutManager = GridLayoutManager(this, 2)
}
private fun onClicks() {
btnProductAdd.setOnClickListener {
val intent = Intent(this#MainActivity, AddDetails::class.java)
intent.putExtra("isFor", "Add")
startActivity(intent)
}
llFab.setOnClickListener {
val intent = Intent(this#MainActivity, AddDetails::class.java)
intent.putExtra("isFor", "Add")
startActivity(intent)
}
}
private fun setUpData() {
if (userList.size > 0) {
llEmptyView.visibility = View.GONE
llMain.visibility = View.VISIBLE
} else {
llEmptyView.visibility = View.VISIBLE
llMain.visibility = View.GONE
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.menu_view) {
if (userList.size > 0) {
changeLayoutManager()
}
return true
}
return super.onOptionsItemSelected(item)
}
}
My ProductInfoGetSet.kt:-
package com.example.itemgetset
import android.widget.ImageView
class ProductInfoGetSet(
var id: String,
var image: ImageView,
var name: String,
var quantity: String,
var price: String
)
Temp.kt:-
package com.example.itemgetset
import android.widget.ImageView
class Temp {
var id: String = ""
var image: ImageView =
var name: String = ""
var quantity: String = ""
var price: String = ""
}
Thanks in advance!!
I understand you are new to Android. I will list down points below for you to understand clearly.
As a standard practice you must not use ImageView in any model as Model can only hold data.
Use databinding for views.
As suggested by Rupam Saini, you can use Glide or Picasso for image loading.
You can't pass imageView in bundle as it will create different object when you read it again. There is a chance of leaking context also.
Regarding your question
in this adapter i gent and error on holder.image = productInfoGetSet.image this line and not get solved.
You are trying to set an ImageView to another ImageView which is not correct. Temp file is incorrect, there is no value after = . So Temp file must also have error.
It'll be better if you show your ProductInfoGetSet class and the error logs.
You should not set the image directly
holder.image = productInfoGetSet.image
Instead you can get the image's URI and then set it like this
holder.image.setImageUri(imageUri)
If you are still getting issues then you can use the Glide library