I am creating android library. In lib there is screen with 3 edittexts. User enters day, month and year. I have to find out is user older than 18.
I don't have any documentation for error handling or anything for this task. So I did something on my own.
My function for checking is user older than 18 is like this:
fun isUserAdult(birthDay: String, birthMonth: String, birthYear: String): Boolean {
val year = Integer.parseInt(birthDay)
val month = Integer.parseInt(birthMonth)
val day = Integer.parseInt(birthYear)
val c1 = Calendar.getInstance()
c1.set(year, month - 1, day, 0, 0)
val c2 = Calendar.getInstance()
var diff = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR)
if (c1.get(Calendar.MONTH) > c2.get(Calendar.MONTH) ||
(c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH) && c1.get(Calendar.DATE) > c2.get(
Calendar.DATE
))
) {
diff--
}
return diff >= 18
}
My error handling is based just on my logic. It looks something like this:
fun isDataValid(birthDay: String, birthMonth: String, birthYear: String): Boolean {
return !(birthDay.startsWith("0") && birthMonth.startsWith("0") && birthYear.startsWith("0") || Integer.parseInt(
birthMonth
) > 12 || Integer.parseInt(birthDay) > 31 || Calendar.getInstance()
.get(Calendar.YEAR) < Integer.parseInt(birthYear) || Integer.parseInt(birthYear)< 1880)
}
This looks fine on the first look but I believe there are a lot of cases when considering date that makes my code error-prone.
Is there any other way to do this or has anyone some advice on how to improve my way?
Related
The bounty expires in 7 days. Answers to this question are eligible for a +50 reputation bounty.
MARSH is looking for an answer from a reputable source:
Please help me this is happening because of Localisation but i have debug code i am seeing its going in English language but its showing spanish language
This is popup for time picker.
when I click on keyboard icon it's showing like below screen.
I am using localization in our APP and below code I have written to open Time picker Popup
private fun openTimePickerDialog(datetime: String) {
val mHour: Int = datetime.substring(8, 10).toInt()
val mMinute: Int = datetime.substring(10, 12).toInt()
setDefaultLanguage()
Log.i("TAG", "openTimePickerDialog: $mHour $mMinute")
val timePickerDialog = TimePickerDialog(
activity,
{ _, hourOfDay, minute ->
var selectedMinute = minute.toString()
var selectedHour = hourOfDay.toString()
if (minute < 10) {
selectedMinute = "0$selectedMinute"
}
if (hourOfDay < 10) {
selectedHour = "0$selectedHour"
}
isClickedDate = ""
val date: String = datetime.substring(0, 8)
val time = selectedHour + selectedMinute + "00"
Log.i("TAG", "onTimeSet: $date$time")
roveR3SettingFragmentViewModel.setDateTime(date + time)
// txtTime.setText(hourOfDay + ":" + minute);
}, mHour, mMinute, false
)
timePickerDialog.setButton(
DatePickerDialog.BUTTON_POSITIVE,
getString(R.string.ok),
timePickerDialog
)
timePickerDialog.setButton(
DatePickerDialog.BUTTON_NEGATIVE,
getString(R.string.txt_cancel),
timePickerDialog
)
timePickerDialog.show()
}
private fun setDefaultLanguage() {
if (appPreference.appLanguage == LANGAUGE_ES) {
val locale1 = Locale("en")
Locale.setDefault(locale1)
val config = requireContext().resources.configuration
config.setLocale(locale1)
requireContext().createConfigurationContext(config)
} else if (appPreference.appLanguage == LANGAUGE_ES) {
val locale1 = Locale("ja")
Locale.setDefault(locale1)
val config = requireContext().resources.configuration
config.setLocale(locale1)
requireContext().createConfigurationContext(config)
}
}
Can any one please help me how to fix the language issue which is coming when i click on keyboard icon of time picker dialogue. I want it in english language I have selected it for English only other all thing coming in english but time picker is coming in Spanish language. Thanks.
Check the setDefaultLanguage() method in your code carefully.
Conditions for both if & else if looks the same, so always it will run the functions in the else if section.
Try to use a different condition for else if
Check the example code here,
private fun setDefaultLanguage() {
if (appPreference.appLanguage == CONDITION_1) {
val locale1 = Locale("en")
Locale.setDefault(locale1)
val config = requireContext().resources.configuration
config.setLocale(locale1)
requireContext().createConfigurationContext(config)
} else if (appPreference.appLanguage == CONDITION_2) {
val locale1 = Locale("ja")
Locale.setDefault(locale1)
val config = requireContext().resources.configuration
config.setLocale(locale1)
requireContext().createConfigurationContext(config)
}
}
In your scenario, both condition 1 and 2 are same. So, always the popup using the language from else if
How can I get the dates of the current week using kotlinx.datetime KMM library?
eg. I want to get a list of current week's date like:
("Monday, 07", "Tuesday, 08", "Wednesday, 09", ... )
This is a similar impementation using Calendar:
fun getDaysOfWeek(): Array<String?> {
val dateFormat = SimpleDateFormat("EEEEE\ndd", Locale.getDefault())
val calendar = Calendar.getInstance()
calendar.firstDayOfWeek = Calendar.MONDAY
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
val days = arrayOfNulls<String>(7)
for (i in 0..6) {
days[i] = dateFormat.format(calendar.time)
calendar.add(Calendar.DAY_OF_MONTH, 1)
}
return days
}
val today = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date
val days = mutableListOf<LocalDate>()
val firstWeekDay = today.daysShift(-DayOfWeek.values().indexOf(today.dayOfWeek))
for (i in 0 until DayOfWeek.values().count()) {
days.add(firstWeekDay.daysShift(i))
}
val dayStrings = days.map { "${it.dayOfWeek}, ${it.dayOfMonth}" }
println("$dayStrings")
fun LocalDate.daysShift(days: Int): LocalDate = when {
days < 0 -> {
minus(DateTimeUnit.DayBased(-days))
}
days > 0 -> {
plus(DateTimeUnit.DayBased(days))
}
else -> this
}
I want to create a function that returns a list of dates in the given range, with recursion. I will provide the starting date, the ending date, and the type of recursion. I am not sure how to start. Any suggestions would be helpful. Is there any library for this, or do I have to do it on my own?
data class Date(
val day: Int,
val month: Int,
val year: Int
)
enum class Recursion {
NEVER,
EVERY_DAY,
EVERY_WORK_DAY,
EVERY_WEEK,
EVERY_MONTH,
ANNUAL
}
fun createListOfEvents(startDate: Date, endDate: Date, recursion: Recursion): List<Date>{
}
You need to enable desugaring if targeting SDK < 26.
Then you can use the LocalDate class for this. Your Date class is kind of redundant, but you could convert inside the function to LocalDate if you want to keep it.
fun createListOfEvents(startDate: LocalDate, endDate: LocalDate, recursion: Recursion): List<LocalDate> {
val step = when (recursion) {
Recursion.NEVER -> return emptyList()
Recursion.EVERY_DAY, Recursion.EVERY_WORK_DAY -> Period.ofDays(1)
Recursion.EVERY_WEEK -> Period.ofWeeks(1)
Recursion.EVERY_MONTH -> Period.ofMonths(1)
Recursion.ANNUAL -> Period.ofYears(1)
}
var date = startDate
val list = mutableListOf<LocalDate>()
while (date <= endDate) {
list.add(date)
date += step
}
if (recursion == Recursion.EVERY_WORK_DAY) {
val weekend = listOf(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY)
list.removeAll { it.dayOfWeek in weekend }
}
return list
}
Well, basically this is an example of how you can do this:
data class Recursion(val field : TemporalUnit, val step: Long)
val step1Day = Recursion(field = ChronoUnit.DAYS, step = 1)
fun createListOfEvents(startDate: LocalDate, endDate: LocalDate, recursion: Recursion): List<LocalDate>{
var currentDate = startDate
val listOfDates = mutableListOf<LocalDate>()
while (currentDate.isBefore(endDate)) {
listOfDates.add(currentDate)
currentDate = startDate.plus(recursion.step, recursion.field)
}
return listOfDates
}
This method returns list of dates from startDate until endDate with the step of Recursion.
As you can see I've used java.time.* classes for this, but eventually you can convert them into your own Date and Recursion and back.
Here TemporalUnit can be DAYS, WEEKS, MONTHS, YEARS (and other).
It covers most of your needs, working days you will have to manage manually.
Hope this makes sense )
so I have this problem where I am trying to make Random Number Generator app on android. Basically you set the minimum and the maximum number and then it randomly picks numbers between min and max.
However my problem comes if the min or max TextEdit field is empty, the app crashes. I would like to display "X" on the screen. How to check if the field is empty or not?
I am using kotlin and here is sample of my code. I am begginer so please do not flame me if the code is wrong :)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val rollButton = findViewById<Button>(R.id.rollButton)
val resultsTextView = findViewById<TextView>(R.id.resultsTextView)
//val seekBar = findViewById<SeekBar>(R.id.seekBar)
val min = findViewById<TextView>(R.id.number_min)
val max = findViewById<TextView>(R.id.number_max)
rollButton.setOnClickListener {
if(min.text.toString().toInt()>= 0 && max.text.toString().toInt() <= 1000){
val rand = Random.nextInt(min.text.toString().toInt(),max.text.toString().toInt()+1)
resultsTextView.text = rand.toString()
}
else if(min.text.toString().isNullOrBlank()){
resultsTextView.text = "X"
}
else{
resultsTextView.text = "X"
}
}
}
}
To check if your EditText is empty use isNullOrEmpty(). This will check if your field is empty or is null, like the method name says. Here is an example:
val editTextString :String = editText.text.toString()
if(!editTextString.isNullOrEmpty()) //returns true if string is null or empty
There is another approach with TextUtils but since you are using Kotlin this approach is better.
EDIT:
You are doing this:
if(min.text.toString().toInt()>= 0 && max.text.toString().toInt() <= 1000){
val rand = Random.nextInt(min.text.toString().toInt(),max.text.toString().toInt()+1)
resultsTextView.text = rand.toString()
}
and here this line min.text.toString().toInt() is throwing you an exception. The reason for this is because currently min or max are empty String. So compailer can't format number from an String equals to "". You should do it like this:
if(!min.text.toString().isNullOrEmpty() && !max.text.toString().isNullOrEmpty() && min.text.toString().toInt()>= 0 && max.text.toString().toInt() <= 1000){
val rand = Random.nextInt(min.text.toString().toInt(),max.text.toString().toInt()+1)
resultsTextView.text = rand.toString()
}
I hope this works. If not, then take this into two IF statements like this:
if(min.text.toString().isNullOrEmpty() || max.text.toString().isNullOrEmpty() {
resultsTextView.text = "X"
} else if(min.text.toString().toInt() >= 0 && max.text.toString().toInt() <= 1000) {
val rand = Random.nextInt(min.text.toString().toInt(), max.text.toString.toInt()+1)
resultsTextView.text = rand.toString()
}
The second approach is maybe an even better and cleaner version since you don't have to check for anything else later.
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 :
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:
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!
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()