0

I'm building an Android App with Kotlin that uses various NYTimes APIs to fetch different news data.. Here I have a search screen where I want the user to be able to enter a search query (i.e. "Japan") and check off any checkbox and they will even be able to add a begin or end date to refine their search :

enter image description here

Typing something in the search query and checking off at least one box are the only requirements, everything else will be mandatory. And once they hit "Search", it will pass the data they entered to a second activity which will use the data to put together an api call, make the api call, and populate a recyclerview , like so:

enter image description here

Now here is my issue... I have the SEARCH button only sending data if the search query has been entered and if the travel checkbox has been checked, and as you can imagine there are a TON of combinations.. I don't know how I can pass over all of those combinations and make each API Call accordingly without having an extremely long If/Else Block that'll take forever... Using Kotlin, there has to be a more efficient way right ?

Here is my Search Activity:

class SearchActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_search)

        search_query_edittext.getBackground().clearColorFilter();


        actionBar?.setDisplayHomeAsUpEnabled(true)
        Enter_Begin_Date.setPaintFlags(Enter_Begin_Date.getPaintFlags())
        Enter_End_Date.setPaintFlags(Enter_End_Date.getPaintFlags())

        // Calendar
        val c = Calendar.getInstance()
        val year = c.get(Calendar.YEAR)
        val month = c.get(Calendar.MONTH)
        val day = c.get(Calendar.DAY_OF_MONTH)

        // TextView Clicked to show Date Picker Dialog
        Enter_Begin_Date.setOnClickListener {
            val dpd = DatePickerDialog(
                this,
                DatePickerDialog.OnDateSetListener { view, Year, Month, Day ->
                    // set to textView
                    if (Day < 10 && Month < 10) {
                        Enter_Begin_Date.text =
                            "0" + Day + "/0" + Month.toInt().plus(1) + "/" + Year
                    } else if (Day < 10 && Month >= 10) {
                        Enter_Begin_Date.text = "0" + Day + "/" + Month.toInt().plus(1) + "/" + Year
                    } else if (Day >= 10 && Month < 10) {
                        Enter_Begin_Date.text = "" + Day + "/0" + Month.toInt().plus(1) + "/" + Year
                    }

                },
                year,
                month,
                day
            )
            // show dialog
            dpd.show()
        }

        Enter_End_Date.setOnClickListener {
            val dpd = DatePickerDialog(
                this,
                DatePickerDialog.OnDateSetListener { view, Year, Month, Day ->
                    // set to textView
                    if (Day < 10 && Month < 10) {
                        Enter_End_Date.text = "0" + Day + "/0" + Month.toInt().plus(1) + "/" + Year
                    } else if (Day < 10 && Month >= 10) {
                        Enter_End_Date.text = "0" + Day + "/" + Month.toInt().plus(1) + "/" + Year
                    } else if (Day >= 10 && Month < 10) {
                        Enter_End_Date.text = "" + Day + "/0" + Month.toInt().plus(1) + "/" + Year
                    }

                },
                year,
                month,
                day
            )
            // show dialog
            dpd.show()
        }

        searchButton.setOnClickListener {
            if ((search_query_edittext.text.isNotEmpty()
                        && Enter_Begin_Date.text.isEmpty()
                        && Enter_End_Date.text.isEmpty()) && TravelTextBox.isChecked && !SportsTextBox.isChecked && !PoliticsTextBox.isChecked && !EntrepreneursTextBox.isChecked && !BusinessTextBox.isChecked && !ArtsCheckBox.isChecked
            ) {
                val searchQuery: String = search_query_edittext.text.toString()
                        val query = searchQuery
                        val travelCategory: String = "Travel"

                        val intent = Intent(this@SearchActivity, ResultsActivity::class.java)
                        intent.putExtra("query", query)
                        intent.putExtra("travelCategory", travelCategory)
                        startActivity(intent)
                }
            }

        }

    }

My Result Activity:

class ResultsActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_results)

        val bundle: Bundle? = intent.extras
        val myQuery = bundle!!.getString("query")
        val myTravelCategory = bundle!!.getString("travelCategory")
        if (bundle.containsKey("query") && bundle.containsKey("travelCategory")) {
            lifecycleScope.launch(IO) {
                val result = ApiClient.getClient.getSearchResultWithCheckbox(query = myQuery!!,
                    category = myTravelCategory!!,
                    api_key = (MYAPIKEY)
                withContext(Main) {
                    SearchResultsRecyclerView.apply {
                        layoutManager = LinearLayoutManager(this@ResultsActivity)
                        adapter = SearchResultsAdapter(result.response.docs)
                    }
                }
            }

        }

    }
}

As you can see, I only have coded enough to cover for the user to enter in the search query , to check the travel checkbox and to hit enter, there are like 145 more combinations (search query + begin date + politics checkbox, search query + end date + sports checkbox, etc etc..) How can I add in all of the other combinations without using an extremely long If/Else block?

Anything to push me in the right direction would be highly appreciated , thanks!

Cosovic
  • 79
  • 6
  • Can't it be done via passing the intents to the next Activity? Have you tried it ? – AgentP Jul 09 '20 at 08:26
  • Can you tell what all parameters does the API take? Can you paste the API contract – p.mathew13 Jul 09 '20 at 09:07
  • The parameters are : q - search query (the search term the user types in - MANDATORY), fq - the category (Travel, Arts, Business, etc- One of these check boxes is MANDATORY), begin date (OPTIONAL), end date (OPTIONAL). – Cosovic Jul 09 '20 at 19:20

1 Answers1

0

check for the condition you want, not the combinations that produce it. Check if the search query is filled and that at least one checkbox is checked. Without knowing how the API works is hard to recommend a particular way to pass the data but taking advantage of nullable types and/or optional paramaters with something like this should work:

private fun getCheckedCategories() : List<String> = listOfNotNull(
    "Travel".takeIf { TravelTextBox.isChecked },
    ...
)

private fun atLeastOneCheckBoxChecked() = getCheckedCategories().isNotEmpty()

With this helper functions you can build a listener similar to this:

searchButton.setOnClickListener {
if (search_query_edittext.text.isNotEmpty() && atLeastOneCheckBoxChecked()) {
    val searchQuery: String = search_query_edittext.text.toString()
    val checkedCategories = getCheckedCategories()
    val beginDate : String? = TODO()
    val endDate : String? = TODO()

    val intent = Intent(this@SearchActivity, ResultsActivity::class.java)
    intent.putExtra("query", searchQuery)
    intent.putStringArrayList("checkedCategories", ArrayList(checkedCategories))
    intent.putExtra("beginDate", beginDate)
    intent.putExtra("endDate", endDate)
    startActivity(intent)
}
}

In the other end the bundle?.getString("beginDate") will return null if not passed, and whatever value it has if passed. Or retrieve the list of passed checkboxes with bundle?getStringArrayList("checkedCategories").orEmpty()

Eric Martori
  • 2,885
  • 19
  • 26
  • Thank you. What about my recyclerview in the results Activity? Do I only apply it once based on how many parameters are fulfilled and how do I do that with the api call? – Cosovic Jul 09 '20 at 20:02
  • Maybe you should create another question or update this one with more details about this other question. Without knowing more details it is hard to recommend anything – Eric Martori Jul 10 '20 at 08:38