I am currently working on an app with a friendship feature similar to Facebook(a request is sent and if accepted they both become friends). The sending user can select multiple users from a list and send them all invites at once. When this happens, the receiving users are added to a relation called "pendingRelation" for the sending user. However, I would also like the sending user to be added as a "pendingRelation" for all the receiving users as soon as the request is sent. I have messed around and haven't been able to find a good solution for this. The code to add the selected users as "pendingRelation" is simple.
private boolean sendFriendRequest() {
//Cycles through list of selected friends and adds as "Pending"
for (int i = 0; i < mPendingFriends.size(); i++) { //Cycles through list
mPendingRelation.add(mPendingFriends.get(i));
}
mCurrentUser.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e != null) {
Log.e(TAG, e.getMessage());
}
}
});
If anyone can help me add the sender as a "pendingRelation" to the reciever as well to create this two-way relationship that would be great. Thanks!
I've actually thought about making a follow system with Parse which is quite similiar to your problem. Have you thought about making a new ParseObject instead of relation? Then you could add something like ParseUser pendingUser, ParseUser requestUser, boolean isAccepted.
Anywho if you can't find help from here you can try post it to parse.com questions.
I am trying to figure out the same thing for my app (although I am using javascript so I can't give you working code.. sorry.).
To expand on Torsten's answer. One solution would be to create a table(class) in Parse with the fields "pendingFriendRequest" "associatedUserID_requestingUser" "associatedUserID_receivingUser" and "accepted (boolean)".
SIDE NOTE: You could also add a matching function this way by querying
this table(class) and determining whether there are two
"pendingFriendRequests" from each individual user for the other user.
Then, you can present the user the results of querying this table and an option to "accept" (you can also present an option to ignore/delete and just drop the row).
Once the user clicks "accept" link that to a function which then creates the user relation.
In javascript it looks something like this:
likeAUser: function (userId) {
var currentUser = $rootScope.loggedInUser;
var User = Parse.Object.extend("User");
var user = new User();
user.id = userId;
var likes = currentUser.relation("Likes");
//console.log(likes);
likes.add(user);
return currentUser.save();
},
and within the function you are creating the new relation you would then drop(delete) the row from the "pendingRequests" table.
I hope this helps,
I have been racking my brain on how to do this and this is the best way I can figure out pending Parse making it easier to interact with relations elements inside their user class. Sorry I don't know the android version to help more.
Related
I'm relatively new to Firebase Database, having used MySQL up until now. I know that there's no 'associated' data in Firebase as such, but I think I'm still trying to create it, because that's how my mind works! So, it may be that the problem I'm having is because my data is formatted badly - I'd appreciate any pointers.
In my app (using Android Studio), each user can have a number of Boxes. Each Box uses a single colour Palette (it can be the default one, or a user-defined one). A Palette consists of a number of Colours.
Currently, my data is like this:
Boxes
BoxKey1
name: Test Box
paletteKey: paletteKey1
belongsTo: userKey1
BoxKey2
... etc ...
Colours
ColourKey1
name: Red
hexCode: ff0000
ColourKey2
name: Blue
... etc ...
Palettes
PaletteKey1
name: default
colours
ColourKey1: true
ColourKey7: true
... etc ...
PaletteKey2
... etc ...
Users
UserKey1
name: Joe Bloggs
boxes
BoxKey1: true
BoxKey5: true
... etc ...
So, I can retrieve a list of the User's Boxes easily enough, and list all the names. If the User clicks on a name, then the Box with that name is retrieved and displayed. I also need to display the Palette used (the name and the Colours it contains).
In the Activity, I retrieve the Box as follows:
mBox.setKey(boxKey);
mBox.initialiseBox(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mBox = dataSnapshot.getValue(Box.class);
boxName.setText(mBox.getName()); // Show Box name
// AT THIS POINT I HAVE THE BOX DETAILS, BUT I NEED THE PALETTE DETAILS TOO
}
});
In the Box class, initialiseBox looks like this:
public void initialiseBox(ValueEventListener listener) {
if(this.key == null) return;
DatabaseReference mBoxReference = FirebaseDatabase.getInstance().getReference()
.child("boxes").child(this.key);
mBoxReference.addListenerForSingleValueEvent(listener);
}
That's working fine, but at this point I've only retrieved the Palette key from the database along with the other Box data. How do I then get the actual Palette, with all its Colours, so I can show those as well?
I've been trying to do a kind of 'nested listener' like this in the Main Activity:
mBox.initialiseBox(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Same as before
mBox = dataSnapshot.getValue(Box.class);
boxName.setText(mBox.getName()); // Show Box name
// Now add a new listener for the Palette
mPalette.setKey(mBox.getPaletteKey());
mPalette.initialisePalette(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mPalette = dataSnapshot.getValue(Palette.class);
paletteName.setText(mPalette.getName());
}
});
}
});
but it seems very unwieldy, and I can't quite get it to work (the Palette isn't getting populated, so at the paletteName.setText bit I'm getting an error).
Is this the correct approach to be taking? If not, what should I be doing? And if it's the right idea, can anyone see where I'm going wrong?
Related data in Firebase (and many other NoSQL databases) are almost as common as in SQL databases. The main differences are:
In Firebase the relation is not managed for you by the DBMS. This means that you need to write your own code (and possibly server-side security rules) to ensure ensure the relationship stay in-tact.
You often will duplicate some of the data in Firebase, which reduces the need for lookups. But this comes at the cost of needing to duplicate data during a write, and you'll need to consider strategies for keeping the duplicated data up to date.
What you're doing is called a client-side join and is indeed one valid way to get data from different top-level nodes into your app.
Whether it is the best approach to do this with a nested listener depends on the data and use-case. Things to consider here:
If the target list is short, you might simply want to preload the entire list and remove the need for nested joins.
What do you need from the joined item? If it's just a single property (e.g. the name of the palette), consider if it's worth it to duplicate that property under the source to remove the need for a nested join.
Nesting the code is going to rapidly become unreadable. Pull out the listener into a utility-class, and invoke it with a simpler interface.
i.e. you'll probably want to centralize the error handling, which you can perfectly do in the helper class. This leaves you with a single callback methods, which can be lambdafied in Java 8 - making it much easier to read.
I often recommend that you model the screens of your app in Firebase. So if your app has a list of user names, model a list of user names in your database. Right now you also nest the box IDs under that list, which means you'll end up loading the box IDs for all users, just to show their names.
I highly recommend reading NoSQL data modeling and watching Firebase for SQL developers.
My app has a registration page wherein only those users who enter the right passcode are allowed to register. This passcode is stored inside firebase database inside a child called "Councilpasscodes". After entering the passcode the user should press the submit button, after comparing the two passcodes the user should be allowed to register if the passcodes are same.
This is the code for comparing the edit text string and the child value:
mpasscode=FirebaseDatabase.getInstance().getReference().child("Councilpasscodes");
submit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final String passcode1=editText.getText().toString().trim();
mpasscode.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String passc= (String) dataSnapshot.child("passcode").getValue();
if (passcode1.equals(passc)){
//do something
}else if(!passcode1.equals(passc)){
//do something
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
The problem is after pressing the submit button it is not really checking the two strings i.e. if (passcode1.equals(passc)) and if(!passcode1.equals(passc)) is not being called even after entering the right passcode. I am not sure what is wrong with the code as I am new to app development.Any help is appreciated.Thank you.
EDIT:
I think it is not executing addListenerForSingleValue at all. I am not sure why is this happening.
Alright mate. The reason why your ValueEventListener's onDataChange isn't getting called is that you're not authorized to edit or read your database. This happens because the default security settings for a firebase real-time database disallows any read or write without an authenticated user. To prove this observe your warning logs inside Android Monitor. (The blue ones.) It will show a caught exception mentioning permission denied from Firebase as soon as you click submit.
Read about Firebase security from here.
For a quick solution what you can do is, you can allow read or writes without any sort of authentication. To do that edit your Realtime database rules and add this instead of what's written there.
{
"rules": {
".read": true,
".write": true
}
}
I'm also gonna attach a screenshot for reference. You'll find this screen inside the firebase console. Inside the console click on your project and then on Database to the left as shown.
.
This is a security lapse none the less, so to set up proper Authentication from your app, follow these steps.
https://firebase.google.com/docs/auth/android/start/
Also, add a toString() to dataSnapshot.child("passcode").getValue() like this to convert it to String as it's probably long.
String passc = dataSnapshot.child("passcode").getValue().toString();
Also, just to be sure. Add this line if you haven't already
FirebaseApp.initializeApp(this);
above your
mpasscode=FirebaseDatabase.getInstance().getReference().child("Councilpasscodes");
Hope it helps!
Have you tried using .compareTo() method?
if (passcode1.compareTo(passc) == 0) { }
I think firebase is returning integer instead. You can put the quote to 1234 and try again or compare as integer.
if you are using only numerics then equalsIgnoreCase would do good or if there is no limit of type of character you use in counsilcode then .match would be good
I'm managing my UI list with RealmRecyclerViewAdapter. I'd like to add a "pending" item to the collection that will display immediately while simultaneously posting the new item to the server. In case of failure, I will remove it from the display. Similar to a chat feature; I display the chat when they hit send, and if for some reason the post fails I can remove it and alert the user.
The problem is that with a regular RecyclerView adapter, I can just add one item to the end of the collection without an id, and remove it as needed. But since RealmRecyclerViewAdapter uses managed RealmResults, I can't add a new item without an id.
Can someone suggest a way to handle the situation I'm describing with RealmRecyclerViewAdapter?
Without knowing what your data model looks like. It is hard to give concrete advice, but it sounds like all your have ID's, so something like this should work:
1) It must be possible to generate ID's offline. The standard solution for that is GUIDs: https://en.wikipedia.org/wiki/Universally_unique_identifier
2) Have a boolean on your model class: "syncedWithServer" or something similar. Then you can render all items not yet synced as "pending".
public class ChatEntry extends RealmObject {
#PrimaryKey
private String id = UUID.randomUUID().toString();
private String entry;
private boolean syncedWithServer;
}
I have a node in Firebase getting continually updated with information from a logfile. The node is lines/ and each child of lines/ is from a post() so it has a unique ID.
When a client first loads, I want to be able to grab the last X number of entries. I expect I'll do this with once(). From then on, however, I want to use an on() with child_added so that I get all new data. However, child_added gets all data stored in the Firebase and, after the initial setup, only want the new stuff.
I see that I can add a limitToLast() on the on(), but, if I say limitToLast(1) and a flood of entries come in, will my app still get all the new entries? Is there some other way to do this?
You need to include a timestamp property and run a query.
// Get the current timestamp
var now = new Date().getTime();
// Create a query that orders by the timestamp
var query = ref.orderByChild('timestamp').startAt(now);
// Listen for the new children added from that point in time
query.on('child_added', function (snap) {
console.log(snap.val()
});
// When you add this new item it will fire off the query above
ref.push({
title: "hello",
timestamp: Firebase.ServerValue.TIMESTAMP
});
The Firebase SDK has methods for ordering, orderByChild() and methods for creating a range startAt(). When you combine the two you can limit what comes back from Firebase.
I think there is a problem in #David East's solution. He is using the local timestamp which may cause problem if the time is not accurate in client device. Here is my suggested solution (iOS Swift):
Using observeSingleEvent to get the complete data set
Then returned it in reversed order by reversed()
Get the last timestamp by for example data[0].timestamp
Using queryStarting for timestamp
self._dbref.queryOrdered(byChild: "timestamp").queryStarting(atValue: timestamp+1)
.observe(.childAdded, with: {
snapshot in
print(snapshot.value)
})
You have the right idea. child_added should be called only for the new nodes. Without source code it's hard to tell why you get all the data in your child_added event.
You can check the chat demo app to see how they load new chat messages. The use case sounds similar.
https://github.com/firebase/firechat/blob/master/src/js/firechat.js#L347
Here's temporary but quick solution:
// define a boolean
var bool = false;
// fetch the last child nodes from firebase database
ref.limitToLast(1).on("child_added", function(snap) {
if (bool) {
// all the existing child nodes are restricted to enter this area
doSomething(snap.val())
} else {
// set the boolean true to doSomething with newly added child nodes
bool = true;
}
});
Disadvantage: It will load all the child nodes.
Advantage: It will not process existing child nodes but just the newly added child nodes.
limitToLast(1) will do the work.
I'm an early and very happy adopter of both Flux and React so much so that, recently, I ported Fluxxor into Android and it's been okay so far.
The issue I am having with it Flux is dealing with data for a Single Item or Details Page. Bear with me below. I will try to be as clear as I can.
The pattern I am using is.
On page load(componentWillMount/componentWillReceiveProps and onStart), I check if the id passed to the page (via url or bundle) matches the id of the item currently in the store and the page if the store is in a processing or success state.
If yes, I do nothing, else, I dispatch an action to load the data for that item.
componentWillMount: function () {
id = this.props.params.path.split("-")[0];
var artistData = this.props.state.artistData;
if(artistData.id != id)
this.getFlux().actions.artistActions.loadArtist(id);
else if (!artistData.artist && !artistData.loading)
this.getFlux().actions.artistActions.loadArtist(id);
this.getFlux().actions.userActions.fetchSuggestions();
}
protected void onStart() {
GenreSongsStore.State state = App.getFlux().getStore(GenreSongsStore.class).getState();
if(mId == state.Genre.getId()) {
if (state.HasMore)
App.getFlux().getActions().Genres.songs(mId, state.Page + 1);
}
else
App.getFlux().getActions().Genres.songs(mId, 1);
super.onStart();
}
In React this is fine since you use a single state on the root. I didn't bother too much until I started working with Android.
Here, I don't use a single state but query the relevant store and it totally smells
If you are not using that page, the data is still held in memory
Since the data is not shared it seems there is no benefit to doing it like this
Won't it simply be easier to load the data in the component/activity/fragment?
However, I get the benefit of maintaining the currently loading state. So the user can minimize and reopen the app and we continue (no need for saving an instance bundle).
I know by doing it like this, I lose the benefit of unidirectional data flow. But it seems to make more sense in the context of Android (pun intended).
Can I have your views on how you do this and if I'm simply worried about nothing.
NB: The data is not shared by any other stores at.