Update Spinner from another spinner dynamically - android

I have a fragment that creates controls at runtime, first create a spinner and then the second, the detail is in the second spinner depends on having the first selection.
As I can update the data of the second spinner depending on the selection of the first?
final Spinner Combo2 = new Spinner(FichaRutasVerif2SeccionSlideFragment.this.getActivity());
final Spinner Combo1 = new Spinner(FichaRutasVerif2SeccionSlideFragment.this.getActivity());
List<String> list = new ArrayList<String>();
list.add("TERRESTRE");
list.add("FLUVIAL");
list.add("AEREO");
final ArrayAdapter<String> adapterCombo = new ArrayAdapter<String>(FichaRutasVerif2SeccionSlideFragment.this.getActivity()
,android.R.layout.simple_spinner_item,list);
List<String> list2 = new ArrayList<String>();
list2.add("OP1");
list2.add("OP2");
final ArrayAdapter<String> adapterCombo2 = new ArrayAdapter<String>(FichaRutasVerif2SeccionSlideFragment.this.getActivity()
,android.R.layout.simple_spinner_item, list2);
if(listFormato.get(posicion).cSeccion.trim().equals("M"))
{
adapterCombo.setDropDownViewResource(R.layout.spinner);
Combo1.setAdapter(adapterCombo);
Combo1.setSelection(listFormato.get(posicion).iIndexCombo);
llTempZZ.addView(Combo1);
Combo1.setGravity(Gravity.CENTER);
llTempXX.addView(llTempZZ);
llTEMPADRE.addView(llTempXX);
pllh.addView(llTEMPADRE);
}
else if(listFormato.get(posicion).cSeccion.trim().equals("U")){
final Spinner Combo0 = new Spinner(FichaRutasVerif2SeccionSlideFragment.this.getActivity());
List<String> list3 =new ArrayList<String>();
list3.add("SI");
list3.add("NO");
ArrayAdapter<String> adapterCombo3 = new ArrayAdapter<String>(FichaRutasVerif2SeccionSlideFragment.this.getActivity()
,android.R.layout.simple_spinner_item, list3);
adapterCombo3.setDropDownViewResource(R.layout.spinner);
Combo0.setAdapter(adapterCombo3);
llTempZZ.addView(Combo0);
llTempXX.addView(llTempZZ);
//llTempXX.addView(llTempAA);
llTEMPADRE.addView(llTempXX);
pllh.addView(llTEMPADRE);
Combo0.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterView,
View view, int pos, long id) {
if (pos == 0) {
pll2.setVisibility(View.VISIBLE);
}
else if(pos==1) {
pll2.setVisibility(View.GONE);
}
listFormato.get(posicion).vResultado = Combo0.getSelectedItem().toString();
RECORDCARDITEM_DAO.Actualizar(FichaRutasVerif2SeccionSlideFragment.this.getActivity(), listFormato.get(posicion));
}
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
}
else if(listFormato.get(posicion).cSeccion.trim().equals("T"))
{
adapterCombo2.setDropDownViewResource(R.layout.spinner);
Combo2.setAdapter(adapterCombo2);
//Combo1.setSelection(listFormato.get(posicion).iIndexCombo);
llTempZZ.addView(Combo2);
Combo2.setGravity(Gravity.CENTER);
llTempXX.addView(llTempZZ);
llTEMPADRE.addView(llTempXX);
//////TEXTOS
Combo2.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> adapterView,
View view, int pos, long id) {
if(Combo2.getSelectedItemPosition()==0)
{
}
if (pos ==12) {
llTempAA.setVisibility(View.VISIBLE);
} else {
llTempAA.setVisibility(View.GONE);
}
listFormato.get(posicion).vResultado = Combo2.getSelectedItem().toString();
RECORDCARDITEM_DAO.Actualizar(FichaRutasVerif2SeccionSlideFragment.this.getActivity(), listFormato.get(posicion));
}
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
}

You can do something like this
Spinner firstSpinner = (Spinner) findViewById(R.id.first_spinner);
// You can set your first spinner values here if not set already, and then
firstSpinner.setOnItemSelectedListener(onFirstSpinnerChange(firstSpinner));
And the further add this
AdapterView.OnItemSelectedListener onFirstSpinnerChange(Spinner mySpinner) {
return new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
// You can add this method to set the values of the second spinner in your activity
// You can use the position, or alternatively selectedItemView for this purpose to identify the selected item
setSecondSpinnerBasedOnFirstOnePositionSelected();
// Or you can just set your spinner in this block
}
#Override
public void onNothingSelected(AdapterView<?> parentView) {
// do nothing
}
};
}

Related

how to invisible recyclerview item getting value from spinner

I want when user click on "قرآن" my program invisible else things mean tarjuma and tafsir,
same like when he clicks on "مع ترجمہ" my program visible Quran and tarjuma and hide the tafsir.
I am using spinner it works fine but after refresh my recyclerview but I want without refreshing the recyclerview, mean is that when the user selects any Spinner value recyclerview change the view.
refresh mean going to another activity.
anybody who help me!!
here is my RecyclerView Adapter
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, int position) {
final Quran quran = quranic.get(position);
if (Quran.spinner.equals("قرآن")) {
holder.quran.setText(Html.fromHtml(quran.getQuranText()));
holder.reference.setText(quran.getReferences());
holder.tarjuma.setVisibility(View.INVISIBLE);
holder.tafsir.setVisibility(View.INVISIBLE);
} else if (Quran.spinner.equals("مع ترجمہ")) {
holder.quran.setText(Html.fromHtml(quran.getQuranText()));
holder.tarjuma.setText(Html.fromHtml(quran.getTarjuma()));
holder.reference.setText(quran.getReferences());
holder.tafsir.setVisibility(View.INVISIBLE);
} else {
holder.quran.setText(Html.fromHtml(quran.getQuranText()));
holder.tarjuma.setText(Html.fromHtml(quran.getTarjuma()));
holder.tafsir.setText(Html.fromHtml(quran.getTafsir()));
holder.reference.setText(quran.getReferences());
}
}
my MainActivity
Spinner spinner = (Spinner) findViewById(R.id.visibility);
List<String> spinnerList = new ArrayList<>();
spinnerList.add(0, "Select");
spinnerList.add(1, "قرآن");
spinnerList.add(2, "مع ترجمہ");
spinnerList.add(3, "مع تفسیر");
ArrayAdapter dataAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, spinnerList);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(dataAdapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getItemAtPosition(position).equals("Select")) {
// do nothing
} else {
String item = parent.getItemAtPosition(position).toString();
Quran.spinner = item;
Toast.makeText(parent.getContext(), "Selected: " + item, Toast.LENGTH_LONG).show();
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
Quran.java
public static String spinner = "";
You just need to call notifyDataSetChanged(); on your recycler view adapter each time you select an item from your spinner.
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getItemAtPosition(position).equals("Select")) {
// do nothing
} else {
String item = parent.getItemAtPosition(position).toString();
Quran.spinner = item;
Toast.makeText(parent.getContext(), "Selected: " + item, Toast.LENGTH_LONG).show();
RecyclerView.Adapter adapter = recyclerView != null ? recyclerView.getAdapter() : null;
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
Even better if you keep a reference to your recycler view adapter, then replace:
RecyclerView.Adapter adapter = recyclerView != null ? recyclerView.getAdapter() : null;
if (adapter != null) {
adapter.notifyDataSetChanged();
}
by:
adapter.notifyDataSetChanged();
}
Spinner spinner = (Spinner) findViewById(R.id.visibility);
List<String> spinnerList = new ArrayList<>();
spinnerList.add(0, "Select");
spinnerList.add(1, "قرآن");
spinnerList.add(2, "مع ترجمہ");
spinnerList.add(3, "مع تفسیر");
ArrayAdapter dataAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, spinnerList);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(dataAdapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getItemAtPosition(position).equals("Select")) {
// do nothing
} else {
String item = parent.getItemAtPosition(position).toString();
Quran.spinner = item;
//add this line
yourAdapterObject.notifyDataSetChanged();
Toast.makeText(parent.getContext(), "Selected: " + item, Toast.LENGTH_LONG).show();
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});

how to get spinner value position on button click [duplicate]

I'm trying to get the position (number) of the spinner when selected to use it in another Activity that will display a different map each time depending on the item selected. when I run the application it crashes. this is the first Activity code:
public class TestProjectActivity extends Activity {
public Spinner spinner1;
public Integer number;
private Button valideButton;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MySpinner();
valide_button();
}
public void MySpinner() {
final Spinner spinner1 = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.num, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(adapter);
spinner1.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parentView,
View selectedItemView, int position, long id) {
// Object item = parentView.getItemAtPosition(position);
TestProjectActivity.this.number = spinner1
.getSelectedItemPosition() + 1;
}
public void onNothingSelected(AdapterView<?> arg0) {// do nothing
}
});
}
public void valide_button() {
valideButton = (Button) findViewById(R.id.valide_button);
valideButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(TestProjectActivity.this,
MetroMapActivity.class);
startActivity(intent);
}
});
}
}
The way to get the selection of the spinner is:
spinner1.getSelectedItemPosition();
Documentation reference:
http://developer.android.com/reference/android/widget/AdapterView.html#getSelectedItemPosition()
However, in your code, the one place you are referencing it is within your setOnItemSelectedListener(). It is not necessary to poll the spinner, because the onItemSelected method gets passed the position as the "position" variable.
So you could change that line to:
TestProjectActivity.this.number = position + 1;
If that does not fix the problem, please post the error message generated when your app crashes.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = findViewById(R.id.button);
spinner = findViewById(R.id.sp_item);
setInfo();
spinnerAdapter = new SpinnerAdapter(this, arrayList);
spinner.setAdapter(spinnerAdapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
//first, we have to retrieve the item position as a string
// then, we can change string value into integer
String item_position = String.valueOf(position);
int positonInt = Integer.valueOf(item_position);
Toast.makeText(MainActivity.this, "value is "+ positonInt, Toast.LENGTH_SHORT).show();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
note: the position of items is counted from 0.
final int[] positions=new int[2];
Spinner sp=findViewByID(R.id.spinner);
sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
Toast.makeText( arg2....);
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
if (position ==0) {
if (rYes.isChecked()) {
Toast.makeText(SportActivity.this, "yes ur answer is right", Toast.LENGTH_LONG).show();
} else if (rNo.isChecked()) {
Toast.makeText(SportActivity.this, "no.ur answer is wrong", Toast.LENGTH_LONG).show();
}
}
This code is supposed to select both check boxes.
Is there a problem with it?

How can I pick only once a value from spinner in android

I have a spinner with ten numbers 0-10 and I if someone picks a number I want him not to be able to pick the same value again. So inside ItemSelected I do the following with no result
#Override
public void onItemSelected(AdapterView<?> adapter, View v, int position, long id) {
// On selecting a spinner item
if (position > 0 && position!=tempPosition)
{
TeamSpinnerNumber = adapter.getItemAtPosition(position).toString();
tempPosition = position
}
}
Check this i worked out for you may it help you.
public class MainActivity extends AppCompatActivity {
ArrayList<String> mStrings;
ArrayAdapter<String> mStringArrayAdapter;
Spinner mSpinner;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSpinner = (Spinner) findViewById(R.id.spinner);
mStrings = new ArrayList<String>() {{
add("None");
add("one");
add("two");
add("three");
}};
mStringArrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings);
mSpinner.setAdapter(mStringArrayAdapter);
mSpinner.setSelection(0);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String string = parent.getItemAtPosition(position).toString();
if (!string.equals("None"))
removeThisFromSpinner(string);
mSpinner.setSelection(0);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
private void removeThisFromSpinner(String s) {
mStrings.remove(s);
mStringArrayAdapter.notifyDataSetChanged();
}
}
try this, hope it helps :
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Log.i(TAG, "onItemSelected: "+position);
//checking the position of the selected spinner item, if the previous position is not the same then do something here
if(position>0 && position!=myPosition){
}
myPosition = position;
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
and don't forget to add global variable to the class :
int myPosition = 999; // the non existed position make it global variable

Loading data to Chain of Spinners according to the previous selected value

I have 3 spinners in my activity and I'm loading data for these 3 spinners from json response.
1st spinner(crustSP) gets data straight forward from the json response.
2nd spinner's (SizeSP) data depends on what selected from 1st spinner and
3rd spinner's (extraDescriptionOneSP) data depends on what select from 2nd spinner.
My question is it crashes inside 2nd SP because I haven't selected any value inside that when activity starting (I have shown that inside the code as a comment), how can I overcome that? where should I have that piece of code. It goes on without crashing when I hard code the position of sizeSp.
crust = Utils.removeDuplicatesFromList(crust);
ArrayAdapter<String> dataAdapterCru = new ArrayAdapter<String>(
this, android.R.layout.simple_spinner_item, crust);
dataAdapterCru
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
crustSP.setAdapter(dataAdapterCru);
crustSP.setOnItemSelectedListener(new MyOnItemSelectedListener(
ActivityPizzaCustomize.this) {
public void onNothingSelected(AdapterView<?> arg0) {
}
#Override
public void onItemSelected(AdapterView<?> parent,
View view, int position, long id) {
String crustSelectedItem = crustSP.getSelectedItem()
.toString();
List<String> resultDescription = getFilteredDescriptions(
crustSelectedItem, sizeDescription);
sizeSP.setOnItemSelectedListener(new MyOnItemSelectedListener(
ActivityPizzaCustomize.this) {
public void onNothingSelected(AdapterView<?> arg0) {
}
#Override
public void onItemSelected(AdapterView<?> parent,
View view, int position, long id) {
String sizeSelectedItem = sizeSP
.getSelectedItem().toString(); // it crashes here since I haven't selected any value
List<String> resultTopping = getFilteredToppings(
sizeSelectedItem, topDescription);
extraDescriptionOneSP
.setOnItemSelectedListener(new MyOnItemSelectedListener(
ActivityPizzaCustomize.this));
ArrayAdapter<String> dataAdapterExtraDesOne = new ArrayAdapter<String>(
ActivityPizzaCustomize.this,
android.R.layout.simple_spinner_item,
resultTopping);
dataAdapterExtraDesOne
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
extraDescriptionOneSP
.setAdapter(dataAdapterExtraDesOne);
extraDescriptionOneSP
.setAdapter(new NothingSelectedSpinnerAdapter(
dataAdapterExtraDesOne,
R.layout.contact_spinner_row_nothing_selected,
ActivityPizzaCustomize.this));
}
});
ArrayAdapter<String> dataAdapterDes = new ArrayAdapter<String>(
ActivityPizzaCustomize.this,
android.R.layout.simple_spinner_item,
resultDescription);
dataAdapterDes
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sizeSP.setAdapter(dataAdapterDes);
sizeSP.setAdapter(new NothingSelectedSpinnerAdapter(
dataAdapterDes,
R.layout.contact_spinner_row_nothing_selected,
ActivityPizzaCustomize.this));
}
});
This is how I filter the items,
List<String> getFilteredDescriptions(String crustSelectedItem,
List<String> sizeDescription) {
List<String> resultDescription = new ArrayList<String>();
crustSelectedItem = crustSP.getSelectedItem().toString();
if (sizeDescription == null || sizeDescription.isEmpty())
return resultDescription;
for (int i = 0; i < sizeDescription.size(); i++) {
sizeDescription = Utils.removeDuplicatesFromList(sizeDescription);
if (!sizeDescription.get(i).contains(crustSelectedItem))
continue;
resultDescription.add(sizeDescription.get(i));
}
return resultDescription;
}
List<String> getFilteredToppings(String sizeSelectedItem,
List<String> topDescription) {
List<String> resultTopping = new ArrayList<String>();
sizeSelectedItem = sizeSP.getSelectedItem().toString();
if (topDescription == null || topDescription.isEmpty())
return resultTopping;
for (int i = 0; i < topDescription.size(); i++) {
topDescription = Utils.removeDuplicatesFromList(topDescription);
if (!topDescription.get(i).contains(sizeSelectedItem))
continue;
resultTopping.add(topDescription.get(i));
}
return resultTopping;
}
You have to call onItemSelectedListner inside the other one, Like,,
spinner1.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
Arraylist2.add((String)spinner1.getItemAtPosition(position));
//Some Code/Ligic here
spinner2.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent,
View view, int position2, long id) {
// TODO Auto-generated method stub
Arraylist3.add((String) spinner2.getItemAtPosition(position2));
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub111
}
});
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
Hope it helps...
just give it try..
put this code before setting onItemSelectedListner..
spin1.setSelection(0, false);

Get the position of a spinner in Android

I'm trying to get the position (number) of the spinner when selected to use it in another Activity that will display a different map each time depending on the item selected. when I run the application it crashes. this is the first Activity code:
public class TestProjectActivity extends Activity {
public Spinner spinner1;
public Integer number;
private Button valideButton;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MySpinner();
valide_button();
}
public void MySpinner() {
final Spinner spinner1 = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.num, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(adapter);
spinner1.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parentView,
View selectedItemView, int position, long id) {
// Object item = parentView.getItemAtPosition(position);
TestProjectActivity.this.number = spinner1
.getSelectedItemPosition() + 1;
}
public void onNothingSelected(AdapterView<?> arg0) {// do nothing
}
});
}
public void valide_button() {
valideButton = (Button) findViewById(R.id.valide_button);
valideButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(TestProjectActivity.this,
MetroMapActivity.class);
startActivity(intent);
}
});
}
}
The way to get the selection of the spinner is:
spinner1.getSelectedItemPosition();
Documentation reference:
http://developer.android.com/reference/android/widget/AdapterView.html#getSelectedItemPosition()
However, in your code, the one place you are referencing it is within your setOnItemSelectedListener(). It is not necessary to poll the spinner, because the onItemSelected method gets passed the position as the "position" variable.
So you could change that line to:
TestProjectActivity.this.number = position + 1;
If that does not fix the problem, please post the error message generated when your app crashes.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = findViewById(R.id.button);
spinner = findViewById(R.id.sp_item);
setInfo();
spinnerAdapter = new SpinnerAdapter(this, arrayList);
spinner.setAdapter(spinnerAdapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
//first, we have to retrieve the item position as a string
// then, we can change string value into integer
String item_position = String.valueOf(position);
int positonInt = Integer.valueOf(item_position);
Toast.makeText(MainActivity.this, "value is "+ positonInt, Toast.LENGTH_SHORT).show();
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
note: the position of items is counted from 0.
final int[] positions=new int[2];
Spinner sp=findViewByID(R.id.spinner);
sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
Toast.makeText( arg2....);
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
if (position ==0) {
if (rYes.isChecked()) {
Toast.makeText(SportActivity.this, "yes ur answer is right", Toast.LENGTH_LONG).show();
} else if (rNo.isChecked()) {
Toast.makeText(SportActivity.this, "no.ur answer is wrong", Toast.LENGTH_LONG).show();
}
}
This code is supposed to select both check boxes.
Is there a problem with it?

Categories

Resources