Passing data from one table to the other on PARSE - pointers

everyone been trying to get data from one table using pointers, example User table and songs table, when you tap on a user it displays list of songs in the songs table specific to that users object id i tried using this method but i get an error query.wherekey("" equalTo: (PFUser.current()?.objectId!)!)
HERE IS MY CODE
var users = [""]
var userIDs = [""]
var isFollowing = ["" : true]
override func viewDidLoad() {
super.viewDidLoad()
//load user query
let query = PFUser.query ()
query?.findObjectsInBackground(block: { (objects, error) in
if error != nil {
print(error!)
} else if let users = objects {
for objects in users {
if let user = objects as? PFUser {
self.users.append(user.username!)
self.userIDs.append(user.objectId!)
let query = PFQuery(className: "Followers")
query.whereKey("Follower", equalTo: (PFUser.current()?.objectId!)!)
query.whereKey("Following", equalTo: user.objectId!)
query.findObjectsInBackground(block: { (objects, error) in
if let objects = objects {
if objects.count > 0 {
self.isFollowing[user.objectId!] = true
} else {
self.isFollowing[user.objectId!] = false
}
if self.isFollowing.count == self.users.count {
self.tableView.reloadData()
}
}
})
}
}
}
})
Thank You All
**HERE IS MY CODE FOR THE FIRST VIEW WHERE I AM ABLE TO GET ALL USERS AND SEGUE TO ANOTHER TABLE VIEW CONTROLLER**
//
// users.swift
//
//
// Created by Nawir on 1/17/17.
// Copyright © 2017 Nawir. All rights reserved.
//
import Foundation
import Parse
class artistsviewcontroller: UITableViewController {
var users = [""]
var userIDs = [""]
override func viewDidLoad() {
super.viewDidLoad()
//updating users array
let query = PFUser.query ()
query?.findObjectsInBackground(block: { (objects, error) in
if error != nil {
print(error!)
} else if let users = objects {
for objects in users {
if let user = objects as? PFUser {
self.users.append(user.username!)
self.userIDs.append(user.objectId!)
}
}
}
self.tableView.reloadData()
})
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let Usercell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! mTableViewCell
Usercell.textLabel!.text = users[indexPath.row]
return Usercell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// print("rowtapped: \(indexPath.row)")
let ItemlistTableViewController = self.storyboard?.instantiateViewController(withIdentifier: "itemviewscont") as! itemviewscont
self.navigationController?.pushViewController(ItemlistTableViewController, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
HERE IS MY SECOND TABLEVIEWCONTROLLER
// itemviews.swift
//
//
// Created by Nawir on 1/17/17.
// Copyright © 2017 Nawir. All rights reserved.
//
import Foundation
import Parse
class itemviewscont: UITableViewController {
var users = [String: String] ()
var itemname = [String] ()
override func viewDidLoad() {
super.viewDidLoad()
//query to get all user data from parse
let query = PFUser.query()
query?.findObjectsInBackground { (objects, error) in
if let users = objects {
self.users.removeAll()
for object in users {
if let user = object as? PFUser {
// self.users = [user.objectId!]
self.users[user.objectId!] = user.username!
}
}
}
//query to make connection
let getfollow = PFQuery(className: "Mkitems")
getfollow.whereKey("user", equalTo: PFUser.current()!)
getfollow.findObjectsInBackground(block: { (objects, error) in
if let followers = objects {
for object in followers {
if let follower = object as? PFObject {
let mainuser = follower["User"]
let query = PFQuery(className: "Music")
query.whereKey("fuser", equalTo: mainuser!)
query.findObjectsInBackground(block: { (objects,error) in
if let nitems = objects {
for object in nitems {
if let nitem = object as? PFObject {
self.musicname.append(nitem["name_title"] as! String)
self.tableView.reloadData()
}
}
}
})
}
}
}
})
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemname.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mscell", for: indexPath)
cell.textLabel?.text = itemname[indexPath.row]
return cell
}
//dont pass this line its the end!
}
THANK YOU ALL

If you searching for current user object (assuming Follower is a pointer ) then use
query.whereKey("Follower", equalTo: PFUser.current()!)
and not :
query.whereKey("Follower", equalTo: (PFUser.current()?.objectId!)!)

Related

SwiftUI: Updating Firestore from DetailView

I am working on incorporating a Firestore repository into a SwiftUI 2 app. The list view loads appropriately, and refreshes automatically when the data in the Firestore collection is changed. A NavigationLink loads the appropriate DetailView correctly. A button on the DetailView is set to change data within the relevant document, and works correctly, but the DetailView page does not refresh with the correct data (it appears correctly when exiting to the list view and returning); likewise the DetailView will not respond to changes to the collection made elsewhere.
I have attempted to use various configurations of ObservedObject and State, but have been unable to get the result intended.
Any help would be appreciated. Snipped Code listed below shows the flow, and uses the status field as an example.
CustomerRepository
class CustomerRepository: ObservableObject {
private let path: String = "customers"
private let store = Firestore.firestore()
#Published var customers: [Customer] = []
private var cancellables: Set<AnyCancellable> = []
init() {
store.collection(path)
.addSnapshotListener { querySnapshot, error in
if let error = error {
print("Error getting customers \(error.localizedDescription)")
return
}
self.customers = querySnapshot?.documents.compactMap { document in
try? document.data(as: Customer.self)
} ?? []
}
}
func update(_ customer: Customer) {
guard let customerID = customer.id else { return }
do {
try store.collection(path).document(customerID).setData(from: customer)
} catch {
fatalError("Unable to update record: \(error.localizedDescription)")
}
}
}
CustomerListViewModel
class CustomerListViewModel: ObservableObject {
#Published var customerViewModels: [CustomerViewModel] = []
private var cancellables: Set<AnyCancellable> = []
#Published var customerRepository = CustomerRepository()
init() {
customerRepository.$customers.map { customers in
customers.map(CustomerViewModel.init)
}
.assign(to: \.customerViewModels, on: self)
.store(in: &cancellables)
}
}
CustomerViewModel
class CustomerViewModel: ObservableObject, Identifiable {
private let customerRepository = CustomerRepository()
#Published var customer: Customer
private var cancellables: Set<AnyCancellable> = []
var id = ""
init(customer: Customer) {
self.customer = customer
$customer
.compactMap { $0.id }
.assign(to: \.id, on: self)
.store(in: &cancellables)
}
func update(customer: Customer) {
customerRepository.update(customer)
}
}
CustomerListView
struct CustomerListView: View {
#ObservedObject var customerListViewModel = CustomerListViewModel()
var body: some View {
NavigationView {
List {
ForEach(customerListViewModel.customerViewModels) { customerViewModel in
NavigationLink(
destination: CustomerDetailView(customerViewModel: customerViewModel)) {
CustomerCell(customerViewModel: customerViewModel)
}
}
}
}
}
}
CustomerDetailView
struct CustomerDetailView: View {
var customerViewModel: CustomerViewModel
var body: some View {
VStack {
Text(customerViewModel.customer.status.description)
}.onTapGesture {
nextTask()
}
}
private func nextTask() {
switch customerViewModel.customer.status {
case .dispatched:
customerViewModel.customer.status = .accepted
...
default:
return
}
update(customer: customerViewModel.customer)
}
func update(customer: Customer) {
customerViewModel.update(customer: customer)
}
}
After some reconfiguring, and the help of this example:
https://peterfriese.dev/swiftui-firebase-update-data/
I was able to solve my issue. Below is a breakdown of the revised code in case it will help others....
CustomerViewModel
class CustomerViewModel: ObservableObject, Identifiable {
#Published var customer: Customer
#Published var modified = false
private var cancellables: Set<AnyCancellable> = []
init(customer: Customer = Customer(status: .new)) {
self.customer = customer
self.$customer
.dropFirst()
.sing { [weak self] customer in
self?.modified = true
}
.store(in: &cancellables)
}
func handleDoneTapped() {
self.updateOrAddCustomer()
}
}
CustomerListView
// Snip to Navigation Link
NavigationLink(
destination: CustomerDetailView(customerViewModel: CustomerViewModel(customer: customerViewModel.customer))) {
CustomerCell(customerViewModel: customerViewModel)
}
CustomerDetailView
struct CustomerDetailView: View {
#ObservedObject var customerViewModel = CustomerViewModel()
var body: some View {
VStack {
Text(customerViewModel.customer.status.description)
}.onTapGesture {
nextTask()
}
}
private func nextTask() {
switch customerViewModel.customer.status {
case .dispatched:
customerViewModel.customer.status = .accepted
...
default:
return
}
update(customer: customerViewModel.customer)
}
func update(customer: Customer) {
customerViewModel.handleDoneTapped()
}
}
Here you need to put the parameters for which values being updated and want the UI to update accordingly:
class CustomerViewModel: ObservableObject, Identifiable {
private let customerRepository = CustomerRepository()
#Published var customer: Customer
private var cancellables: Set<AnyCancellable> = []
var id = ""
var status: StatusEnum
init(customer: Customer) {
self.customer = customer
self.status = customer.status
$customer
.compactMap { $0.status }
.assign(to: \.status, on: self)
.store(in: &cancellables)
$customer
.compactMap { $0.id }
.assign(to: \.id, on: self)
.store(in: &cancellables)
}
func update(customer: Customer) {
customerRepository.update(customer)
}
}
Then, use this new status variable in the view: Text(customerViewModel.status.description).

Kotlin searchView does not reload Firebase array

I have one activity with 2 recyclerViews, both recyclers are used with Firebase. One of the recyclers displays the results of a query, the other recycler has a listener that updates every time there is an update in Firebase. I added a searchView to filter the results from Firebase. The issue I'm having is when I'm trying to search the results from the Firebase query, when I start typing I see results but when I click the X to stop searching, the adapter does not reload the array and i don't see the list of items unless I reload the activity. I'm not sure what I'm missing here. Any help/suggestion is greatly appreciated. Here is my code:
Adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.eduardoz.ezmdapp.Model.Charges
import com.eduardoz.ezmdapp.R
class ChargesAdapter (private var charges: ArrayList<Charges>
, private var chargesAll: ArrayList<Charges>
, private val itemClick: (Charges) -> Unit)
: RecyclerView.Adapter<ChargesAdapter.ViewHolder>()
, Filterable {
inner class ViewHolder(itemView: View, val itemClick: (Charges) -> Unit) :
RecyclerView.ViewHolder(itemView) {
private val chargeCode = itemView.findViewById<TextView>(R.id.chargeCodeTxt)
private val chargeDescription = itemView.findViewById<TextView>(R.id.chargeDescriptionTxt)
fun bindCharges(charges: Charges) {
chargeCode?.text = charges.chargeCode
chargeDescription?.text = charges.chargeDescription
itemView.setOnClickListener { itemClick(charges) }
}
}
init {
this.charges = charges
chargesAll = java.util.ArrayList(charges)
}
override fun getItemCount(): Int {
return charges.count()
}
override fun onBindViewHolder(holder: ChargesAdapter.ViewHolder, position: Int) {
holder.bindCharges(charges[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChargesAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.charges_list, parent, false)
return ViewHolder(view, itemClick)
}
override fun getFilter(): Filter {
return searchFilter
}
private val searchFilter: Filter = object: Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList: ArrayList<Charges> = ArrayList()
if (constraint!!.isEmpty()) {
filteredList.addAll(chargesAll)
} else {
for(item in chargesAll) {
if
(item.chargeDescription.toLowerCase().contains(constraint.toString().toLowerCase())) {
filteredList.add(item)
}
}
}
val searchResults = FilterResults()
searchResults.values = filteredList
return searchResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
charges.clear()
charges.addAll(results!!.values as Collection<Charges>)
notifyDataSetChanged()
}
}
}
Activity
descriptionSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
if (newText.isNotEmpty()) {
searchViewBar(newText)
} else {
if (newText.isEmpty()) { //I ADDED THIS TO RELOAD THE ADAPTER
charges.clear()
chargeList()
}
}
return false
}
})
private fun searchViewBar(newText: String) {
chargesListener = chargesCollectionRef
.whereGreaterThanOrEqualTo(CHARGE_DESCRIPTION, newText)
.whereLessThanOrEqualTo(CHARGE_DESCRIPTION, newText+"z")
.addSnapshotListener(this) { snapshot, exception ->
if (exception != null) {
println("error")
}
if (snapshot != null) {
charges.clear()
parseData(snapshot)
}
}
}
fun parseData(snapshot: QuerySnapshot) {
for (document in snapshot.documents) {
val data = document.data
val chargeCode = data!![CHARGE_CODE] as String
val chargeDescription = data[CHARGE_DESCRIPTION] as String
val chargeSpecialty = data[CHARGE_SPECIALTY] as String
val newChargeList = Charges(chargeCode, chargeDescription, chargeSpecialty)
charges.add(newChargeList)
}
chargesFromAdapter.notifyDataSetChanged()
}

Cannot fetch messages from another user FirebaseDatabase

This is a simple chat messaging app, using Firebase Realtime Database and the Authentication. I have successfully created the database, but I cannot fetch the message from one user to another. Because, when I send the message/click the send button, it creates different nodes, I think its a string node with quotation mark in the name. The node structure I created is user-messages --> fromId(current user uid) --> toUid(to whom the messages are sent).
To make more clear explanation, this is the screenshot of what happened.
I think the problem is, it creates a different nodes with the "uid", which means string. So the database has two nodes, one with the "...", and the other the normal one. For some info, I use some library such as Picasso image load, groupie, and parcelize.
This is the source code for the ChatLogActivity
import...
class ChatLogActivity : AppCompatActivity() {
companion object {
val TAG = "ChatLog"
}
val adapter = GroupAdapter<ViewHolder>()
var toUser: User? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_log)
recyclerview_chat_log.adapter = adapter
toUser = intent.getParcelableExtra(NewMessageActivity.USER_KEY)
titleChatLog.text = toUser?.nama
listenForMessages()
arrowBack.setOnClickListener {
finish()
}
send_button_chat_log.setOnClickListener {
Log.d(TAG, "Attempt to send message.....")
performSendMessage()
}
}
private fun listenForMessages() {
val fromId = FirebaseAuth.getInstance().uid
val toId = toUser?.uid
val ref = FirebaseDatabase.getInstance().getReference("/user-messages/$fromId/$toId")
ref.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
val chatMessage = p0.getValue(ChatMessage::class.java)
if (chatMessage != null) {
Log.d(TAG, chatMessage.text)
if (chatMessage.fromId == FirebaseAuth.getInstance().uid) {
val currentUser = LatestMessageActivity.currentUser?: return
adapter.add(ChatFromItem(chatMessage.text, currentUser))
} else {
adapter.add(ChatToItem(chatMessage.text, toUser!!))
}
}
}
override fun onCancelled(p0: DatabaseError) {
}
override fun onChildChanged(p0: DataSnapshot, p1: String?) {
}
override fun onChildMoved(p0: DataSnapshot, p1: String?) {
}
override fun onChildRemoved(p0: DataSnapshot) {
}
})
}
private fun performSendMessage() {
val text = edittext_chat_log.text.toString()
val fromId = FirebaseAuth.getInstance().uid
val user = intent.getParcelableExtra<User>(NewMessageActivity.USER_KEY)
val toId = user.uid
val ref = FirebaseDatabase.getInstance().getReference("/user-messages/$fromId/$toId").push()
val toRef = FirebaseDatabase.getInstance().getReference("/user-messages/$toId/$fromId ").push()
if (fromId == null) return
val chatMessage = ChatMessage(ref.key!!, text, fromId, toId, System.currentTimeMillis() / 1000)
ref.setValue(chatMessage)
.addOnSuccessListener {
Log.d(TAG, "Save our chat message: ${ref.key}")
edittext_chat_log.text.clear()
recyclerview_chat_log.scrollToPosition(adapter.itemCount - 1)
}
toRef.setValue(chatMessage)
}
}
class ChatFromItem(val text: String, val user: User) : Item<ViewHolder>() {
override fun getLayout(): Int {
return R.layout.chat_from_row
}
override fun bind(viewHolder: ViewHolder, position: Int) {
val uri = user.profileImageUrl
val targetImageView = viewHolder.itemView.imageViewFrom
Picasso.get().load(uri).into(targetImageView)
viewHolder.itemView.textViewFrom.text = text
}
}
class ChatToItem(val text: String, val user: User) : Item<ViewHolder>() {
override fun getLayout(): Int {
return R.layout.chat_to_row
}
override fun bind(viewHolder: ViewHolder, position: Int) {
val uri = user.profileImageUrl
val targetImageView = viewHolder.itemView.imageViewTo
Picasso.get().load(uri).into(targetImageView)
viewHolder.itemView.textViewTo.text = text
}
}
And this is the ChatMessage, class that store the messages.
class ChatMessage(val id:String, val text: String, val fromId: String, val toId: String, val timeStamp: Long) {
constructor(): this("", "", "", "", -1)
}
I'm very glad if anyone can help this problem. Thank you

How to find the visible pushViewController from the navigation controller?

My app layout consists of a tabbar, from each tab there is a navbar to which is attaches a UITableViewController.
When I didSelect a row, I push a view controller with becomes nicely embedded in the navigation bar.
I would like to find this latter view controller programmatically.
Here is how I push my visible view controller (streamlined version):
#objc
func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
let vc = WebPageViewController()
navigationController?.pushViewController(vc, animated: true)
}
I did not managed to find a way. I am using this extension:
public extension UIWindow {
public var visibleViewController: UIViewController? {
return UIWindow.getVisibleViewControllerFrom(rootViewController)
}
public static func getVisibleViewControllerFrom(_ vc: UIViewController?) -> UIViewController? {
if let nc = vc as? UINavigationController {
return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
} else if let tc = vc as? UITabBarController {
return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
} else {
if let pvc = vc?.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(pvc)
}
else if let pushed = vc?.childViewControllers.last {
return pushed
}
else {
return vc
}
}
}
}

access an array from another class

what i want to do here is when i access the first album by pressing on the picture i should get pictures from firebase for that specific album but i have a problem with that and here is my code.
class albumsVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource{
#IBOutlet weak var collectionView: UICollectionView!
var posts = [Post]()
static var imageCache: NSCache<NSString, UIImage> = NSCache()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
DataService.ds.REF_POSTS3.observe(.value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print ("SNAP: \(snap)")
if let postDict = snap.value as? Dictionary<String, AnyObject>{
let key = snap.key
let post = Post(postKey: key , postData: postDict)
self.posts.append(post)
}
}
}
self.collectionView.reloadData()
})
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let post = posts[indexPath.row]
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)as? collectionViewCellAlbums {
if let img = albumsVC.imageCache.object(forKey: post.mainImg as NSString) {
cell.configureCell(post: post, img: img)
return cell
}else {
cell.configureCell(post: post)
return cell
}
}
else {
return collectionViewCellAlbums()
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "showAlbum", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
/**
if segue.identifier == "showAlbum"
{
let indexPaths = self.collectionView!.indexPathsForSelectedItems!
let indexPath = indexPaths[0] as IndexPath
let vc = segue.destination as! newViewController
let post = posts[indexPath.row]
if let img = CollectionVC.imageCache.object(forKey: post.imageUrl as NSString) {
vc.image = img
}
}
*/
}
}
I don't know how to access the array in the second class as shown in the picture for this function override func prepare(for segue
the class for the second array is exactly the same as the first one except the newViewController.swift
class newViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var image = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = self.image
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
In class collectionVC you should have variable :
imageList
and in albumVC at:
prepare(for segue: UIStoryboardSegue, sender: Any?)
after
let vc = segue.destination as! newViewController
set :
vc.imageList = self.post.getAllImageOfPost()
In such cases using a singleton class solves the problem. In Singleton pattern you create instance just-in-time. This means when you set an array for example, this array will be allocated in memory until the program finishes running.
Refer to this link for Singleton implementation:
http://www.galloway.me.uk/tutorials/singleton-classes/

Resources