Navigation Broken on Android App Using Firebase Auth - android

I am writing my first Android App and have implemented Firebase Auth. My app navigation was working correctly before I added in the Firebase pieces. Now I am not able to get from the Main Activity to my starting Frag (Frag1). I would like to have the app open to Frag1 once the Firebase Auth runs through its process, but I can't get that to work. Here are the main parts of my files:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.richeypro.android.fishpro">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application
android:allowBackup="true"
android:name=".CatchApplication"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".LoginActivity" />
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="#string/facebook_app_id"
tools:replace="android:value" />
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.kt
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import androidx.navigation.NavController
import androidx.navigation.Navigation
import com.bumptech.glide.Glide
import com.firebase.ui.auth.AuthUI
import com.google.android.material.navigation.NavigationView
import com.google.firebase.auth.FirebaseAuth
import com.richeypro.android.fishpro.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
lateinit var binding: ActivityMainBinding
val auth = FirebaseAuth.getInstance().currentUser
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
var toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
var fragment = Fragment()
var ft: FragmentTransaction = supportFragmentManager.beginTransaction()
ft.add(R.id.content_frame, fragment)
ft.commit()
var drawer: DrawerLayout = findViewById(R.id.drawer_layout)
var toggle: ActionBarDrawerToggle = ActionBarDrawerToggle(this, drawer, toolbar, R.string.nav_open_drawer, R.string.nav_close_drawer)
drawer.addDrawerListener(toggle)
toggle.syncState()
var navigationView: NavigationView = findViewById(R.id.nav_view)
navigationView.setNavigationItemSelectedListener(this)
if(auth!=null && intent!= null){
createUI()
}
else{
startActivity(Intent(this,LoginActivity::class.java))
this.finish()
}
}
override fun onResume() {
super.onResume()
if(auth!=null&& intent!= null){
createUI()
}
else{
startActivity(Intent(this,LoginActivity::class.java))
this.finish()
}
}
fun createUI(){
var txtName: TextView = binding.txtName
var txtEmail: TextView = binding.txtEmail
var txtPhone: TextView = binding.txtPhone
var txtProvider: TextView = binding.txtProvider
var btnLogOut: Button = binding.btnLogOut
var btnCatchList: Button = binding.btnCatchList
var profile_image: ImageView = binding.profileImage
val list = auth?.providerData
var providerData:String = ""
list?.let {
for(provider in list){
providerData = providerData+ " " +provider.providerId
}
}
auth?.let {
txtName.text = auth.displayName
txtEmail.text = auth.email
txtPhone.text = auth.phoneNumber
txtProvider.text = providerData
Glide
.with(this)
.load(auth.photoUrl)
.fitCenter()
.placeholder(R.drawable.login_background)
.into(profile_image)
}
btnLogOut.setOnClickListener{
AuthUI.getInstance().signOut(this)
.addOnSuccessListener {
val intent = Intent(this,LoginActivity::class.java)
startActivity(intent)
// this.finish()
Toast.makeText(this, "Successfully Log Out", Toast.LENGTH_SHORT).show()
}
}
btnCatchList.setOnClickListener{
Toast.makeText(this, "Clicked FAB", Toast.LENGTH_SHORT).show()
val navController: NavController = Navigation.findNavController(this, R.id.nav_host_fragment)
val action = CatchDetailFragmentDirections.actionCatchDetailFragmentToAddCatchFragment(
null.toString(), 1)
navController.navigateUp()
navController.navigate(action)
}
}
// fun generateFBKey(){
// try {
// val info = packageManager.getPackageInfo(
// "com.example.firebaseintro",
// PackageManager.GET_SIGNATURES
// )
// for (signature in info.signatures) {
// val md: MessageDigest = MessageDigest.getInstance("SHA")
// md.update(signature.toByteArray())
// Log.d("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT))
// }
// } catch (e: PackageManager.NameNotFoundException) {
// } catch (e: NoSuchAlgorithmException) {
// }
// }
override fun onBackPressed() {
super.onBackPressed()
finishAffinity()
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
var id: Int = item.itemId
var fragment: Fragment
var intent: Intent = Intent()
when (id) {
R.id.nav_catch_list -> fragment = CatchListFragment()
R.id.nav_add_angler -> fragment = AddAnglerFragment()
//R.id.nav_help -> //Do something here
//R.id.nav_feedback -> fragment = SendFeedbackFragment()
else -> fragment = SelectScreenFragment()
}
if (fragment != null) {
var ft: FragmentTransaction = supportFragmentManager.beginTransaction()
ft.replace(R.id.content_frame, fragment)
ft.commit()
} else startActivity(intent)
var drawer: DrawerLayout = findViewById(R.id.drawer_layout)
drawer.closeDrawer(GravityCompat.START)
return true
}
}
LoginActivity.kt
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.firebase.ui.auth.AuthUI
import com.firebase.ui.auth.ErrorCodes
import com.firebase.ui.auth.IdpResponse
import com.google.firebase.auth.FirebaseAuth
class LoginActivity : AppCompatActivity() {
companion object {
private const val RC_SIGN_IN = 123
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
createSignInIntent()
}
private fun createSignInIntent() {
val providers = arrayListOf<AuthUI.IdpConfig>(
AuthUI.IdpConfig.EmailBuilder().build(),
AuthUI.IdpConfig.PhoneBuilder().build(),
AuthUI.IdpConfig.GoogleBuilder().build()
)
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.setIsSmartLockEnabled(false)
.setTheme(R.style.MySuperAppTheme)
.setLogo(R.drawable.fishem_up_logo_final_main_logo_white)
.build(),
RC_SIGN_IN
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(requestCode == RC_SIGN_IN){
var response = IdpResponse.fromResultIntent(data)
if (resultCode == Activity.RESULT_OK){
val user = FirebaseAuth.getInstance().currentUser
val intent = Intent(this,MainActivity::class.java)
// val image = user?.photoUrl
//
// intent.putExtra("USERNAME", user?.displayName)
// intent.putExtra("USEREMAIL",user?.email)
// intent.putExtra("USERPHONE",user?.phoneNumber)
// intent.putExtra("USERPROVIDER",user?.providerId)
// intent.putExtra("USERIMAGE",user?.photoUrl)
startActivity(intent)
}
else{
if(response == null){
finish()
}
if (response?.getError()?.getErrorCode() == ErrorCodes.NO_NETWORK) {
//Show No Internet Notification
return
}
if(response?.getError()?.getErrorCode() == ErrorCodes.UNKNOWN_ERROR) {
Toast.makeText(this, response?.error?.errorCode.toString(), Toast.LENGTH_LONG)
.show()
Log.d("ERRORCODE", response?.error?.errorCode.toString())
return
}
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
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:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/mobile_navigation"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ImageView
android:id="#+id/profile_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/fui_ic_yahoo_24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="16dp"
android:layout_marginTop="64dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="16dp"/>
<TextView
android:id="#+id/txtName"
android:text="Peter Allen"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/profile_image"
style="#style/TextStyle" />
<TextView
android:id="#+id/txtEmail"
style="#style/TextStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Email"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtName" />
<TextView
android:id="#+id/txtPhone"
style="#style/TextStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Phone Number"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtEmail" />
<TextView
android:id="#+id/txtProvider"
style="#style/TextStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Provider"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtPhone" />
<Button
android:id="#+id/btnCatchList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="#color/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.522"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/txtPhone"/>
<Button
android:id="#+id/btnLogOut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:background="#drawable/fui_idp_button_background_email"
android:text="Log Out"
android:textColor="#color/browser_actions_bg_grey"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.522"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnCatchList" />
<include
layout="#layout/toolbar_main"
android:id="#+id/toolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/nav_header"
app:menu="#menu/menu_nav" />
</androidx.drawerlayout.widget.DrawerLayout>

Regardless of how you handle your fragment/activity state. You should only check the currentUser when necessary, you don't want it to initialize too early.
val auth = FirebaseAuth.getInstance()
if (auth.currentUser == null) {
// LoginActivity
} else {
}
You might want to check out AuthStateListener so you can listen to authentication changes asynchronously.

Related

Android with Kotlin - Sending data back to MainActivity

I have two activities. I want to receive a value from MainActivity, change the value from SecondActivity, and send it back to editText of MainActivity.
However, the editText of MainActivity does not change even if I move back from SecondActivity.
Could you tell me which part I misunderstood?
MainActivity.kt code
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts
import com.example.homework07.databinding.ActivityMainBinding
import com.google.android.material.snackbar.Snackbar
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val result = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
it.resultCode
val ret_num = it.data?.getIntExtra("result", 0) ?:0
Snackbar.make(binding.root, "result code: ${it.resultCode}, result number: ${ret_num}", Snackbar.LENGTH_SHORT).show()
}
binding.button.setOnClickListener {
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("num", Integer.parseInt(binding.editText.text.toString()))
result.launch(intent)
}
}
}
activity_main.xml code
<?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="match_parent"
tools:context=".MainActivity">
<EditText
android:id="#+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:ems="10"
android:hint="Enter number only"
android:inputType="number"
android:minHeight="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="START SECOND ACTIVITY"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/editText" />
</androidx.constraintlayout.widget.ConstraintLayout>
SecondActivity.kt code
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
import com.example.homework07.databinding.ActivitySecondBinding
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivitySecondBinding.inflate(layoutInflater)
setContentView(binding.root)
val viewModel = ViewModelProvider(this)[MyViewModel::class.java]
viewModel.myLiveData.observe(this) {
binding.textView.text = "$it"
}
var num2 = intent?.getIntExtra("num", 0) ?:0
binding.textView.text = "$num2"
binding.buttonInc.setOnClickListener {
num2 = viewModel.myLiveData.value ?:0
viewModel.myLiveData.value = Integer.parseInt(binding.textView.text.toString()) + 1
}
binding.buttonDec.setOnClickListener {
num2 = viewModel.myLiveData.value ?:0
viewModel.myLiveData.value = Integer.parseInt(binding.textView.text.toString()) - 1
}
setResult(0, Intent().putExtra("result", num2))
}
}
activity_second.xml code
<?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="match_parent"
tools:context=".SecondActivity">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="32dp"
android:text="TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/buttonInc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="INCREASE"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/textView"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/buttonDec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="DECREASE"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/textView"
app:layout_constraintTop_toBottomOf="#+id/buttonInc" />
</androidx.constraintlayout.widget.ConstraintLayout>
MyViewModel.kt code
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MyViewModel : ViewModel() {
val myLiveData : MutableLiveData<Int> = MutableLiveData()
}
Thank you.
You made a mistake:
setResult(0, Intent().putExtra("result", num2))
replace 0 (it cancel result) to Activity.RESULT_OK.
This line has a mistake (resultCode) parameter:
setResult(0, Intent().putExtra("result", num2))
It's better if you make a constant for resultCode or do something like this in your SecondActivity.kt.
setResult(200, Intent().putExtra("result", num2))
And in MainActivity.kt add this is "registerActivityForResult":
if(it.resultCode == 200){
//Rest of the code here
}
Or you can also follow Below answer
You should set the result before finishing the SecondActivity with:
intent.putExtra("result", num2)
setResult(Activity.RESULT_OK, intent)
finish()
The, after checking the result, retrieve the value in the FirstActivity:
val result = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val ret_num = result.data?.getIntExtra("result", 0) ?:0
Snackbar.make(binding.root, "result code: ${it.resultCode}, result number: ${ret_num}", Snackbar.LENGTH_SHORT).show()
}
}

I want change profile using image capture on navigation drawer ? its possible?

Navigation drawer
I wrote this code but problem is crash application.
This id my nav_header file xml code,i am using circleimageview and imagebutton.
<?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:orientation="vertical"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:background="#color/white">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/Profile"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:src="#drawable/ic_baseline_person_24"
app:civ_border_color="#color/black"
app:civ_border_width="2dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="#+id/change_Profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/background_center"
app:layout_constraintBottom_toBottomOf="#+id/Profile"
app:layout_constraintEnd_toEndOf="#+id/Profile"
app:srcCompat="#drawable/ic_baseline_add_circle_24" />
<TextView
android:id="#+id/User_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="72dp"
android:paddingTop="8dp"
android:text="Robin Hud"
android:textColor="#color/black"
android:textSize="20dp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="110dp"
android:text="sufiyan123#gmail.com"
android:textSize="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="135dp"
android:background="#color/underline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
----------
This is kotlin file code for navigation drawer
package com.example.pgf.view.home
import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.view.MenuItem
import android.widget.ImageButton
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import com.example.pgf.R
import com.example.pgf.model.PGListModel
import com.example.pgf.view.authentication.Login
import com.example.pgf.view.home.fragments.*
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.navigation.NavigationView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.ktx.auth
import com.google.firebase.ktx.Firebase
import de.hdodenhof.circleimageview.CircleImageView
class MainActivity : AppCompatActivity() {
private lateinit var toggle: ActionBarDrawerToggle
private lateinit var drawerLayout: DrawerLayout
var email:String? = null
var profile: CircleImageView? = null
var reqcode = 345
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Profile change
profile = findViewById(R.id.Profile)
var btnChange = findViewById<ImageButton>(R.id.change_Profile)
btnChange.setOnClickListener {
var captureImage = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(captureImage,reqcode)
}
//get user Email
val user = FirebaseAuth.getInstance().currentUser
email = user?.email
Toast.makeText(applicationContext,email,Toast.LENGTH_SHORT).show()
drawerLayout = findViewById(R.id.drawer)
val navView: NavigationView = findViewById(R.id.navView)
toggle = ActionBarDrawerToggle(this,drawerLayout,R.string.open,R.string.close)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
replaceFragment(HomeFragment(),"Home")
navView.setNavigationItemSelectedListener {
it.isChecked = true
when(it.itemId){
R.id.nav_home -> replaceFragment(HomeFragment(),it.title.toString())
R.id.nav_star -> replaceFragment(StarFragment(),it.title.toString())
R.id.nav_help -> replaceFragment(HelpFragment(),it.title.toString())
R.id.nav_setting -> replaceFragment(SettingFragment(),it.title.toString())
R.id.nav_profile -> replaceFragment(ProfileFragment(),it.title.toString())
R.id.nav_logout -> logout()
R.id.nav_share -> Toast.makeText(applicationContext,"Clicked Share",Toast.LENGTH_SHORT).show()
}
true
}
}
private fun replaceFragment(fragment: Fragment, title: String){
val fragmentStateManagerControl = supportFragmentManager
val fragmentTransaction = fragmentStateManagerControl.beginTransaction()
fragmentTransaction.replace(R.id.framelayout,fragment)
fragmentTransaction.commit()
drawerLayout.closeDrawers()
setTitle(title)
}
fun logout(){
Firebase.auth.signOut()
startActivity(
Intent(this,Login::class.java)
)
this.finish()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (toggle.onOptionsItemSelected(item)){
return true
}
return super.onOptionsItemSelected(item)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode== Activity.RESULT_OK && requestCode==reqcode && data!=null)
{
profile!!.setImageBitmap(data.extras?.get("data") as Bitmap)
}
else
{
Toast.makeText(applicationContext,"Something Went Wrong!!",Toast.LENGTH_LONG).show()
}
}
}
This is my all code,so I want to change profile picture using camera capture on navigation drawer.
so what I do for this?
Logcat
enter image description here

My Recyclerview sometimes display data and sometimes it doesnt

My Recyclerview sometimes needs a refresh to start displaying data, some times it need much time to display the data and sometimes it works like a charm. I even used the same adapter for 2 recycler views one of them displayed data immediately but the other didn't show at all like the the image below:
This problem started to show up when I added another recycler view but in a different fragment that used same adapter. I thought using same adapter was the problem so I created a new one but the problem is still there. Note: I'm using same layout for displaying the recycler view items too. Any Ideas would be really helpful.
Thanks
UPDATE: Codes
Adapter :
import android.graphics.Paint
import android.view.LayoutInflater
import android.view.TextureView
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.ecommapp.R
import com.example.ecommapp.main_activity.data.Product
import kotlinx.android.synthetic.main.product_item_layout.view.*
class ProductItemAdapter(val listener: ProductItemAdapter.onItemClickListener) : ListAdapter<Product, ProductItemAdapter.ProductViewHolder>(Comparator()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
val inflater = LayoutInflater.from(parent.context).inflate(R.layout.product_item_layout, parent, false)
return ProductViewHolder(inflater)
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
val currentItem = getItem(position)
if (currentItem != null) {
holder.bind(currentItem)
}
}
inner class ProductViewHolder(view : View): RecyclerView.ViewHolder(view){
init {
view.setOnClickListener{
val position = adapterPosition
val product = getItem(position)
if(position != RecyclerView.NO_POSITION){
listener.onItemClick(product)
}
}
}
private val container = view.container_main
private val imageView = view.img_product_item_not_card
private val productName = view.tv_product_item_label
private val productNewPrice = view.tv_product_item_new_price
private val productOldPrice = view.tv_product_item_old_price
fun bind(product: Product) {
productName.text = product.title
productNewPrice.text = product.price
/*var temp = (product.price as Double ) * 1.5
var oldPrice = temp as String
productOldPrice.text = oldPrice
productOldPrice.paintFlags = productOldPrice.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG*/
//Context of the view
Glide.with(imageView.context) // Context
.load(product.image) // Data
.into(imageView) // View
}
}
interface onItemClickListener{
fun onItemClick(product : Product)
}
class Comparator : DiffUtil.ItemCallback<Product>() {
override fun areItemsTheSame(oldItem: Product, newItem: Product) =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: Product, newItem: Product) =
oldItem == newItem
}
}
View Model:
import android.content.ContentValues.TAG
import android.util.Log
import androidx.lifecycle.*
import com.example.ecommapp.main_activity.data.Product
import com.example.ecommapp.main_activity.retrofit.ProductsApi
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
#HiltViewModel
class HomeViewModel #Inject constructor(
private val savedStateHandle: SavedStateHandle,
val api : ProductsApi
) : ViewModel() {
var new_collection_list : MutableLiveData<List<Product>>
var best_sellling_list : MutableLiveData<List<Product>>
init {
new_collection_list = MutableLiveData()
best_sellling_list = MutableLiveData()
get_best_selling_data()
get_new_collection_data()
}
fun get_new_collection_data(){
var call = api.get_products_desc()
call.enqueue(object : Callback<List<Product>> {
override fun onResponse(call: Call<List<Product>>, response: Response<List<Product>>) {
if (response.body() != null){
new_collection_list.postValue(response.body())
Log.d(TAG, "onResponse: Success Response")
}
else{
new_collection_list.postValue(null)
Log.d(TAG, "onResponse: Null Response")
}
}
override fun onFailure(call: Call<List<Product>>, t: Throwable) {
Log.d(TAG, "onFailure: Failure Response")
}
})
}
fun get_best_selling_data() {
var call = api.get_products_asc()
call.enqueue(object : Callback<List<Product>> {
override fun onResponse(call: Call<List<Product>>, response: Response<List<Product>>) {
if (response.body() != null){
best_sellling_list.postValue(response.body())
Log.d(TAG, "onResponse: Success Response")
}
else{
best_sellling_list.postValue(null)
Log.d(TAG, "onResponse: Null Response")
}
}
override fun onFailure(call: Call<List<Product>>, t: Throwable) {
Log.d(TAG, "onFailure: Failure Response")
}
})
}
fun on_swipe_refresh(){
get_new_collection_data()
get_best_selling_data()
}
}
Fragment :
package com.example.ecommapp.main_activity.fragments.home_fragment
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.example.ecommapp.R
import com.example.ecommapp.main_activity.data.Product
import com.example.ecommapp.main_activity.shared_files.recycler_view_adapters.ProductItemAdapter
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.home_fragment_layout.*
#AndroidEntryPoint
class HomeFragment: Fragment(R.layout.home_fragment_layout), ProductItemAdapter.onItemClickListener {
lateinit var new_collection_list : LiveData<List<Product>>
lateinit var best_selling_list : LiveData<List<Product>>
val new_collections_adapter = ProductItemAdapter(this)
val best_selling_adapter = ProductItemAdapter(this)
val viewModel : HomeViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// New Collection Recycler View Setup
rv_new_collections.layoutManager = LinearLayoutManager(
activity?.applicationContext,
LinearLayoutManager.HORIZONTAL,
false
)
rv_new_collections.adapter = new_collections_adapter
// Best Selling Recycler View Setup
rv_best_selling.layoutManager = LinearLayoutManager(
activity?.applicationContext,
LinearLayoutManager.HORIZONTAL,
false
)
rv_best_selling.adapter = best_selling_adapter
//
set_data()
Handler().postDelayed({
if ( isConnected(activity?.applicationContext) ){
layout_new_collection_shimmer.visibility = View.INVISIBLE
rv_new_collections.visibility = View.VISIBLE
layout_best_selling_shimmer.visibility = View.INVISIBLE
rv_best_selling.visibility = View.VISIBLE
set_data()
}
else{
Toast.makeText(activity?.applicationContext, "No Internet Connection, Swipe to reload.", Toast.LENGTH_LONG )
.show()
}
}, 2000)
container_swipe.setOnRefreshListener(object : SwipeRefreshLayout.OnRefreshListener {
override fun onRefresh() {
if ( isConnected(activity?.applicationContext) ){
if( layout_new_collection_shimmer.visibility == View.INVISIBLE){
layout_new_collection_shimmer.visibility = View.INVISIBLE
rv_new_collections.visibility = View.VISIBLE
layout_best_selling_shimmer.visibility = View.INVISIBLE
rv_best_selling.visibility = View.VISIBLE
}
viewModel.on_swipe_refresh()
set_data()
}
else{
Toast.makeText(activity?.applicationContext, "No Internet Connection, Swipe to reload.", Toast.LENGTH_LONG )
.show()
}
// Must be added
container_swipe.isRefreshing = false
}
})
}
fun set_data(){
new_collection_list = viewModel.new_collection_list
best_selling_list = viewModel.best_sellling_list
new_collection_list.observe(viewLifecycleOwner, Observer {
new_collections_adapter.submitList(it)
new_collections_adapter.notifyDataSetChanged()
})
best_selling_list.observe(viewLifecycleOwner, Observer {
best_selling_adapter.submitList(it)
best_selling_adapter.notifyDataSetChanged()
})
}
fun isConnected(ctx: Context?): Boolean {
val hasInternet: Boolean
val connectivityManager =
ctx?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val actNw =
connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
hasInternet = when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
hasInternet = try {
if (connectivityManager.activeNetworkInfo == null) {
false
} else {
connectivityManager.activeNetworkInfo?.isConnected!!
}
} catch (e: Exception) {
false
}
}
return hasInternet}
override fun onItemClick(product : Product) {
val action = HomeFragmentDirections.actionHomeFragmentToProductFragment(product, product.title, R.id.homeFragment)
findNavController().navigate(action)
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="#+id/container_swipe"
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="match_parent"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".main_activity.fragments.home_fragment.HomeFragment"
>
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.SearchView
android:id="#+id/search_view"
android:layout_width="0dp"
android:layout_height="50dp"
app:layout_constraintWidth_percent="0.9"
android:elevation="2dp"
android:outlineProvider="bounds"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="20dp"/>
<androidx.cardview.widget.CardView
android:id="#+id/img_advertisment"
android:layout_width="0dp"
android:layout_height="180dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/search_view"
app:layout_constraintWidth_percent="0.9"
android:background="#00000000"
app:cardElevation="0dp"
app:cardCornerRadius="10dp"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/advertisment"
/>
</androidx.cardview.widget.CardView>
<RelativeLayout
android:id="#+id/container_new_collection"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/img_advertisment"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_percent="0.9"
android:layout_marginTop="20dp"
>
<TextView
android:id="#+id/tv_new_collection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Collections"
android:textColor="#color/tomato"
android:textSize="25dp"
android:fontFamily="sans-serif-black"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show All"
android:textSize="20dp"
android:textColor="#c6c4ce"
android:fontFamily="sans-serif-black"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginTop="5dp"/>
<com.facebook.shimmer.ShimmerFrameLayout
android:id="#+id/layout_new_collection_shimmer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:shimmer_repeat_mode="restart"
app:shimmer_shape="linear"
android:layout_below="#id/tv_new_collection"
android:layout_marginTop="10dp">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
</LinearLayout>
</HorizontalScrollView>
</com.facebook.shimmer.ShimmerFrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_marginTop="10dp"
android:id="#+id/rv_new_collections"
android:layout_width="wrap_content"
android:layout_height="350dp"
android:layout_below="#id/tv_new_collection"
tools:listitem="#layout/product_item_layout"
android:visibility="invisible"
/>
</RelativeLayout>
<RelativeLayout
android:id="#+id/container_best_selling"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/container_new_collection"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_percent="0.9"
android:layout_marginTop="20dp"
>
<TextView
android:id="#+id/tv_best_selling"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Best Selling"
android:textColor="#color/tomato"
android:textSize="25dp"
android:fontFamily="sans-serif-black"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show All"
android:textSize="20dp"
android:textColor="#c6c4ce"
android:fontFamily="sans-serif-black"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginTop="5dp"
/>
<com.facebook.shimmer.ShimmerFrameLayout
android:id="#+id/layout_best_selling_shimmer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:shimmer_repeat_mode="restart"
app:shimmer_shape="linear"
android:layout_marginTop="10dp"
android:layout_below="#id/tv_best_selling">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
</LinearLayout>
</HorizontalScrollView>
</com.facebook.shimmer.ShimmerFrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_best_selling"
android:layout_width="wrap_content"
android:layout_height="350dp"
android:layout_below="#id/tv_best_selling"
tools:listitem="#layout/product_item_layout"
android:layout_marginTop="10dp"
android:visibility="invisible"
/>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
I Figured out what is the problem. The API takes much time to send the data. So, the recycler view renders the view with null values.

How to show a window overlay over the accessibility menu in android 10?

I have done some code which is working fine everywhere except settings app -> accessibility menu or device admin apps menu
I need to display overlay in settings -> accessibility and device admin apps menu
I have a application where i see this type of overlay you can see below image
First image from settings app
Second image from settings app
You can see above second image when i open -> device admin app -> then my app overlay got hidden but another app overlay is still visible I don't know why?
Please help me guys to fix this issue??
**AndridManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxxxx">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION" />
<application
.....
.....
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".OverlayService" />
</application>
</manifest>
import android.content.Intent
import android.graphics.PixelFormat
import android.os.Build
import android.os.IBinder
import android.view.*
class OverlayService : Service() {
private var windowManager: WindowManager? = null
private var view: View? = null
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
val layoutParamsType: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
WindowManager.LayoutParams.TYPE_PHONE
}
val params = WindowManager.LayoutParams().apply {
width = WindowManager.LayoutParams.MATCH_PARENT
height = WindowManager.LayoutParams.WRAP_CONTENT
type = layoutParamsType
flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
format = PixelFormat.TRANSLUCENT
}
params.gravity = Gravity.CENTER or Gravity.START
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
view = inflater.inflate(R.layout.overlay_view, null)
windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
windowManager!!.addView(view, params)
}
override fun onDestroy() {
super.onDestroy()
if (view != null) {
windowManager!!.removeView(view)
view = null
}
}
}
MainActivity.kt
import android.content.Intent
import android.os.Bundle
import android.provider.Settings
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
if (Settings.canDrawOverlays(this)) {
startService(Intent(this, OverlayService::class.java))
} else {
startManageDrawOverlaysPermission()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_DRAW_OVERLAY_PERMISSION -> {
if (Settings.canDrawOverlays(this)) {
startService(Intent(this, OverlayService::class.java))
} else {
Toast.makeText(this, "Permission is not granted!", Toast.LENGTH_SHORT).show()
}
}
}
}
private fun startManageDrawOverlaysPermission() {
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, "package:${packageName}".toUri()).apply {
startActivityForResult(this, REQUEST_CODE_DRAW_OVERLAY_PERMISSION)
}
}
companion object {
private const val REQUEST_CODE_DRAW_OVERLAY_PERMISSION = 5
}
}
activity_main.xml
<?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="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show !"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
overlay_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#00897B"
android:orientation="vertical"
android:padding="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Overlay Example View"
android:textColor="#color/white" />
</LinearLayout>

Old view data appears in activity briefly, before new data is put into activity using databinding and MVVM

I have two activities-
A. Product List
B. Product Detail
Whenever user clicks on product item, he goes to the product detail activity where an API is called which shows detail of that product.
Now the problem is, that for the first time, the views in Product Detail initially have no data and i am inflating the data in views using livedata in viewmodel, with the help of data-binding. Now when the user navigates back to Product List , finish is called on Product Detail Activity.
Mow when user again clicks on another product, this time when he is taken to the product detail screen, old product detail briefly appears before new product detail is fetched from API and binded in the views. I don't know what is causing this behavior. Can somebody point me in the right direction ?
I have already tried calling finish and System.gc, but somehow the view holds on to the old data before new data is inflated in it.
Product List Activity
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import androidx.core.view.GravityCompat
import androidx.appcompat.app.ActionBarDrawerToggle
import android.view.MenuItem
import android.view.View
import androidx.drawerlayout.widget.DrawerLayout
import com.google.android.material.navigation.NavigationView
import android.widget.TextView
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.app.thingle.R
import com.app.thingle.databinding.ActivitySideMenuBinding
import com.app.thingle.data.model.dashBoardDataPackage.DashBoardStatus
import com.app.thingle.data.model.dashBoardDataPackage.Product
import com.app.thingle.utility.Constants
import com.app.thingle.viewModel.DashboardViewModel
import kotlinx.android.synthetic.main.activity_side_menu.view.*
import kotlinx.android.synthetic.main.app_bar_side_menu.view.*
import java.util.ArrayList
class SideMenuActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
lateinit var sideMenuBinding: ActivitySideMenuBinding
lateinit var dashboardViewModel: DashboardViewModel
private lateinit var cartTextView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sideMenuBinding = DataBindingUtil.setContentView(this, R.layout.activity_side_menu)
dashboardViewModel = ViewModelProviders.of(this).get(DashboardViewModel::class.java)
sideMenuBinding.viewModel = dashboardViewModel
dashboardViewModel.getProductsFromServer()
sideMenuBinding.navView.setNavigationItemSelectedListener(this)
val toggle = ActionBarDrawerToggle(
this,
sideMenuBinding.drawerLayout,
sideMenuBinding.appBarSideMenu.mainToolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
)
toggle.isDrawerIndicatorEnabled = false
sideMenuBinding.drawerLayout.addDrawerListener(toggle)
toggle.syncState()
if (!dashboardViewModel.isUser()) {
sideMenuBinding.drawerLayout.nav_view.menu.findItem(R.id.nav_log_out).isVisible = false
}
sideMenuBinding.appBarSideMenu.mainToolbar.toolbar_action_holder.menu_icon_id.setOnClickListener {
sideMenuBinding.drawerLayout.openDrawer(GravityCompat.START)
}
cartTextView =
sideMenuBinding.appBarSideMenu.mainToolbar.toolbar_action_holder.cart_holder.cart_amount
setUpBindings()
}
private fun setUpBindings() {
handleActivityStatus()
handleLoaderState()
handleApiResponse()
setUpListUpdate()
setUpCartStatus()
setUpListClicks()
}
private fun setUpListUpdate() {
dashboardViewModel.getProductsByType().observe(this, Observer {
dashboardViewModel.setItemsInAdapter(it)
})
}
private fun setUpCartStatus() {
dashboardViewModel.getCartCount().observe(this, Observer {
if (it > 0) {
cartTextView.visibility = View.VISIBLE
cartTextView.text = it.toString()
}
})
}
private fun handleApiResponse() {
dashboardViewModel.getApiResponse().observe(this, Observer { handleResponse(it) })
}
private fun handleLoaderState() {
dashboardViewModel.getUiState().observe(this, Observer { handleState(it) })
}
private fun handleActivityStatus() {
dashboardViewModel.getDashboardStatus().observe(this, Observer {
when (it) {
DashBoardStatus.WRONG_PRODUCT_TYPE -> {
sideMenuBinding.appBarSideMenu.mainContent.noResultFoundLayout.visibility =
View.VISIBLE
sideMenuBinding.appBarSideMenu.mainContent.recyclerText.visibility = View.GONE
}
DashBoardStatus.GO_TO_CART_SCREEN -> {
showToast("Go to Cart")
}
DashBoardStatus.GO_TO_SEARCH_SCREEN -> {
this.startActivity(
Intent(this, SearchScreen::class.java)
)
}
DashBoardStatus.EMPTY_LIST -> {
sideMenuBinding.appBarSideMenu.mainContent.noResultFoundLayout.visibility =
View.VISIBLE
sideMenuBinding.appBarSideMenu.mainContent.recyclerText.visibility = View.GONE
}
DashBoardStatus.FETCH_API_SUCCESS -> {
sideMenuBinding.appBarSideMenu.mainContent.recyclerText.visibility =
View.VISIBLE
}
DashBoardStatus.FETCH_API_ERROR -> {
sideMenuBinding.appBarSideMenu.mainContent.noResultFoundLayout.visibility =
View.VISIBLE
sideMenuBinding.appBarSideMenu.mainContent.recyclerText.visibility = View.GONE
}
DashBoardStatus.NO_CONNECTION -> {
showToast(getString(R.string.no_network))
}
else -> showToast(getString(R.string.something_went_wrong))
}
})
}
private fun setUpListClicks() {
dashboardViewModel.getSelectedProductType().observe(this, Observer {
this.startActivity(
Intent(this, BooksCategoryActivity::class.java)
.putParcelableArrayListExtra(
Constants.PRODUCT_LIST,
it.Products as ArrayList<Product>
)
.putExtra(Constants.CATEGORY_NAME, it.name)
.putExtra(Constants.ID, it.id)
)
})
dashboardViewModel.getSelectedProduct().observe(this, Observer {
this.startActivity(
Intent(this, BookDetailActivity::class.java)
.putExtra(Constants.PRODUCT_ID, it.id)
)
})
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_borrows -> {
if (dashboardViewModel.isUser()) {
this.startActivity(Intent(this, BorrowHistoryActivity::class.java))
} else {
goToLogin()
}
}
R.id.nav_contributions -> {
if (dashboardViewModel.isUser()) {
this.startActivity(Intent(this, ContributionHistoryActivity::class.java))
} else {
goToLogin()
}
}
R.id.nav_profile -> {
if (dashboardViewModel.isUser()) {
this.startActivity(Intent(this, EditProfileActivity::class.java))
} else {
goToLogin()
}
}
R.id.nav_help_contact -> {
if (dashboardViewModel.isUser()) {
this.startActivity(Intent(this, ContactUsActivity::class.java))
} else {
goToLogin()
}
}
R.id.nav_log_out -> {
logOut()
}
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
private fun goToLogin() {
this.startActivity(Intent(this, LoginActivity::class.java))
finishAffinity()
}
private fun logOut() {
dashboardViewModel.clearUserData()
goToLogin()
}
override fun onBackPressed() {
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START)
} else {
this.startActivity(Intent(this, ChooseTypeActivity::class.java))
killActivity()
}
}
private fun killActivity() {
this.finishAffinity()
}
}
layout- Product Detail
<?xml version="1.0" encoding="utf-8"?>
<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">
<data>
<variable
name="viewModel"
type="com.app.thingle.viewModel.ProductDetailViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/main_layout_holder"
tools:context=".ui.activities.BookDetailActivity">
<include
android:id="#+id/about_book_toolbar"
layout="#layout/thingle_search_and_cart_toolbar" />
<FrameLayout
android:id="#+id/product_not_available_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="3dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/about_book_toolbar">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/lightPink"
android:fontFamily="#font/avenirltstd_book"
android:gravity="center"
android:padding="5dp"
android:visibility="gone"
android:text="#string/this_product_is_currently_unavailable"
android:textColor="#color/white"
android:textSize="14sp" />
</FrameLayout>
<ScrollView
android:id="#+id/about_product_scrollView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/product_not_available_holder">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/book_image_id"
android:layout_width="100dp"
android:layout_height="140dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/book_name_id"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintVertical_bias="0.1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:fontFamily="#font/avenirltstd_black"
android:textColor="#color/black"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/book_image_id"
app:layout_constraintTop_toTopOf="#id/book_image_id"
app:layout_constraintBottom_toTopOf="#id/book_intro"
/>
<TextView
android:id="#+id/book_intro"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:fontFamily="#font/avenirltstd_book"
android:textColor="#color/black"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/book_image_id"
app:layout_constraintTop_toBottomOf="#id/book_name_id"
app:layout_constraintBottom_toBottomOf="#id/book_image_id"
/>
<Button
android:id="#+id/add_cart_id"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="#drawable/pink_button_border"
android:fontFamily="#font/avenirltstd_book"
android:onClick="#{viewModel::onAddCartButtonClicked}"
android:text="#string/add_to_cart"
android:textAllCaps="false"
android:textColor="#color/white"
android:textSize="18sp"
app:layout_constraintEnd_toStartOf="#id/share_id"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/book_image_id" />
<Button
android:id="#+id/share_id"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:background="#drawable/pink_button_border"
android:fontFamily="#font/avenirltstd_book"
android:onClick="#{viewModel::onShareButtonClicked}"
android:text="#string/share"
android:textAllCaps="false"
android:textColor="#color/white"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="#id/add_cart_id"
app:layout_constraintTop_toBottomOf="#+id/book_image_id" />
<View
android:id="#+id/line_id"
android:layout_width="0dp"
android:layout_height="0.1dp"
android:layout_marginTop="20dp"
android:background="#color/grey"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/add_cart_id" />
<TextView
android:id="#+id/about_book_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="15dp"
android:fontFamily="#font/avenirltstd_book"
android:text="#string/about"
android:textColor="#color/black"
android:textSize="22sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/line_id" />
<TextView
android:id="#+id/text_info_book"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:fontFamily="#font/avenirltstd_book"
android:lineSpacingExtra="#dimen/line_spacing"
android:textColor="#color/lightBlack"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/about_book_info" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Product Detail Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.TextView
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.app.thingle.R
import com.app.thingle.data.model.bookDetailDataPackage.ProductDetailStatus
import com.app.thingle.databinding.ActivityBookDetailBinding
import com.app.thingle.utility.Constants
import com.app.thingle.viewModel.ProductDetailViewModel
import kotlinx.android.synthetic.main.thingle_search_and_cart_toolbar.view.*
import android.view.KeyEvent.KEYCODE_BACK
import android.view.KeyEvent
import androidx.lifecycle.ViewModel
class BookDetailActivity : BaseActivity() {
private lateinit var bookDetailBinding: ActivityBookDetailBinding
private lateinit var productDetailViewModel: ProductDetailViewModel
private lateinit var cartTextView: TextView
private lateinit var toolBarTitle: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bookDetailBinding = DataBindingUtil.setContentView(this, R.layout.activity_book_detail)
productDetailViewModel = ViewModelProviders.of(this).get(ProductDetailViewModel::class.java)
bookDetailBinding.viewModel = productDetailViewModel
productDetailViewModel.getProductById(intent.getIntExtra(Constants.PRODUCT_ID, -1))
setUpBindings()
setUpToolbar()
}
private fun setUpToolbar() {
toolBarTitle = bookDetailBinding.aboutBookToolbar.toolbar_action_holder.thingle_toolbar_text
toolBarTitle.text = getString(R.string.about_Book)
bookDetailBinding.aboutBookToolbar.toolbar_action_holder.thingle_logo_toolbar_back.setOnClickListener { onBackPressed() }
bookDetailBinding.aboutBookToolbar.toolbar_action_holder.toolbar_search_id.setOnClickListener {
this.startActivity(
Intent(this, SearchScreen::class.java)
)
finish()
}
bookDetailBinding.aboutBookToolbar.toolbar_action_holder.cart_id.setOnClickListener {
showToast(
"Go To Cart"
)
}
cartTextView =
bookDetailBinding.aboutBookToolbar.toolbar_action_holder.cart_holder.cart_amount
}
private fun setUpBindings() {
setUpValues()
handleLoaderState()
handleApiResponse()
setUpCartStatus()
handleActivityStatus()
setUpButtonClick()
}
private fun setUpValues() {
productDetailViewModel.getProduct().observe(this, Observer {
if (!it.isAvailable) {
bookDetailBinding.productNotAvailableHolder.visibility = View.VISIBLE
bookDetailBinding.addCartId.visibility = View.GONE
}
bookDetailBinding.bookNameId.text = it.title
bookDetailBinding.bookIntro.text = it.shortDescription
bookDetailBinding.textInfoBook.text = it.description
if (it.ProductImages!!.isNotEmpty()) {
if (it.ProductImages[0].imageUrl != null) {
setImageUrlOnImageView(
bookDetailBinding.bookImageId,
it.ProductImages[0].imageUrl
)
}
}
})
}
private fun setUpButtonClick() {
productDetailViewModel.getProductId().observe(this, Observer {
showToast(it.toString())
})
}
private fun handleActivityStatus() {
productDetailViewModel.getActivityStatus().observe(this, Observer {
when (it) {
ProductDetailStatus.FETCH_API_SUCCESS -> {
}
ProductDetailStatus.FETCH_API_ERROR -> {
showToast(getString(R.string.something_went_wrong))
onBackPressed()
}
ProductDetailStatus.NO_CONNECTION -> {
showToast(getString(R.string.no_network))
}
ProductDetailStatus.EMPTY_DATA -> {
showToast(getString(R.string.no_data))
onBackPressed()
}
ProductDetailStatus.SHARE_BUTTON_CLICKED -> {
showToast("Share")
}
//ProductDetailStatus.ADD_CART_BUTTON_CLICKED->{showToast("Add To Cart")}
else -> {
showToast(getString(R.string.something_went_wrong))
}
}
})
}
private fun setUpCartStatus() {
productDetailViewModel.getCartCount().observe(this, Observer {
if (it > 0) {
cartTextView.visibility = View.VISIBLE
cartTextView.text = it.toString()
}
})
}
private fun handleApiResponse() {
productDetailViewModel.getApiResponse().observe(this, Observer { handleResponse(it) })
}
private fun handleLoaderState() {
productDetailViewModel.getUiState().observe(this, Observer { handleState(it) })
}
override fun onBackPressed() {
super.onBackPressed()
killActivity()
}
private fun killActivity() {
finish()
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode == KEYCODE_BACK) {
killActivity()
}
return super.onKeyDown(keyCode, event)
}
}
Product Detail Viewmodel
import android.app.Application
import android.view.View
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.app.thingle.data.model.bookDetailDataPackage.ProductDetailStatus
import com.app.thingle.data.model.bookDetailDataPackage.ResponseObject
import com.app.thingle.data.repository.CartRepository
import com.app.thingle.data.repository.ProductDetailRepository
import com.app.thingle.utility.ApiResponseCallback
import com.app.thingle.utility.ConnectionDetector
import com.app.thingle.utility.SingleLiveEvent
class ProductDetailViewModel(application: Application) : BaseViewModel(application) {
private var product: MutableLiveData<ResponseObject> = MutableLiveData()
private var productId: MutableLiveData<Int> = MutableLiveData()
private var userCartItems =
MutableLiveData<List<com.app.thingle.data.model.cartDataPackage.ResponseObject>>()
var cartCount: MutableLiveData<Int> = MutableLiveData()
private val productDetailStatus = SingleLiveEvent<ProductDetailStatus>()
fun getProductById(productId: Int) {
if (product.value == null && productId != -1) {
fetchProductsByType(productId)
} else {
productDetailStatus.value = ProductDetailStatus.EMPTY_DATA
}
}
private fun fetchProductsByType(id: Int) {
if (ConnectionDetector.getInstance(context).isConnectionAvailable()) {
setLoaderState(true)
product = ProductDetailRepository.instance.fetchProductById(
id,
context,
object : ApiResponseCallback {
override fun provideResponse(
isApiError: Boolean,
isResponseError: Boolean,
response: String
) {
if (isApiError || isResponseError) {
setLoaderState(false)
productDetailStatus.value = ProductDetailStatus.FETCH_API_ERROR
} else {
productDetailStatus.value = ProductDetailStatus.FETCH_API_SUCCESS
if (product.value == null) {
productDetailStatus.value = ProductDetailStatus.EMPTY_DATA
}
if (isUser()) {
fetchCartForUser()
} else {
setLoaderState(false)
cartCount.value = 0
}
}
}
})
} else {
productDetailStatus.value = ProductDetailStatus.NO_CONNECTION
}
}
private fun fetchCartForUser() {
userCartItems =
CartRepository.instance.fetchCartForUser(context, object : ApiResponseCallback {
override fun provideResponse(
isApiError: Boolean,
isResponseError: Boolean,
response: String
) {
setLoaderState(false)
if (isApiError || isResponseError) {
cartCount.value = 0
} else {
if (userCartItems.value!!.isNotEmpty()) {
cartCount.value = userCartItems.value!!.size
}
}
}
})
}
fun getProductId(): LiveData<Int> {
return productId
}
fun getProduct(): LiveData<ResponseObject> {
return product
}
fun getCartCount(): LiveData<Int> {
return cartCount
}
fun getActivityStatus(): SingleLiveEvent<ProductDetailStatus> {
return productDetailStatus
}
fun onAddCartButtonClicked(v: View) {
productDetailStatus.value = ProductDetailStatus.ADD_CART_BUTTON_CLICKED
productId.value = product.value!!.id
}
fun onShareButtonClicked(v: View) {
productDetailStatus.value = ProductDetailStatus.SHARE_BUTTON_CLICKED
}
}
I found out the solution by implementing onCleared() inside my viewmodel and clearing my viewmodel objects.
super.onCreate(null) instead of super.onCreate(savedInstanceState) should do the trick.
You might want to put in some code to check if you want this to happen (ie. last instance was finished) or not (ie. you navigated away and system cleaned up your activity which it has to restart)

Categories

Resources