I defined two layers in a fragment, the display of which depends on the internet and gps on and off
There is no problem when the program runs, but when I enter another fragment and return to the first fragment, the code does not work properly.
onViewCreated
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//broadcast receiver for check runtime network
val registerReceiver = requireActivity().registerReceiver(
broadcastReceiver,
IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")
)
val registerReceiverr = requireActivity().registerReceiver(
broadcastReceiver,
IntentFilter("android.location.PROVIDERS_CHANGED")
)
}
broadcastReceiver
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Networkstate.isOnline(context) == false) {
binding.offlineRoot.visibility = View.VISIBLE
binding.onlineRoot.visibility = View.GONE
} else {
locationManager = requireActivity().getSystemService(AppCompatActivity.LOCATION_SERVICE) as LocationManager?
val statusOfGPS = locationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER)
if (statusOfGPS == true) {
binding.offlineRoot.visibility = View.GONE
binding.onlineRoot.visibility = View.VISIBLE
binding.ongps.visibility = View.VISIBLE
binding.offgps.visibility = View.GONE
} else {
binding.offlineRoot.visibility = View.GONE
binding.onlineRoot.visibility = View.VISIBLE
binding.ongps.visibility = View.GONE
binding.offgps.visibility = View.VISIBLE
}
}
}
}
Related
I have been having an issue with my card view color. I have a where you can select the color of the cardView. The color sets to the color that is selected. However when you update the entry the color defaults to the default color as if you never selected a color to begin with. I have the code I believe is correct but i may be missing something. Any help is greatly appreciated.
Adapter
class NotesAdapter :
RecyclerView.Adapter<NotesAdapter.NotesViewHolder>() {
private var listener: OnItemClickListener? = null
private var arrList = ArrayList<Notes>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotesViewHolder {
return NotesViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item_rv_notes,parent,false)
)
}
override fun getItemCount(): Int {
return arrList.size
}
fun setData(arrNotesList: List<Notes>){
arrList = arrNotesList as ArrayList<Notes>
}
fun setOnClickListener(listener1: OnItemClickListener){
listener = listener1
}
override fun onBindViewHolder(holder: NotesViewHolder, position: Int) {
holder.itemView.tvTitle.text = arrList[position].title
holder.itemView.tvDesc.text = arrList[position].noteText
holder.itemView.tvDateTime.text = arrList[position].dateTime
if (arrList[position].color != null){
holder.itemView.cardView.setCardBackgroundColor(Color.parseColor(arrList[position].color))
}else{
holder.itemView.cardView.setCardBackgroundColor(Color.parseColor(R.color.ColorLightBlack.toString()))
}
if (arrList[position].imgPath != null){
holder.itemView.imgNote.setImageBitmap(BitmapFactory.decodeFile(arrList[position].imgPath))
holder.itemView.imgNote.visibility = View.VISIBLE
}else{
holder.itemView.imgNote.visibility = View.GONE
}
if (arrList[position].webLink != ""){
holder.itemView.tvWebLink.text = arrList[position].webLink
holder.itemView.tvWebLink.visibility = View.VISIBLE
}else{
holder.itemView.tvWebLink.visibility = View.GONE
}
holder.itemView.cardView.setOnClickListener {
listener!!.onClicked(arrList[position].id!!)
}
}
class NotesViewHolder(view:View) : RecyclerView.ViewHolder(view)
interface OnItemClickListener{
fun onClicked(noteId:Int)
}
}
BottomFragment
#Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", "DEPRECATION",
"UNUSED_EXPRESSION")
class NotesBottomSheetFragment : BottomSheetDialogFragment() {
private var selectedColor = "#E53935"
companion object {
var noteId = -1
fun newInstance(id:Int): NotesBottomSheetFragment {
val args = Bundle()
val fragment = NotesBottomSheetFragment()
fragment.arguments = args
noteId = id
return fragment
}
}
#SuppressLint("RestrictedApi", "InflateParams")
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
val view = LayoutInflater.from(context).inflate(R.layout.fragment_notes_bottom_sheet,null)
dialog.run {
setContentView(view)
}
val param = (view.parent as View).layoutParams as CoordinatorLayout.LayoutParams
val behavior = param.behavior
if (behavior is BottomSheetBehavior<*>){
behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback(){
override fun onSlide(bottomSheet: View, slideOffset: Float) {
TODO("Not yet implemented")
}
#SuppressLint("SwitchIntDef")
override fun onStateChanged(bottomSheet: View, newState: Int) {
""
when (newState) {
BottomSheetBehavior.STATE_DRAGGING -> {
}
BottomSheetBehavior.STATE_SETTLING -> {
}
BottomSheetBehavior.STATE_EXPANDED -> {
}
BottomSheetBehavior.STATE_COLLAPSED -> {
}
BottomSheetBehavior.STATE_HIDDEN -> {
dismiss()
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
}
})
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_notes_bottom_sheet,container,false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (noteId != -1){
layoutDeleteNote.visibility = View.VISIBLE
}else{
layoutDeleteNote.visibility = View.GONE
}
setListener()
}
private fun setListener(){
fNote1.setOnClickListener {
imgNote1.setImageResource(R.drawable.ic_tick)
imgNote2.setImageResource(0)
imgNote4.setImageResource(0)
imgNote5.setImageResource(0)
imgNote6.setImageResource(0)
imgNote7.setImageResource(0)
selectedColor = "#4e33ff"
val intent = Intent("bottom_sheet_action")
intent.putExtra("action","Blue")
intent.putExtra("selectedColor",selectedColor)
LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent)
}
fNote2.setOnClickListener {
imgNote1.setImageResource(0)
imgNote2.setImageResource(R.drawable.ic_tick)
imgNote4.setImageResource(0)
imgNote5.setImageResource(0)
imgNote6.setImageResource(0)
imgNote7.setImageResource(0)
selectedColor = "#BAFFD105"
val intent = Intent("bottom_sheet_action")
intent.putExtra("action","Yellow")
intent.putExtra("selectedColor",selectedColor)
LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent)
}
fNote4.setOnClickListener {
imgNote1.setImageResource(0)
imgNote2.setImageResource(0)
imgNote4.setImageResource(R.drawable.ic_tick)
imgNote5.setImageResource(0)
imgNote6.setImageResource(0)
imgNote7.setImageResource(0)
selectedColor = "#ae3b76"
val intent = Intent("bottom_sheet_action")
intent.putExtra("action","Purple")
intent.putExtra("selectedColor",selectedColor)
LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent)
}
fNote5.setOnClickListener {
imgNote1.setImageResource(0)
imgNote2.setImageResource(0)
imgNote4.setImageResource(0)
imgNote5.setImageResource(R.drawable.ic_tick)
imgNote6.setImageResource(0)
imgNote7.setImageResource(0)
selectedColor = "#7CB342"
val intent = Intent("bottom_sheet_action")
intent.putExtra("action","Green")
intent.putExtra("selectedColor",selectedColor)
LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent)
}
fNote6.setOnClickListener {
imgNote1.setImageResource(0)
imgNote2.setImageResource(0)
imgNote4.setImageResource(0)
imgNote5.setImageResource(0)
imgNote6.setImageResource(R.drawable.ic_tick)
imgNote7.setImageResource(0)
selectedColor = "#ff7746"
val intent = Intent("bottom_sheet_action")
intent.putExtra("action","Orange")
intent.putExtra("selectedColor",selectedColor)
LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent)
}
fNote7.setOnClickListener {
imgNote1.setImageResource(0)
imgNote2.setImageResource(0)
imgNote4.setImageResource(0)
imgNote5.setImageResource(0)
imgNote6.setImageResource(0)
imgNote7.setImageResource(R.drawable.ic_tick)
selectedColor = "#000000"
val intent = Intent("bottom_sheet_action")
intent.putExtra("action","Black")
intent.putExtra("selectedColor",selectedColor)
LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent)
}
layoutImage.setOnClickListener{
val intent = Intent("bottom_sheet_action")
intent.putExtra("action","Image")
LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent)
dismiss()
}
layoutWebUrl.setOnClickListener{
val intent = Intent("bottom_sheet_action")
intent.putExtra("action","WebUrl")
LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent)
dismiss()
}
layoutDeleteNote.setOnClickListener {
val intent = Intent("bottom_sheet_action")
intent.putExtra("action","DeleteNote")
LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent)
dismiss()
}
}
}
Create Note Fragment
private fun updateNote(){
launch {
context?.let {
val notes = NotesDatabase.getDatabase(it).noteDao().getSpecificNote(noteId)
notes.title = etNoteTitle.text.toString()
notes.subTitle = etNoteSubTitle.text.toString()
notes.noteText = etNoteDesc.text.toString()
notes.dateTime = currentDate
notes.color = selectedColor
notes.imgPath = selectedImagePath
notes.webLink = webLink
NotesDatabase.getDatabase(it).noteDao().updateNote(notes)
etNoteTitle.setText("")
etNoteSubTitle.setText("")
etNoteDesc.setText("")
layoutImage.visibility = View.GONE
imgNote.visibility = View.GONE
tvWebLink.visibility = View.GONE
requireActivity().supportFragmentManager.popBackStack()
}
}
}
private fun saveNote(){
if (etNoteTitle.text.isNullOrEmpty()){
Toast.makeText(context,"Note Title is Required",Toast.LENGTH_SHORT).show()
}
else if(etNoteSubTitle.text.isNullOrEmpty()){
Toast.makeText(context,"Note Sub-Title is Required",Toast.LENGTH_SHORT).show()
}
else if (etNoteDesc.text.isNullOrEmpty()){
Toast.makeText(context,"Note Description is Required",Toast.LENGTH_SHORT).show()
}
else{
launch {
val notes = Notes()
notes.title = etNoteTitle.text.toString()
notes.subTitle = etNoteSubTitle.text.toString()
notes.noteText = etNoteDesc.text.toString()
notes.dateTime = currentDate
notes.color = selectedColor
notes.imgPath = selectedImagePath
notes.webLink = webLink
context?.let {
NotesDatabase.getDatabase(it).noteDao().insertNotes(notes)
etNoteTitle.setText("")
etNoteSubTitle.setText("")
etNoteDesc.setText("")
layoutImage.visibility = View.GONE
imgNote.visibility = View.GONE
tvWebLink.visibility = View.GONE
requireActivity().supportFragmentManager.popBackStack()
}
}
}
}
So my issue is with when updating the note the cardview does not retain the same color as when it was originally saved. SO change the card color works fine. It just the update portion that i am having an issue with. In my adapter it should trigger that the default color is different so it should retain the color not default.
I believe the issue is here
if (arrList[position].color != null){
holder.itemView.cardView.setCardBackgroundColor(Color.parseColor(arrList[position].color))
}else{
holder.itemView.cardView.setCardBackgroundColor(Color.parseColor(R.color.ColorLightBlack.toString()))
}
however I may be wrong. Any help is greatly appreciated.
I am updating my app to completely remove synthetics and move to viewbinding, however I am struggling with converting the onBackPressed method (now also deprecated) with my Activity, Fragment and Navigation Drawer.
I originally had it like this:
Activity (Before)
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate")
super.onCreate(savedInstanceState)
val activityBinding: BusinessActivityBinding = DataBindingUtil.setContentView(
this,
R.layout.business_activity
)
nav_view.setNavigationItemSelectedListener(this)
val headerView = activityBinding.navView.getHeaderView(0)
headerView.navHeaderEmailText.setOnClickListener { sendSupportEmail() }
navController = findNavController(this, R.id.NavHostFragment)
// other stuff
}
fun openCloseNavigationDrawer() {
if (business_drawer_layout.isDrawerOpen(GravityCompat.START)) {
business_drawer_layout.closeDrawer(GravityCompat.START)
} else {
business_drawer_layout.openDrawer(GravityCompat.START)
}
}
override fun onBackPressed() {
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(R.id.NavHostFragment) as NavHostFragment
val backStackEntryCount = navHostFragment?.childFragmentManager?.backStackEntryCount
when {
(business_drawer_layout.isDrawerOpen(GravityCompat.START)) -> business_drawer_layout.closeDrawer(
GravityCompat.START
)
(backStackEntryCount == 0) -> dialogLeaveApp()
else -> super.onBackPressed()
}
}
private fun dialogLeaveApp(){
MaterialDialog(this).show {
title(R.string.business_activity_dialog_leave_app_heading)
message(R.string.business_activity_dialog_leave_app_message)
positiveButton(R.string.business_activity_dialog_confirm_button){
super.onBackPressed()
}
negativeButton(R.string.business_activity_dialog_cancel_button) {
dismiss()
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_sites_fragment -> navigateWithClearStack(R.id.sitesFragment)
R.id.nav_projects_fragment -> navigateWithClearStack(R.id.projectsFragment)
R.id.nav_contacts_fragment -> navigateWithClearStack(R.id.contactsFragment)
R.id.nav_tasks_fragment -> navigateWithClearStack(R.id.tasksFragment)
R.id.nav_profile_fragment -> makeToast("Todo: Profile Fragment")
R.id.nav_settings_fragment -> navigateWithClearStack(R.id.settingsFragment)
}
business_drawer_layout.closeDrawer(GravityCompat.START)
return true
}
private fun navigateWithClearStack(destination: Int) {
businessViewModel.clearCurrentVMData()
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(R.id.NavHostFragment) as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.business_navigation)
graph.startDestination = destination
navController.graph = graph
}
}
Fragment (already using viewbinding)
class SitesFragment : Fragment() {
private lateinit var navController: NavController
private lateinit var businessViewModel: BusinessViewModel
private lateinit var sitesAdapter: SitesRecyclerViewAdapter
private var _binding: SitesFragmentBinding? = null // this property is only valid between onCreateView & onDestroyView
private val binding get() = _binding!! //https://stackoverflow.com/questions/57647751/android-databinding-is-leaking-memory
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
Log.d(TAG, "onCreateView()")
activity?.let {
businessViewModel = ViewModelProvider(it).get(BusinessViewModel::class.java)
Log.d(TAG, "businessViewModel = $businessViewModel")
}
Log.d(TAG, businessViewModel.currentStatus("${TAG}, onCreateView()"))
// Inflate the layout for this fragment
_binding = SitesFragmentBinding.inflate(inflater, container, false)
val view = binding.root
binding.apply {
sitesDrawerMenuButton.setOnClickListener {
(activity as BusinessActivity).openCloseNavigationDrawer()
Log.d(TAG, "sitesDrawerMenuButton clicked, openCloseNavigationDrawer()")
}
// Other listeners
}
return view
}
Activity (After)
private var _binding: BusinessActivityBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate")
super.onCreate(savedInstanceState)
// Inflate the layout for this activity
_binding = BusinessActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.NavHostFragment) as NavHostFragment
this.navController = navHostFragment.navController
binding.navView.setupWithNavController(this.navController)
// Setup OnBackPressedDispatcher
val backPressedCallback = object:OnBackPressedCallback(false){
override fun handleOnBackPressed() {
onBackButtonPressed()
}
}
// Other stuff
}
fun openCloseNavigationDrawer() { // accessed by Fragment
if (binding.businessDrawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.businessDrawerLayout.closeDrawer(GravityCompat.START)
} else {
binding.businessDrawerLayout.openDrawer(GravityCompat.START)
}
}
fun onBackButtonPressed() {
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(R.id.NavHostFragment) as NavHostFragment
val backStackEntryCount = navHostFragment.childFragmentManager.backStackEntryCount
when {
(binding.businessDrawerLayout.isDrawerOpen(GravityCompat.START)) -> binding.businessDrawerLayout.closeDrawer(
GravityCompat.START
)
(backStackEntryCount == 0) -> dialogLeaveApp()
}
}
private fun dialogLeaveApp(){
// as before
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// as before
}
private fun navigateWithClearStack(destination: Int) {
// as before
}
So the issue is that when you back press, it simply exits the app, rather than triggering my function onBackButtonPressed() (which replaces the depricated onBackPressed())and variable 'backPressedCallback' is never used..
I'm trying to implement an OnClick listener for specific items in a recyclerview. I've done it before with activities, but now I want to do this in a fragment and I've run into a problem. I'm getting the error No value passed for parameter 'click'. This is the line of code that gives that error:
recyclerAdapterAbstract = abstractList.let {AbstractAdapter(requireActivity(),it)}
This the only error Android Studio is currently showing me. The logcat doesn't show any error. Only the Build Output shows what's wrong and it's exactly what I said earlier
Fragment Class
#Suppress("UNREACHABLE_CODE")
class AbstractWallpapers: Fragment(), PurchasesUpdatedListener, AbstractAdapter.OnItemClickListenerAbstract {
private lateinit var subscribeAbstract: Button
private var billingClient: BillingClient? = null
lateinit var recyclerView: RecyclerView
lateinit var abstractList: ArrayList<Abstract>
private var recyclerAdapterAbstract: AbstractAdapter? = null
private var myRef3: DatabaseReference? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_abstract_wallpaper, container, false)
recyclerView = requireActivity().findViewById(R.id.abstract_recyclerView)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = view.findViewById(R.id.abstract_recyclerView)
val layoutManager = GridLayoutManager(requireContext(), 2)
recyclerView.layoutManager = layoutManager
recyclerView.setHasFixedSize(true)
myRef3 = FirebaseDatabase.getInstance().reference
abstractList = ArrayList()
ClearAll()
GetDataFromFirebase()
subscribeAbstract = view.findViewById(R.id.abstract_subscribe_btn)
subscribeAbstract.setOnClickListener {
subscribeAbstract()
}
//Establish connection to billing client
//check subscription status from google play store cache
//to check if item is already Subscribed or subscription is not renewed and cancelled
billingClient = BillingClient.newBuilder(requireActivity()).enablePendingPurchases().setListener(this).build()
billingClient!!.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
val queryPurchase = billingClient!!.queryPurchases(BillingClient.SkuType.SUBS)
val queryPurchases = queryPurchase.purchasesList
if (queryPurchases != null && queryPurchases.size > 0) {
handlePurchases(queryPurchases)
} else {
saveSubscribeValueToPref(false)
}
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(requireActivity(), "Service Disconnected", Toast.LENGTH_SHORT).show()
}
})
//item subscribed
if (subscribeValueFromPref) {
subscribeAbstract.visibility = View.GONE
} else {
subscribeAbstract.visibility = View.VISIBLE
}
}
// Code relating to my Firebase storage
#SuppressLint("NotifyDataSetChanged")
private fun GetDataFromFirebase() {
val query: Query = myRef3!!.child("Abstract")
query.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (dataSnapshot: DataSnapshot in snapshot.children) {
val abstract = Abstract()
abstract.abstract = dataSnapshot.child("abstract").value.toString()
abstractList.add(abstract)}
recyclerAdapterAbstract = abstractList.let {AbstractAdapter(requireActivity(),it)}
recyclerView.adapter = recyclerAdapterAbstract
recyclerAdapterAbstract!!.notifyDataSetChanged()
}
override fun onCancelled(error: DatabaseError) {}
})
if (recyclerAdapterAbstract != null) recyclerAdapterAbstract!!.notifyDataSetChanged()
}
private fun ClearAll() {
abstractList.clear()
abstractList = ArrayList()
}
private val preferenceObject: SharedPreferences
get() = requireActivity().getSharedPreferences(PREF_FILE, 0)
private val preferenceEditObject: SharedPreferences.Editor
get() {
val pref = requireActivity().getSharedPreferences(PREF_FILE, 0)
return pref.edit()
}
private val subscribeValueFromPref: Boolean
get() = preferenceObject.getBoolean(SUBSCRIBE_KEY, false)
private fun saveSubscribeValueToPref(value: Boolean) {
preferenceEditObject.putBoolean(SUBSCRIBE_KEY, value).commit()
}
//initiate purchase on button click
fun subscribeAbstract() {
//check if service is already connected
if (billingClient!!.isReady) {
initiatePurchase()
} else {
billingClient = BillingClient.newBuilder(requireActivity()).enablePendingPurchases().setListener(this).build()
billingClient!!.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
initiatePurchase()
} else {
Toast.makeText(requireActivity(), "Error " + billingResult.debugMessage, Toast.LENGTH_SHORT).show()
}
}
override fun onBillingServiceDisconnected() {
Toast.makeText(requireActivity(), "Service Disconnected ", Toast.LENGTH_SHORT).show()
}
})
}
}
private fun initiatePurchase() {
val skuList: MutableList<String> = ArrayList()
skuList.add(ITEM_SKU_SUBSCRIBE)
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS)
val billingResult = billingClient!!.isFeatureSupported(BillingClient.FeatureType.SUBSCRIPTIONS)
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
billingClient!!.querySkuDetailsAsync(params.build()
) { billingResult, skuDetailsList ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
if (skuDetailsList != null && skuDetailsList.size > 0) {
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList[0])
.build()
billingClient!!.launchBillingFlow(requireActivity(), flowParams)
} else {
//try to add subscription item "sub_example" in google play console
Toast.makeText(requireActivity(), "Item not Found", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(requireActivity(),
" Error " + billingResult.debugMessage, Toast.LENGTH_SHORT).show()
}
}
} else {
Toast.makeText(requireActivity(),
"Sorry Subscription not Supported. Please Update Play Store", Toast.LENGTH_SHORT).show()
}
}
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
//if item subscribed
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
handlePurchases(purchases)
}
else if (billingResult.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
val queryAlreadyPurchasesResult = billingClient!!.queryPurchases(BillingClient.SkuType.SUBS)
val alreadyPurchases = queryAlreadyPurchasesResult.purchasesList
alreadyPurchases?.let { handlePurchases(it) }
}
else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
Toast.makeText(requireActivity(), "Purchase Canceled", Toast.LENGTH_SHORT).show()
}
else {
Toast.makeText(requireActivity(), "Error " + billingResult.debugMessage, Toast.LENGTH_SHORT).show()
}
}
fun handlePurchases(purchases: List<Purchase>) {
for (purchase in purchases) {
//if item is purchased
if (ITEM_SKU_SUBSCRIBE == purchase.sku && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
// Invalid purchase
// show error to user
Toast.makeText(requireActivity(), "Error : invalid Purchase", Toast.LENGTH_SHORT).show()
return
}
// else purchase is valid
//if item is purchased and not acknowledged
if (!purchase.isAcknowledged) {
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient!!.acknowledgePurchase(acknowledgePurchaseParams, ackPurchase)
} else {
// Grant entitlement to the user on item purchase
// restart activity
if (!subscribeValueFromPref) {
saveSubscribeValueToPref(true)
Toast.makeText(requireActivity(), "Item Purchased", Toast.LENGTH_SHORT).show()
recreate(requireActivity())
}
}
} else if (ITEM_SKU_SUBSCRIBE == purchase.sku && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
Toast.makeText(requireActivity(),
"Purchase is Pending. Please complete Transaction", Toast.LENGTH_SHORT).show()
} else if (ITEM_SKU_SUBSCRIBE == purchase.sku && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
saveSubscribeValueToPref(false)
subscribeAbstract.visibility = View.VISIBLE
Toast.makeText(requireActivity(), "Purchase Status Unknown", Toast.LENGTH_SHORT).show()
}
}
}
var ackPurchase = AcknowledgePurchaseResponseListener { billingResult ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
//if purchase is acknowledged
// Grant entitlement to the user. and restart activity
saveSubscribeValueToPref(true)
recreate(requireActivity())
}
}
/**
* Verifies that the purchase was signed correctly for this developer's public key.
*
* Note: It's strongly recommended to perform such check on your backend since hackers can
* replace this method with "constant true" if they decompile/rebuild your app.
*
*/
private fun verifyValidSignature(signedData: String, signature: String): Boolean {
return try {
// To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
val base64Key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhBlajrk5nNjpRTPJjDtGxgtgAeKijz3Wc0KrRKKSCxxsViHl7DhsI+sUZfk4Y1jxSg4/3W1uRo/0UASM77XfJIq34bK9KYgoSAGYSuH8Z+4fK/MrPz7dHhsljkAi4GZkv8x9VhZdDdpn2GSHVFaxs8c+HBOFp9aWAErHrQhi9/7fYf39pQSTC3WkVcy9xNDZxiiKTfDN3dyEvS0XQ617ZJwqDuRdkU5Aw9+R8r+oXyURV/ekgCQkWfCUaTp/jWdySOIcR87Bde24lQAXbvJaL5uAYI4zPwO4sIP1AbXLuDtv3N2rFVmP/1cML/NHDcfI5FOoStz88jzJU26Ngpqu1QIDAQAB"
Security.verifyPurchase(base64Key, signedData, signature)
} catch (e: IOException) {
false
}
}
override fun onDestroy() {
super.onDestroy()
if (billingClient != null) {
billingClient!!.endConnection()
}
}
companion object {
const val PREF_FILE = "MyPref"
const val SUBSCRIBE_KEY = "subscribe"
const val ITEM_SKU_SUBSCRIBE = "abstract_wallpapers"
}
override fun onItemClick(item: String) {
}
}
Adapter class
class AbstractAdapter(private val mContext: Context, private val abstractList: ArrayList<Abstract>, private val click: OnItemClickListenerAbstract ) :
RecyclerView.Adapter<AbstractAdapter.ViewHolder>() {
interface OnItemClickListenerAbstract{
fun onItemClick(item:String)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.abstract_image_view, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Glide.with(mContext)
.load(abstractList[position].abstract)
.into(holder.imageView)
holder.imageView.setOnClickListener {
val intent = Intent(mContext, AbstractPreview::class.java)
intent.putExtra("abstract", abstractList[position].abstract.toString())
Toast.makeText(mContext, "Fullscreen view", Toast.LENGTH_SHORT).show()
mContext.startActivity(intent)
}
holder.downloadBtn.setOnClickListener {
abstractList.get(position).abstract?.let { it1 -> click.onItemClick(it1) }
}
}
override fun getItemCount(): Int {
return abstractList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.findViewById(R.id.abstractImageView)
val downloadBtn: Button = itemView.findViewById(R.id.abstractDownloadBtn)
}
companion object
}
You have 3 parameters for the class AbstractAdapter
class AbstractAdapter(private val mContext: Context, private val abstractList: ArrayList<Abstract>, private val click: OnItemClickListenerAbstract )
but you are instantiating the object with only two parameters
AbstractAdapter(requireActivity(),it)
It's expecting the third parameter for the clickListener
AbstractAdapter(requireActivity(),it,this)
(send the Fragment as the third param)
I'm facing a problem with my recycler view, I'd wanted to refresh it every second, for that I use a timer which creates new request, but I think that my recyclerview is destroyed and directly recreated, when I'm scrolling it keep always returning to the top every second. Here is my fragment, I heard about layoutmanager but don't really know how to use it, is it linked?
class DlFragment (private val context: MainActivity): Fragment(){
private var myTimer: Timer? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_dl,container, false)
val dlRecyclerView = view?.findViewById<RecyclerView>(R.id.dl_list_recycle_view)
myTimer = Timer()
myTimer!!.schedule(object : TimerTask() {
override fun run() {
getDlList(dlRecyclerView)
}
}, 0, 1000)
val comfirmButton= view.findViewById<Button>(R.id.input_post_dl_button)
comfirmButton.setOnClickListener { postDl(view) }
return view
}
private fun getDlList(dlRecyclerView: RecyclerView?) {
GlobalScope.launch(Dispatchers.Main) {
try {
val response = ApiClientQnap.apiServiceQnap.getQuery(0,20,"all","all",ApiClientQnap.sid)
if (response.isSuccessful && response.body() != null) {
val content = response.body()
if (content != null) {
//println(content)
//val dlRecyclerView = view?.findViewById<RecyclerView>(R.id.dl_list_recycle_view)
dlRecyclerView?.adapter = DlAdapter(context,content.data)
}
} else { println("Error Occurred: ${response.message()}") }
} catch (e: Exception) {println("Error Occurred: ${e.message}") }
}
}
private fun postDl(view: View){
val url_Dl = view.findViewById<EditText>(R.id.input_post_dl_text)
GlobalScope.launch(Dispatchers.Main) {
try {
val response = ApiClientQnap.apiServiceQnap.postDL("Films","Films",
url_Dl.text.toString(),ApiClientQnap.sid)
if (response.isSuccessful && response.body() != null) {
val content = response.body()
println(response.body())
if (content != null) {
if(content.error == 0) {
Toast.makeText(context, "yeee", Toast.LENGTH_LONG).show()
url_Dl.text.clear()
}
else
Toast.makeText(context, "no", Toast.LENGTH_LONG).show()
}
} else { println("Error Occurred: ${response.message()}") }
} catch (e: Exception) {println("Error Occurred: ${e.message}") }
}
}
Edit: Here's my DlAdapter
class DlAdapter(
val context: MainActivity,
private var dlList: ArrayList<Data>
) : RecyclerView.Adapter<DlAdapter.ViewHolder>() {
class ViewHolder(view : View): RecyclerView.ViewHolder(view){
val dl_title = view.findViewById<TextView>(R.id.dl_title)
val dl_progress = view.findViewById<TextView>(R.id.dl_progress)
val dl_speed = view.findViewById<TextView>(R.id.dl_speed)
val progressBar = view.findViewById<ProgressBar>(R.id.progressBar)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater
.from(parent.context)
.inflate(R.layout.fragment_dl_list,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentDl = dlList[position]
holder.dl_title.text = currentDl.source_name
holder.progressBar.progress = (currentDl.progress!!)
when (currentDl.state) {
5 -> holder.dl_progress.text = ("Terminé")
2 -> holder.dl_progress.text = ("Arrété")
4 -> holder.dl_progress.text = ("Echec")
1 -> holder.dl_progress.text = (currentDl.progress.toString() + " % En pause")
104 -> {
holder.dl_progress.text = (currentDl.progress.toString() + " %")
var toFloat = currentDl.down_rate?.toFloat()
toFloat = toFloat?.div(1000000)
holder.dl_speed.text = (toFloat.toString()+" Mo")
}
}
}
override fun getItemCount(): Int = dlList.size
fun updateData(newData: ArrayList<Data>) {
dlList.clear()
dlList.addAll(newData)
notifyDataSetChanged()
}
}
As #hardartcore suggested, you can try to convert the RecyclerView.Adapter to a ListAdapter and use a DiffUtil.ItemCallback class.
Try to convert your adapter like this:
class DlAdapter : ListAdapter<Data, DlAdapter.ViewHolder>(DlDiffCallback()) {
class ViewHolder(view : View): RecyclerView.ViewHolder(view){
val dl_title = view.findViewById<TextView>(R.id.dl_title)
val dl_progress = view.findViewById<TextView>(R.id.dl_progress)
val dl_speed = view.findViewById<TextView>(R.id.dl_speed)
val progressBar = view.findViewById<ProgressBar>(R.id.progressBar)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater
.from(parent.context)
.inflate(R.layout.fragment_dl_list,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// Use the getItem method to retrieve a specific item
val currentDl = getItem(position)
holder.dl_title.text = currentDl.source_name
holder.progressBar.progress = (currentDl.progress!!)
when (currentDl.state) {
5 -> holder.dl_progress.text = ("Terminé")
2 -> holder.dl_progress.text = ("Arrété")
4 -> holder.dl_progress.text = ("Echec")
1 -> holder.dl_progress.text = (currentDl.progress.toString() + " % En pause")
104 -> {
holder.dl_progress.text = (currentDl.progress.toString() + " %")
var toFloat = currentDl.down_rate?.toFloat()
toFloat = toFloat?.div(1000000)
holder.dl_speed.text = (toFloat.toString()+" Mo")
}
}
}
}
class DlDiffCallback : DiffUtil.ItemCallback<Data>() {
// Change this method comparisons based on your equality conditions
override fun areItemsTheSame(oldItem: DataItem, newItem: DataItem): Boolean = oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: DataItem, newItem: DataItem): Boolean = oldItem == newItem
}
You can then update your RecyclerView adapter by using the submitList method:
val adapter = DlAdapter()
adapter.submitList(content.data)
How can I check if a user has uploaded photos to my image views in Kotlin android, so that I can allow them to move to the next fragment. I want to include this in my on Apply function where I have including the other checks for is Null Or Empty for the text views. I have 4 image views I want the user to upload photos to. I want to check this in on apply function.
private lateinit var userId: String
private lateinit var userDatabase: DatabaseReference
private var callback: TinderCallback?=null
fun setCallback(callback: TinderCallback) {
this.callback = callback
userId= callback.onGetUserId()
userDatabase= callback.getUserDatabase().child(userId)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_profile, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
progressLayout.setOnTouchListener { view, event -> true }
populateInfo()
photoIV.setOnClickListener{callback?.startActivityForPhoto()}
image1IV.setOnClickListener{callback?.startActivityForPhoto1()}
image2IV.setOnClickListener{callback?.startActivityForPhoto2()}
image3IV.setOnClickListener{callback?.startActivityForPhoto3()}
applyButton.setOnClickListener { onApply()}
signoutButton.setOnClickListener{callback?.onSignOut()}
}
fun populateInfo(){
progressLayout.visibility = View.VISIBLE
userDatabase.addListenerForSingleValueEvent(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if(isAdded){
val user = snapshot.getValue(User::class.java)
nameET.setText(user?.name, TextView.BufferType.EDITABLE)
emailET.setText(user?.email, TextView.BufferType.EDITABLE)
ageET.setText(user?.age, TextView.BufferType.EDITABLE)
occupationET.setText(user?.occupation, TextView.BufferType.EDITABLE)
countryET.setText(user?.country, TextView.BufferType.EDITABLE)
cityET.setText(user?.city, TextView.BufferType.EDITABLE)
interestsET.setText(user?.interests, TextView.BufferType.EDITABLE)
if(user?.gender == GENDER_MALE) {
radioMan1.isChecked = true
}
if (user?.gender == GENDER_FEMALE){
radioWoman1.isChecked = true
}
if(user?.preferredGender == GENDER_MALE) {
radioMan2.isChecked = true
}
if(user?.preferredGender == GENDER_FEMALE){
radioWoman2.isChecked = true
}
if (!user?.imageUrl.isNullOrEmpty()) {
populateImage(user?.imageUrl!!)
}
if (!user?.image1url.isNullOrEmpty()) {
populateImage1(user?.image1url!!)
}
if (!user?.image2url.isNullOrEmpty()) {
populateImage2(user?.image2url!!)
}
if (!user?.image3url.isNullOrEmpty()) {
populateImage3(user?.image3url!!)
}
progressLayout.visibility = View.GONE
}
}
override fun onCancelled(error: DatabaseError) {
progressLayout.visibility = View.GONE
}
})
}
private fun onApply(){
if(nameET.text.toString().isNullOrEmpty() ||
ageET.text.toString().isNullOrEmpty() ||
emailET.text.toString().isNullOrEmpty() ||
radioGroup1.checkedRadioButtonId == -1 ||
radioGroup2.checkedRadioButtonId == -1) {
Toast.makeText(context, getString(R.string.error_profile_incomplete), Toast.LENGTH_SHORT).show()
} else {
val name = nameET.text.toString()
val age = ageET.text.toString()
val email = emailET.text.toString()
val occupation = occupationET.text.toString()
val country = countryET.text.toString()
val city = cityET.text.toString()
val interests = interestsET.text.toString()
val gender =
if(radioMan1.isChecked) GENDER_MALE
else GENDER_FEMALE
val preferredGender =
if(radioMan2.isChecked) GENDER_MALE
else GENDER_FEMALE
userDatabase.child(DATA_NAME).setValue(name)
userDatabase.child(DATA_AGE).setValue(age)
userDatabase.child(DATA_EMAIL).setValue(email)
userDatabase.child(DATA_COUNTRY).setValue(country)
userDatabase.child(DATA_CITY).setValue(city)
userDatabase.child(DATA_OCCUPATION).setValue(occupation)
userDatabase.child(DATA_INTERESTS).setValue(interests)
userDatabase.child(DATA_GENDER).setValue(gender)
userDatabase.child(DATA_GENDER_PREFERRENCE).setValue(preferredGender)
callback?.profileComplete()
}
}
fun updateImageUri(Uri:String){
userDatabase.child(DATA_IMAGE_URL).setValue(Uri)
populateImage(Uri)
}
fun updateImageUri1(Uri:String){
userDatabase.child(DATA_PHOTO1_URL).setValue(Uri)
populateImage1(Uri)
}
fun populateImage(Uri: String) {
Glide.with(this)
.load(Uri)
.into(photoIV)
}
fun populateImage1(Uri: String){
Glide.with(this)
.load(Uri)
.into(image1IV)
}
fun updateImageUri2(Uri:String){
userDatabase.child(DATA_PHOTO2_URL).setValue(Uri)
populateImage2(Uri)
}
fun populateImage2(Uri: String) {
Glide.with(this)
.load(Uri)
.into(image2IV)
}
fun updateImageUri3(Uri:String){
userDatabase.child(DATA_PHOTO3_URL).setValue(Uri)
populateImage3(Uri)
}
fun populateImage3(Uri: String) {
Glide.with(this)
.load(Uri)
.into(image3IV)
}```
If those populateImage functions are where you add the images to the ImageViews, you could set an imageAdded var in there, one for each ImageView. Then your code can check if all 4 are set to true