Repeated Items in RecyclerView - java

I am having problems with repeated items in RecyclerView. Whenever I upload to my firebase and open the main activity again there are repeated itmes in the recyclerView from the previous load. How do I remove repeated items from my recyclerView.
Code for my Main Activity is
private RecyclerView mRecyclerView;
private RecyclerViewAdapter mAdapter;
private DatabaseReference mDatabaseReference;
private List<Upload> mUploads;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_posts);
setupBottomNavigation();
mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mUploads = new ArrayList<>();
mDatabaseReference = FirebaseDatabase.getInstance().getReference("uploads");
mDatabaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot postSnapshot : dataSnapshot.getChildren())
{
Upload upload = postSnapshot.getValue(Upload.class);
mUploads.add(upload);
}
mAdapter = new RecyclerViewAdapter(MainActivity.this, mUploads);
mRecyclerView.setAdapter(mAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(MainActivity.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
Button btn_post = (Button) findViewById(R.id.post_Main);
btn_post.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent_posts = new Intent(MainActivity.this, Posts.class);
startActivity(intent_posts);
}
});
}
Code from my Adapter class is
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.rViewHolder> {
private Context mContext;
private List<Upload> mUploads;
public RecyclerViewAdapter(Context context, List<Upload> uploads){
mContext = context;
mUploads = uploads;
}
#Override
public rViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.card_view_recycler_view, parent, false);
return new rViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull rViewHolder viewHolder, int position) {
Upload uploadCurrent = mUploads.get(position);
viewHolder.textViewDescription.setText(uploadCurrent.getDescription());
Picasso.get().load(uploadCurrent.getImageUrl()).into(viewHolder.imageView);
}
#Override
public int getItemCount() {
return mUploads.size();
}
public class rViewHolder extends RecyclerView.ViewHolder{
public TextView textViewDescription;
public ImageView imageView;
public rViewHolder(View itemView){
super(itemView);
textViewDescription = itemView.findViewById(R.id.r_description);
imageView = itemView.findViewById(R.id.r_image_view);
}
}

i think this happens because firebase store data offline, try below way to initialise instance
FirebaseDatabase.getInstance().setPersistenceEnabled(false);
should work.

Try to clear your List before addind data to it as shown below.
private RecyclerView mRecyclerView;
private RecyclerViewAdapter mAdapter;
private DatabaseReference mDatabaseReference;
private List<Upload> mUploads;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_posts);
setupBottomNavigation();
mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mUploads = new ArrayList<>();
mDatabaseReference = FirebaseDatabase.getInstance().getReference("uploads");
mDatabaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot postSnapshot : dataSnapshot.getChildren())
{
Upload upload = postSnapshot.getValue(Upload.class);
mUploads.clear();
mUploads.add(upload);
}
mAdapter = new RecyclerViewAdapter(MainActivity.this, mUploads);
mRecyclerView.setAdapter(mAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(MainActivity.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
Button btn_post = (Button) findViewById(R.id.post_Main);
btn_post.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent_posts = new Intent(MainActivity.this, Posts.class);
startActivity(intent_posts);
}
});
}

Try clearing your ArrayList in this case mUploads before adding items to it i.e.,
mDatabaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
// Clear ArrayList
mUploads.clear();
for(DataSnapshot postSnapshot : dataSnapshot.getChildren())
{
Upload upload = postSnapshot.getValue(Upload.class);
mUploads.add(upload);
}
mAdapter = new RecyclerViewAdapter(MainActivity.this, mUploads);
mRecyclerView.setAdapter(mAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(MainActivity.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
This works well on my end and I hope it helps.
Reference here.

If you uninstall the app and install it again and there are duplicate items in the list the first time you run the app after installing, then there are duplicate items in the backend Firebase. If there are duplicate items only the second time you run the app then your code is responsible.
The code you have showed looks good to me. There have to be something else your not showing like by mistake you have duplicate addValueEventListener or you are feeding the Adapter a second time with the List<Upload> mUploads
As many suggest here that you do the mUploads.clear(); is not necessary since you populating the array from the onCreate(), witch only run once during Activity lifecykle
I would move the private List<Upload> mUploads; inside the onCreate() as a local variable if your not using it elsewhere

Related

How do i fix recyclerview shows database entrys twice after new entry?

My Code
FloatingActionButton button;
button = findViewById(R.id.floatbtn);
if (button != null) {
button.setOnClickListener(new android.view.View.OnClickListener() {
#Override
public void onClick(android.view.View v) {
startActivity(new Intent(Userlist.this, AddTextActivity.class));
recyclerView.removeAllViews();
recyclerView.removeAllViewsInLayout();
}
});
}
recyclerView = findViewById(R.id.userList);
database = FirebaseDatabase.getInstance().getReference("Messages");
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<>();
myAdapter = new MyAdapter(this, list);
recyclerView.setAdapter(myAdapter);
database.addValueEventListener(new ValueEventListener() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
Text text = dataSnapshot.getValue(Text.class);
list.add(text);
}
myAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
How do i fix recyclerview shows database entrys twice after new entry
I try to delete to remove all Views when Activity is closing. This didnt work.
Can you help me with this problem?
Why is this happening at all?

Is there a way to prevent the skipping of layout for the recyclerview?

Basically the app it's just a simple to do list, but when I add new task to do, it appears on firebase, but not on my app, giving the error
"E/RecyclerView: No adapter attached; skipping layout".
I tried to fix it following the answers here on stackoverflow but none of them helped me, probably I was wrong to adapt the adjustments to my code. I'm just learning and this is my first project, I was following a tutorial to do it.
Anyway, this is the MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonadd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Intent a = new Intent(MainActivity.this, AggiungiPiattoAttivity.class);
startActivity(a);
}
});
//working with data
ourdoes = findViewById(R.id.ourdoes);
ourdoes.setLayoutManager(new LinearLayoutManager(this));
list = new ArrayList<MyDoes>();
//get data from firebase
reference = FirebaseDatabase.getInstance(URL).getReference().child("AppLista");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//set code to retrive data and replace layout
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren())
{
MyDoes p = dataSnapshot1.getValue(MyDoes.class);
list.add(p);
}
doesAdapter = new DoesAdapter(MainActivity.this, list);
ourdoes.setAdapter(doesAdapter);
doesAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
//set code to show an error
Toast.makeText(getApplicationContext(), "No Data", Toast.LENGTH_SHORT).show();
}
});
}
This is the class where I add a new to do task:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aggiungi_piatto_attivity);
buttonaddnewpiatto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//insert data to database
reference = FirebaseDatabase.getInstance(URL).getReference().child("BoxDoese").child("Does" + doesNum);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("titledoes").setValue(addnamenewpiattosetted.getText().toString());
dataSnapshot.getRef().child("descdoes").setValue(adddescnewpiattosetted.getText().toString());
dataSnapshot.getRef().child("qualcosaalpostodiunimmagine").setValue(addrecipenewpiattosetted.getText().toString());
Intent a = new Intent( AggiungiPiattoAttivity.this, MainActivity.class);
startActivity(a);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
});
This is my adapter class:
public class DoesAdapter extends RecyclerView.Adapter<DoesAdapter.MyViewHolder> {
Context context;
ArrayList<MyDoes> myDoes;
public DoesAdapter(){
}
public DoesAdapter(Context c, ArrayList<MyDoes> p ){
context = c;
myDoes=p;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_does, viewGroup, false));
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder myViewHolder, int i) {
myViewHolder.titledoes.setText(myDoes.get(i).getTitledoes());
myViewHolder.qualcosaalpostodiunimmagine.setText(myDoes.get(i).getQualcosaalpostodiunimmagine());
myViewHolder.descdoes.setText(myDoes.get(i).getDescdoes());
}
#Override
public int getItemCount() {
return myDoes.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView titledoes, descdoes, qualcosaalpostodiunimmagine;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
titledoes = (TextView) itemView.findViewById(R.id.titledoes);
qualcosaalpostodiunimmagine = (TextView) itemView.findViewById(R.id.qualcosaalpostodiunimmagine);
descdoes = (TextView) itemView.findViewById(R.id.descdoes);
}
}
}
I also have other classes but to not put too much code I avoid to put them, they should not be relevant.
Create an empty adapter the same time you set LayoutManager for the RecyclerView: Save it as field of your class:
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
doesAdapter = new DoesAdapter(MainActivity.this, list);
recyclerView.setAdapter(DoesAdapter);
When data is ready, populate the adapter and notify:
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
/// origin code here
for (DataSnapshot dataSnapshot1: dataSnapshot.getChildren())
{
MyDoes p = dataSnapshot1.getValue(MyDoes.class);
list.add(p);
}
// reset data in adapter and not re-creating adapter:
doesAdapter.setItems(list);
doesAdapter.notifyDataSetChanged();
// instead of doesAdapter = new DoesAdapter(MainActivity.this, list);
recyclerView.setAdapter(DoesAdapter);
}
Source: https://stackoverflow.com/a/58251986/12596713

Error while passing data from clicked item in listview to another activity

After populating the Listview with the list of diaries, upon clicking a particular diary, the corresponding pictures have to be displayed in another activity.
For this, I'm passing the position of clicked item in the intent. But, the app crashes upon execution
This is the history fragment code
public class HistoryFragment extends Fragment
{
ListView lv;
Context context;
public HistoryFragment()
{
//default constructor
}
//The following method will get the context from the activity to which the fragment is attached
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context=context;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState)
{
final View view = inflater.inflate(R.layout.scrolllist, container, false);
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidRef = rootRef.child("image").child(uid);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//List<String> cities = new ArrayList<>();
//cities = new ArrayList<>();
final ArrayList<Word> cities = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String cityName = ds.getKey();
cities.add(new Word(cityName));
}
lv = (ListView)view.findViewById(R.id.list_of_ds);
ContentAdapter arrayAdapter = new ContentAdapter(context,cities);
lv.setAdapter(arrayAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError)
{
//Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
}
};
uidRef.addListenerForSingleValueEvent(valueEventListener);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
//String diary_name=title.get(position).toString();
Intent myIntent = new Intent(view.getContext(), DiaryViewActivity.class);
myIntent.putExtra("diaryname", lv.getItemAtPosition(position).toString());
startActivity(myIntent);
}
});
return view;
}
}
This is the activity to which intent is passed
//DiaryViewActivity.java
public class DiaryViewActivity extends AppCompatActivity implements IFirebaseLoadDone
{
ViewPager viewPager;
MAdapter adapter;
DatabaseReference diaries;
IFirebaseLoadDone iFirebaseLoadDone;
FirebaseAuth mAuth=FirebaseAuth.getInstance();
//final ArrayList<Word> word = new ArrayList<Word>();
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_diary_view);
Bundle bd = getIntent().getExtras();
String myVal = bd.getString("diaryname");
String currentUser;
currentUser = mAuth.getCurrentUser().getUid();
diaries = FirebaseDatabase.getInstance().getReference().child("image").child(currentUser)
.child(myVal);
iFirebaseLoadDone = this;
loadDairy();
viewPager = (ViewPager)findViewById(R.id.view_pager);
viewPager.setPageTransformer(true,new DepthPageTransformer());
}
private void loadDairy() {
diaries.addListenerForSingleValueEvent(new ValueEventListener() {
List<Display> diaryList = new ArrayList<>();
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot data:dataSnapshot.getChildren()) {
Display d = data.getValue(Display.class);
//word.add(new Word(d.dname));
diaryList.add(d);
}
iFirebaseLoadDone.onFirebaseLoadSuccess(diaryList);
}
#Override
public void onCancelled(DatabaseError databaseError) {
iFirebaseLoadDone.onFirebaseLoadFailed(databaseError.getMessage());
}
});
}
#Override
public void onFirebaseLoadSuccess(List<Display> diaryList) {
adapter = new MAdapter(this,diaryList);
viewPager.setAdapter(adapter);
}
#Override
public void onFirebaseLoadFailed(String message) {
Toast.makeText(this,"error! "+message,Toast.LENGTH_SHORT).show();
}
}
The following error occurs -
Attempt to invoke virtual method 'void android.widget.listview.setonitemclicklistener(android.widget.adapterview$onitemclicklistener)' on a null object reference
At the time that you call lv#setOnItemClickListener, your ListView (lv) hasn't been instantiated yet and won't be until the callback to ValueEventListener#onDataChange happens.

I want to fetch Product ID from Firebase

I am retrieving Product Information from Firebase, but the issue is that I can't select any specific ID that is stored in Firebase.
I tried different solutions for the problem including get(position) but it's getting the position of the product in the RecyclerView
This the ProductsAdapter onBindViewHolder function.
Changes are added using *'s
#Override
public void onBindViewHolder(#NonNull ProductViewHolder holder, int position) {
Product productCurrent = mProducts.get(position);
holder.product_title.setText(toCapitalize(productCurrent.getpTitle()));
holder.product_pice.setText("$: " + productCurrent.getpPrice());
Picasso.with(mContext)
.load(productCurrent.getpImageUrl())
.placeholder(R.mipmap.ic_launcher)
.fit()
.centerCrop()
.into(holder.product_image);
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, ProductPreview.class);
intent.putExtra("pImageUrl", productCurrent.getpImageUrl());
intent.putExtra("pTitle", toCapitalize(productCurrent.getpTitle()));
intent.putExtra("pPrice", productCurrent.getpPrice());
intent.putExtra("pDescription", toCapitalize(productCurrent.getpDescription()));
Toast.makeText(mContext, " " + position, Toast.LENGTH_SHORT).show();
mContext.startActivity(intent);
}
});
}
This Code is from the ProductsActivity having the RecyclerView
private ProductsAdapter mAdapter;
private ProgressBar mProgressBar;
DatabaseReference mDatabaseReference;
private ArrayList<Product> mProducts;
***ArrayList<ProductKeys> mProductKeys;***
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_products);
mRecyclerView = findViewById(R.id.products_recycler_view);
mRecyclerView.setHasFixedSize(true);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getApplicationContext(),2);
mRecyclerView.setLayoutManager(gridLayoutManager);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mProducts = new ArrayList<>();
***mProductKeys = new ArrayList<>();***
mDatabaseReference = FirebaseDatabase.getInstance().getReference("products");
mDatabaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapShot : dataSnapshot.getChildren())
{
Product product = postSnapShot.getValue(Product.class);
mProducts.add(product);
***mProductKeys.add(postSnapShot.getKey());***
}
mAdapter = new ProductsAdapter(ProductsActivity.this, mProducts);
mRecyclerView.setAdapter(mAdapter);
mProgressBar.setVisibility(View.INVISIBLE);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(ProductsActivity.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show();
mProgressBar.setVisibility(View.INVISIBLE);
}
});
Getting Error:
(com.*)
in ArrayList cannot be applied
to
(java.lang.String)
Please help me out of this... Thanks in Advance
If you're trying to determine the Firebase Database ID of the item at position in the onBindViewHolder method, you will have to maintain that mapping yourself. You can easily do this by extracting both the getKey() as well as the getValue() from the snapshot in onDataChange and keeping lists of both of them.
Something like this:
mProductKeys = new ArrayList<String>();
mDatabaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapShot : dataSnapshot.getChildren())
{
Product product = postSnapShot.getValue(Product.class);
mProducts.add(product);
mProductKeys.add(postSnapShot.getKey());
}
mAdapter = new ProductsAdapter(ProductsActivity.this, mProducts);
mRecyclerView.setAdapter(mAdapter);
mProgressBar.setVisibility(View.INVISIBLE);
}
And then in the onBindViewHolder you can look up the key for the item that was clicked on in mProductKeys.
Ok, I tried different things and #Frank's answer gave me some idea to do this. Just added one Line and its done. :) No Need to add ArrayList<String>.
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapShot : dataSnapshot.getChildren())
{
Product product = postSnapShot.getValue(Product.class);
product.setpKey(postSnapShot.getKey());
mProducts.add(product);
}
mAdapter = new ProductsAdapter(ProductsActivity.this, mProducts);
mRecyclerView.setAdapter(mAdapter);
mProgressBar.setVisibility(View.INVISIBLE);
}
And Added the String pKey to my Product.class with Setter and Getter.

I need to save all the job overviews int an array list, sorry if there is an obvious answer I am very new to java and android

Database
I have tried using orderByChild and nested for loops, but i am not sure how which method to use or how to use it. The purpose is to display cards of various strings in JOBOVERVIEW. Do you fellow stackoverflowrians have an answer, I have been stuck for a while and dont know where to proceed form here.
cheers and please dont hate.
package com.example.sherwin.todo;
import java.util.ArrayList;
public class JobList extends Fragment {
public JobList() {
}
public static JobList newInstance() {
JobList fragment = new JobList();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_job_list, container, false);
final RecyclerView recyclerView = (RecyclerView)rootView.findViewById(R.id.job_list_recycler_view);
LinearLayoutManager llm = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(llm);
final ArrayList<JobClass> joblistclass = new ArrayList<>();
final DatabaseReference myRef = FirebaseDatabase.getInstance().getReference("USERS/04950F4AE53F80/JOBS");
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot data:dataSnapshot.getChildren()
) {
if (data.getChildren().equals("JOBOVERVIEW")){
JobClass jblst = data.getValue(JobClass.class);
joblistclass.add(jblst);
}
}
final JobListRecyclerAdapter adapterb = new JobListRecyclerAdapter(joblistclass);
recyclerView.setAdapter(adapterb);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w("TAG:", "Failed to read value.", error.toException());
}
});
return rootView;
}
}
To achieve this, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference jobsRef = rootRef
.child("USERS")
.child("04950F4AE53F80")
.child("JOBS");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String jobDate = ds.child("JOBOVERVIEW").child("jobDate").getValue(String.class);
Log.d("TAG", jobDate);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
jobsRef.addListenerForSingleValueEvent(eventListener);
And the output will be:
29/09
2/2
//and so on

Categories

Resources