How to validate Material RangeDatePicker from first selection(point) in Android? - android

I want validate range-date-picker from first selection to 6 month but I couldn't.
Tried to catch(detect) first user selection(date) on range picker from this 'CalendarConstraints.Builder()'
val constDate = CalendarConstraints.Builder()
constDate.setValidator(object : CalendarConstraints.DateValidator {
...
//this code not work correctly
override fun isValid(date: Long): Boolean {
val calendar = Calendar.getInstance()
if (initTime == 0.toLong())
initTime = System.currentTimeMillis()
return if (System.currentTimeMillis() > initTime + 1000) {
Log.e("DateActivity", "isValid: 크다")
if (firstOrder == 0) {
firstSelect = date
firstOrder++
calendar.time = Date(firstSelect)
calendar.add(Calendar.MONTH, 6)
}
val remainDate = Calendar.getInstance()
remainDate.time = Date(date)
calendar > remainDate
} else {
Log.e("DateActivity", "isValid: 크지 않다.")
true
}
}
}
builder.setCalendarConstraints(constDate.build())
val picker = builder.build()
By time difference(System.currentTimeMillis()) try to catch first selection but when swipe picker other date catched in override fun isValid() . so I tried setOnTouchListener{} but no found way picker's setOnTouchListener in override fun isValid() cause picker built after CalendarConstraints set.
This is just static validation. I Think.
https://stackoverflow.com/a/58354878/13050313
https://stackoverflow.com/a/62080184/13050313

Now, I don't need this function what I asked 7 month ago, but I got this now.
//global
private const val RESET_TIME_MILLIS = 1500L
private var TERM_CALENDAR: Calendar = Calendar.getInstance()
private const val DAY_OF_TERM = 60
//prperties of Fragment or Activity
private val calendar = Calendar.getInstance()
private var firstSelect: Calendar? = null
private var secondSelect: Calendar? = null
//setValidator(below object)
object : CalendarConstraints.DateValidator {
private val dayList = arrayListOf<Calendar>()
private var job: Job? = null
override fun isValid(date: Long): Boolean {
if (job == null) {
job = lifecycleScope.launch {
delay(RESET_TIME_MILLIS)
if (secondSelect != null) {
firstSelect = null
secondSelect = null
}
dayList.clear()
}
} else {
if (job!!.isCompleted) {
job = null
}
}
calendar.time = Date(date)
val instancCal = Calendar.getInstance().apply {
time = Date(date)
}
dayList.add(instancCal)
if (calendar.dayOfMonth() == 1 && dayList.count() == 2) {
if (firstSelect == null) {
firstSelect = dayList[0]
TERM_CALENDAR.apply {
set(Calendar.YEAR, firstSelect!!.get(Calendar.YEAR))
set(Calendar.MONTH, firstSelect!!.get(Calendar.MONTH))
set(Calendar.DAY_OF_MONTH, firstSelect!!.get(Calendar.DAY_OF_MONTH))
add(
Calendar.DAY_OF_MONTH,
DAY_OF_TERM
)
}
} else if (secondSelect == null) {
secondSelect = dayList[0]
}
}
if (secondSelect != null) {
if (calendar in firstSelect!!..TERM_CALENDAR) {
return true
}
return false
}
return if (firstSelect == null) {
true
} else {
calendar in firstSelect!!..TERM_CALENDAR
}
}
override fun describeContents(): Int {
return 0
}
override fun writeToParcel(dest: Parcel?, flags: Int) {
}
}
It is like this (valid from selected to 60days)

Related

How to add a local filter to calendar using kotlin?

private var modelList: ArrayList<PMDetailResponse.ResultBean>? = null
private var modelListUnchecked: ArrayList<PMDetailResponse.ResultBean>? = null
private lateinit var headerFilter: PMDetailResponse.ResultBean
private var mDetailAdapter: PMDetailAdapter? = null
lateinit var mPreventiveMaintenanceViewModel: PreventiveMaintenanceViewModel
//var mDetailAdapter!!.mAnythingChecked = false
var openedBy: String = ""
var runQuery:String = ""
var noDataReceived = false
companion object {
fun getInstance(): PMWorkOrderDueSoonFragment {
return PMWorkOrderDueSoonFragment()
}
}
private fun handleIncidentListApiResponse(
pmResponses: PMDetailResponse,
isHeaderNeedToAdd: Boolean
) {
mPMResponse = pmResponses
if (pmResponses.result != null) {
var lstResult =
pmResponses.result as ArrayList<PMDetailResponse.ResultBean>
modelList = lstResult
if (lstResult.size > 0) {
setAdapter(
lstResult as ArrayList<PMDetailResponse.ResultBean>,
isHeaderNeedToAdd
)
} else
showNoData(true)
} else
showNoData(true)
}
private fun showNoData(showNoData: Boolean) {
mBindingFragmentGroupBinding.pmAssignedToDeviceRecycerparent.listIncidentNoRecordTv.visibility =
if (showNoData) View.VISIBLE else View.GONE
mBindingFragmentGroupBinding.pmAssignedToDeviceRecycerparent.fragmentIncidentAssigntoHs.visibility =
if (showNoData) View.GONE else View.VISIBLE
}
private fun setAdapter(
lstResult: ArrayList<PMDetailResponse.ResultBean>,
isHeaderNeedToAdd: Boolean
) {
mDetailAdapter = PMDetailAdapter(
lstResult,
this,
true, false, mPreventiveMaintenanceViewModel
)
if (isHeaderNeedToAdd) {
mDetailAdapter!!.addHeader()
}
mBindingFragmentGroupBinding.pmAssignedToDeviceRecycerparent.fragmentIncidentAssigntoDashboardRv.adapter =
mDetailAdapter
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mBindingFragmentGroupBinding =
DataBindingUtil.inflate(
inflater,
R.layout.fragment_pm_assigned_to_device,
container,
false
)
return mBindingFragmentGroupBinding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mPMApiViewModel =
ViewModelProvider(this).get(PMApiViewModel::class.java)
mPreventiveMaintenanceViewModel =
ViewModelProvider(this).get(PreventiveMaintenanceViewModel::class.java)
setUIBackground()
setHasOptionsMenu(true)
mPMApiViewModel.callDuePMApi(PMAssignedStatus.DUE)
callPmDueWOObserver()
openedBy = SharedPreferenceManager.getString(
WeakReference<Context>(activity?.baseContext),
SharedPreferenceConstant.shared_pref_login_user_email
).toString()
}
private fun setUIBackground() {
if (AppConstants.themeColor == Color.WHITE) {
assign_layout.setBackgroundColor(Color.WHITE)
fragment_incident_assignto_dashboard_rv.setBackgroundColor(Color.WHITE)
//linear_layout_assigned_to_hs.setBackgroundColor(Color.WHITE)
//list_incident_no_record_tv.setTextColor(Color.BLACK)
} else {
assign_layout.setBackgroundColor(Color.BLACK)
fragment_incident_assignto_dashboard_rv.setBackgroundColor(Color.BLACK)
//linear_layout_assigned_to_hs.setBackgroundColor(Color.BLACK)
//list_incident_no_record_tv.setTextColor(Color.WHITE)
}
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
mMenu = menu
clearMenu()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
val exportMenuItem: MenuItem = menu.findItem(R.id.export_filter)
var feedBackSubmitTextView =
exportMenuItem.actionView.findViewById<Button>(R.id.button_export_bt)
feedBackSubmitTextView.setText(getString(R.string.dispatch_pm_to_me))
val exportActionView: View = exportMenuItem.getActionView()
exportActionView.setOnClickListener(object : View.OnClickListener {
override fun onClick(p0: View?) {
onOptionsItemSelected(exportMenuItem)
}
})
/* val awesomeMenuItem: MenuItem = menu.findItem(R.id.run_filter)
val awesomeActionView: View = awesomeMenuItem.getActionView()
awesomeActionView.setOnClickListener(object : View.OnClickListener {
override fun onClick(p0: View?) {
onOptionsItemSelected(awesomeMenuItem)
}
})*/
menu.findItem(R.id.run_filter).isVisible = true
menu.findItem(R.id.save_filter).isVisible = true
menu.findItem(R.id.save_filter).setIcon(resources.getDrawable(R.drawable.calendar));
menu.findItem(R.id.icons_menu).isVisible = true
menu.findItem(R.id.icons_menu).subMenu.findItem(R.id.action_barcode_scanner).isVisible =
false
menu.findItem(R.id.icons_menu).subMenu.findItem(R.id.attach).isVisible = false
menu.findItem(R.id.icons_menu).subMenu.findItem(R.id.action_soti_device_details).isVisible =
false
menu.findItem(R.id.icons_menu).subMenu.findItem(R.id.run_pm_filter).isVisible = false
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.export_filter -> {
Log.e("HistoricalFrag", "Export Button Selected")
if(!noDataReceived) {
if (mDetailAdapter!!.mAnythingChecked) {
val jsonArray = updateList()
val pmDispatchRequest: PMDispatchRequestArray = PMDispatchRequestArray(jsonArray)
Log.i("jsonArray", "jsonArray::$jsonArray")
//val workOrderObj = JSONObject()
// workOrderObj.put("DispatchInfoList", jsonArray)
//val jsonStr = jsonArray.toString()
//Log.i("TAG", "jsonStr::$jsonStr")
mDetailAdapter!!.mAnythingChecked = false
if (!jsonArray.isEmpty()) {
mPMApiViewModel.callPMDispatchToMe(pmDispatchRequest)
setObserverForDispatchToMeAPI()
} else {
showToast("Please Select The CheckBox")
}
} else {
showToast("Please Select The CheckBox")
}
}else{
showToast("Not allowed")
}
return true
}
R.id.run_filter -> {
if(!noDataReceived) {
runQuery = ""
mDetailAdapter!!.mAnythingChecked = false
var runQuery = runPMFilter()
if (runQuery.isNotEmpty()) {
mDetailAdapter!!.removeHeader()
mDetailAdapter!!.clear()
callPmDueFilterObserver()
mPMApiViewModel.callFilterDuePMApi(runQuery, PMAssignedStatus.FILTER)
} else {
showToast("No Filter Provided")
}
}else{
showToast("Not allowed")
}
return true
}
R.id.save_filter->{
pickFromDateTime()
return true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun clearMenu() {
mMenu.findItem(R.id.action_search).setVisible(false)
mMenu.findItem(R.id.action_settings).setVisible(false)
mMenu.findItem(R.id.action_incident).setVisible(false)
mMenu.findItem(R.id.export_filter).setVisible(true)
mMenu.findItem(R.id.run_filter).setVisible(true)
mMenu.findItem(R.id.icons_menu).setVisible(false)
}
private fun callPmDueWOObserver() {
if (mPMApiViewModel.callDuePMWorkOrderResponseObserver()
?.hasActiveObservers()!!
)
mPMApiViewModel.callDuePMWorkOrderResponseObserver()?.removeObserver(
pmResponseObserver
)!!
pmResponseObserver = Observer { value ->
if (mPMApiViewModel.mIsResponseforDuePmWorkOrder) {
if (value.apiStatus) {
showProgressDialog()
} else {
mPMApiViewModel.mIsResponseforDuePmWorkOrder = false
hideProgressDialog()
try {
if (value.response != null && !value.response.equals(getString(R.string.server_error))) {
if (value.response is PMDetailResponse) {
val mPmList =
value.response as PMDetailResponse
if (mPmList.result?.size!! > 0) {
handleIncidentListApiResponse(mPmList, true)
} else
showDialog(
getString(R.string.error_msg),
getString(R.string.no_response_server),
true
)
}
} else {
showToast(getString(R.string.server_error))
noDataReceived = true
showNoData(true)
}
} catch (ex: SocketTimeoutException) {
ex.printStackTrace()
LogOperation.getLogger().logInfo(
LogLevel.INFO_LOG,
"callPmDueWOObserver - Socket Time Out Exception : $ex"
)
showToast(getString(R.string.socket_timeout_error))
} catch (ex: Exception) {
ex.printStackTrace()
LogOperation.getLogger().logInfo(
LogLevel.INFO_LOG,
"callPmDueWOObserver - Exception : $ex"
)
showToast(getString(R.string.exception_error))
}
}
}
}
mPMApiViewModel.callDuePMWorkOrderResponseObserver()
?.observe(viewLifecycleOwner, pmResponseObserver)
}
private fun callPmDueFilterObserver() {
if (mPMApiViewModel.callFilterPMWorkOrderResponseObserver()
?.hasActiveObservers()!!
)
mPMApiViewModel.callFilterPMWorkOrderResponseObserver()?.removeObserver(
pmResponseObserver
)!!
pmResponseObserver = Observer { value ->
if (mPMApiViewModel.mIsResponseForFilterDuePMWO) {
if (value.apiStatus) {
showProgressDialog()
} else {
mPMApiViewModel.mIsResponseForFilterDuePMWO = false
hideProgressDialog()
try {
if (value.response != null && !value.response.equals(getString(R.string.server_error))) {
if (value.response is PMDetailResponse) {
val mPmList =
value.response as PMDetailResponse
if (mPmList.result?.size!! > 0) {
//handleIncidentListApiResponse(mPmList, true)
mDetailAdapter!!.clear()
mDetailAdapter!!.removeHeader()
mDetailAdapter!!.updateData(mPmList.result as ArrayList<PMDetailResponse.ResultBean>)
mDetailAdapter!!.addHeader()
mDetailAdapter!!.notifyDataSetChanged()
} else
showDialog(
getString(R.string.error_msg),
getString(R.string.no_response_server),
true
)
}
} else {
showToast(getString(R.string.server_error_loading_previous))
changeFragment(R.id.nav_drawer_pm_due_soon,Bundle(),false)
}
} catch (ex: SocketTimeoutException) {
ex.printStackTrace()
LogOperation.getLogger().logInfo(
LogLevel.INFO_LOG,
"callPmDueFilterObserver - Socket Time Out Exception : $ex"
)
showToast(getString(R.string.socket_timeout_error))
} catch (ex: Exception) {
ex.printStackTrace()
LogOperation.getLogger().logInfo(
LogLevel.INFO_LOG,
"callPmDueFilterObserver - Exception : $ex"
)
showToast(getString(R.string.exception_error))
}
}
}
}
mPMApiViewModel.callFilterPMWorkOrderResponseObserver()
?.observe(viewLifecycleOwner, pmResponseObserver)
}
private fun setObserverForDispatchToMeAPI() {
mPMApiViewModel.dispatchToMe()
?.observe(this, Observer { value ->
if (mPMApiViewModel.mIsFromDispatchApiCall) {
if (value.apiStatus) {
showProgressDialog()
} else {
mPMApiViewModel.mIsFromDispatchApiCall = false
hideProgressDialog()
try {
if (value.response is UpdateIncidentMessage) {
val responseValue = value.response as UpdateIncidentMessage
Log.d("CheckMyResponseValue", " - " + responseValue)
if (responseValue.result?.http_status?.equals("201")!!) {
if (modelListUnchecked!!.size == 0) {
mBindingFragmentGroupBinding.pmAssignedToDeviceRecycerparent.fragmentIncidentAssigntoDashboardRv!!.visibility =
View.GONE
}
//showToast("Dispatched ")
showDispatchDialog(
resources.getString(R.string.dispatch_msg),
responseValue.result?.status_message,true
)
} else if (responseValue.result?.http_status?.equals("400")!! ||
responseValue.result?.http_status?.equals("501")!!) {
mDetailAdapter!!.notifyDataSetChanged()
showDispatchDialog(
resources.getString(R.string.error_msg),
responseValue.result?.status_message,false
)
}
else {
showDispatchDialog(
resources.getString(R.string.error_msg),
resources.getString(R.string.update_error_msg),
false
)
}
}
} catch (ex: SocketTimeoutException) {
ex.printStackTrace()
LogOperation.getLogger().logInfo(
LogLevel.INFO_LOG,
"setObserverForDispatchToMeAPI - Socket Time Out Exception : $ex"
)
} catch (ex: Exception) {
ex.printStackTrace()
LogOperation.getLogger().logInfo(
LogLevel.INFO_LOG,
"setObserverForDispatchToMeAPI - Exception : $ex"
)
}
}
}
})
}
fun showDialog(title: String?, message: String?, stayOnSameScreen: Boolean) {
val dialogBuilder = AlertDialog.Builder(activity)
dialogBuilder.setMessage(message)
.setCancelable(false)
.setPositiveButton("Ok", DialogInterface.OnClickListener { dialog, id ->
dialog.dismiss()
if (stayOnSameScreen) {
backToPreviousFragment(true)
}
})
val alert = dialogBuilder.create()
alert.setTitle(title)
alert.show()
}
override fun onItemChangeListener(
position: Int,
model: PMDetailResponse.ResultBean
) {
try {
modelList!![position] = model
mDetailAdapter!!.mAnythingChecked = true
} catch (e: Exception) {
}
}
private fun updateList(): ArrayList<PMDispatchRequest> {
val temp = ArrayList<PMDetailResponse.ResultBean>()
val jsonArray = ArrayList<PMDispatchRequest>()
try {
for (i in modelList!!.indices) {
if (!modelList!![i].isChecked) {
temp.add(modelList!![i])
}else{
Log.i("TAG", "Number[" + i + "]::" + modelList!![i].number)
jsonArray?.add(createDispatchPMToMeQuery(modelList!![i].number))
}
}
} catch (e: Exception) {
}
modelListUnchecked = temp
/* mDetailAdapter!!.setModel(modelListUnchecked as ArrayList<PMDetailResponse.ResultBean>)
mDetailAdapter!!.notifyDataSetChanged()*/
return jsonArray
}
private fun createDispatchPMToMeQuery(number: String?): PMDispatchRequest {
/*{
"u_work_order_number": "WO0018180",
"u_subcategory": "Preventative Maintenance",
"u_category": "Device Maintenance",
"u_assign_to": "Kchawla#plan-group.com"
}*/
val workOrder = PMDispatchRequest(number,"Preventative Maintenance","Device Maintenance",openedBy)
return workOrder
}
fun createFilter(filterOptions: String, filterColumn: String) {
if(filterOptions != ""){
runQuery = if(filterOptions.startsWith("*")) {
if(runQuery == "")
filterColumn+"LIKE"+filterOptions.substring(1)
else
"$runQuery^"+filterColumn+"LIKE"+filterOptions.substring(1)
}else {
if (runQuery == "")
filterColumn+"STARTSWITH"+filterOptions
else
"$runQuery^"+filterColumn+"STARTSWITH"+filterOptions
}
}
}
fun createPMFrequencyFilter(filterOptions: String, filterColumn: String) {
var pmFilter = ""
if(filterOptions != ""){
pmFilter = pmFrequency(filterOptions)
runQuery = if(pmFilter.startsWith("*")) {
if(runQuery == "")
filterColumn+"IN"+ pmFilter.substring(1)
else
"$runQuery^"+filterColumn+"IN"+pmFilter.substring(1)
}else {
if (runQuery == "")
filterColumn+"IN"+pmFilter
else
"$runQuery^"+filterColumn+"IN"+pmFilter
}
}
}
private fun runPMFilter(): String {
createFilter(mDetailAdapter!!.searchedNumber,"number")
createFilter(mDetailAdapter!!.searchedCI,"cmdb_ci.name")
createFilter(mDetailAdapter!!.searchedDeviceLocation,"location.name")
createFilter(mDetailAdapter!!.searchedParent,"location.parent.name")
createFilter(mDetailAdapter!!.searchedDispatchLocation,"u_dispatch_location.name")
createFilter(mDetailAdapter!!.searchedRequestedDueBy,"requested_due_by")
createPMFrequencyFilter(mDetailAdapter!!.searchedPMFrequency,"u_pm_frequency")
createFilter(mDetailAdapter!!.searchedShortDesc,"short_description")
Log.i("TAG", "runQuery::"+runQuery)
if(runQuery.isNotEmpty()){
//val runQueryLength = runQuery.length
runQuery = runQuery.trim()
runQuery += "/"
}else{
runQuery = ""
}
Log.i("finalQuery", "runQueryFinal::"+runQuery)
return runQuery
}
fun pmFrequency(pmFrequency:String):String{
var pmFreq = ""
if(pmFrequency.startsWith("*")){
pmFreq = pmFrequency.substring(1)
}
else{
pmFreq = pmFrequency
}
if("Monthly".contains(pmFreq,ignoreCase = true)
&& "Yearly".contains(pmFreq,ignoreCase = true)){
pmFreq = "Yearly,Monthly"
}else if("Yearly".contains(pmFreq,ignoreCase = true)){
pmFreq = "Yearly"
}else if("Monthly".contains(pmFreq,ignoreCase = true)){
//pmFreq = "*Monthly"
pmFreq = "Monthly"
}
return pmFreq
}
fun showDispatchDialog(title: String?, message: String?,isSuccess:Boolean) {
val dialogBuilder = AlertDialog.Builder(activity)
dialogBuilder.setMessage(message)
.setCancelable(false)
.setPositiveButton(getString(R.string.ok), DialogInterface.OnClickListener { dialog, id ->
if(!isSuccess) {
mDetailAdapter!!.setModel(modelList as ArrayList<PMDetailResponse.ResultBean>)
mDetailAdapter!!.notifyDataSetChanged()
}
else{
mDetailAdapter!!.setModel(modelListUnchecked as ArrayList<PMDetailResponse.ResultBean>)
mDetailAdapter!!.notifyDataSetChanged()
}
dialog.dismiss()
changeFragment(R.id.nav_drawer_pm_due_soon,Bundle(),false)
//backToPreviousFragment(false)
})
val alert = dialogBuilder.create()
alert.setTitle(title)
alert.show()
}
private fun pickFromDateTime() {
val currentDateTime = Calendar.getInstance()
val startYear = currentDateTime.get(Calendar.YEAR)
val startMonth = currentDateTime.get(Calendar.MONTH)
val startDay = currentDateTime.get(Calendar.DAY_OF_MONTH)
val startHour = currentDateTime.get(Calendar.HOUR_OF_DAY)
val startMinute = currentDateTime.get(Calendar.MINUTE)
var mFromDatePicker = DatePickerDialog(requireContext(), DatePickerDialog.OnDateSetListener { _, year, month, day ->
TimePickerDialog(requireContext(), TimePickerDialog.OnTimeSetListener { _, hour, minute ->
val pickedDateTime = Calendar.getInstance()
pickedDateTime.set(year, month, day, hour, minute)
val formatterDateTime = SimpleDateFormat("yyyy-MM-dd HH mm ss")
val formatterDate = SimpleDateFormat("yyyy-MM-dd")
var selectedFromDateTime = formatterDateTime.format(pickedDateTime.time)
var selectedFromDate = formatterDate.format(pickedDateTime.time)
Log.i(ContentValues.TAG, "selectedFromDateTime::$selectedFromDateTime")
pickToDateTime(selectedFromDateTime)
}, startHour, startMinute, false).show()
/*val pickedDateTime = Calendar.getInstance()
pickedDateTime.set(year, month, day)
doSomethingWith(pickedDateTime)*/
}, startYear, startMonth, startDay);
mFromDatePicker.setTitle("FROM");
mFromDatePicker.datePicker.maxDate = System.currentTimeMillis();
mFromDatePicker.show()
}
private fun pickToDateTime(selectedDateTime1: String) {
val currentDateTime = Calendar.getInstance()
val startYear = currentDateTime.get(Calendar.YEAR)
val startMonth = currentDateTime.get(Calendar.MONTH)
val startDay = currentDateTime.get(Calendar.DAY_OF_MONTH)
val startHour = currentDateTime.get(Calendar.HOUR_OF_DAY)
val startMinute = currentDateTime.get(Calendar.MINUTE)
var mToDatePicker = DatePickerDialog(requireContext(), DatePickerDialog.OnDateSetListener { _, year, month, day ->
TimePickerDialog(requireContext(), TimePickerDialog.OnTimeSetListener { _, hour, minute ->
val pickedDateTime = Calendar.getInstance()
pickedDateTime.set(year, month, day, hour, minute)
val formatterDateTime = SimpleDateFormat("yyyy-MM-dd HH mm ss")
var selectedFromDateTime = formatterDateTime.format(pickedDateTime.time)
Log.i(ContentValues.TAG, "selectedToDateTime::$selectedFromDateTime")
}, startHour, startMinute, false).show()
/* val pickedToDateTime = Calendar.getInstance()
pickedToDateTime.set(year, month, day)
doCallChangeFragment(selectedDateTime, pickedToDateTime)*/
}, startYear, startMonth, startDay);
mToDatePicker.setTitle("TO");
mToDatePicker.datePicker.maxDate = System.currentTimeMillis();
mToDatePicker.show()
}
}
This code is being used to pick up from date,time and to date, time using calender feature for filtering data for particular period but the data is not getting filtered, the data for all the month is being displayed .So I need to add local filter for filtering data according to specific date and time using calendar feature.

Android Kotlin load only one more element to recyclerview problem

I want to load just one element with one scroll gesture. Now it is like one scroll gesture loads 1 or few new elements (depends on time of scroll gesture). As a solution I could do this gesture in shorter time than 500ms or make this postDelayed's delay longer but I guess there are better solutions for that. Do you have any ideas how to do that?
This app is written in MVP pattern. Here is my code:
CurrencyFragmentList.kt
private fun addScrollerListener() {
rvItem.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(_rvItem: RecyclerView, newState: Int) {
super.onScrollStateChanged(_rvItem, newState)
Log.e("scroll", isLoading.toString())
if (!isLoading) {
if (!_rvItem.canScrollVertically(1)) {
loadMore()
isLoading = true
}
}
}
})
}
private fun loadMore() {
showProgressDialog()
var numberOfDays = mainPresenter.getNumberOfMinusDays()
numberOfDays++
mainPresenter.saveNumberOfMinusDaysIntoSp(numberOfDays)
var dateMinusXDays = mainPresenter.currentDateMinusXDaysToStr(numberOfDays)
val nextLimit = listSize + 1
for (i in listSize until nextLimit) {
if (mainPresenter.checkIfSuchDateExistsinSp(dateMinusXDays)) {
Log.d("such date already exists in shared prefs", dateMinusXDays)
handler.postDelayed({
mainPresenter.processDateWithoutMakingACall(dateMinusXDays)
}, 500)
} else {
mainPresenter.makeACall(dateMinusXDays)
Log.d("retrofit call made", dateMinusXDays)
}
}
itemAdapter.notifyDataSetChanged()
}
override fun hideProgressDialog() {
if (apiResponseList.size > 1) {
apiResponseList.removeAt(apiResponseList.size - 1)
listSize = apiResponseList.size
itemAdapter.notifyItemRemoved(listSize)
} else progress_bar.visibility = View.GONE
isLoading = false
}
override fun assignResponseToRecyclerview(apiResponse: ApiResponse?) {
rvItem.apply {
layoutManager = _layoutManager
apiResponseList.add(apiResponse!!)
itemAdapter = activity?.let { ItemAdapter(apiResponseList, it) }!!
adapter = itemAdapter
}
Log.e("assign", isLoading.toString())
}
MainPresenter.kt
override fun makeACall(date: String?) {
//view.showProgressDialog()
date?.let { restModel.fetchApiResponse(this, it) }
}
fun processDateWithoutMakingACall(date: String) {
val apiResponse = processRawJson(sp.getString(date, "").toString())
passResponseToView(apiResponse)
}
override fun processRawJson(rawJson: String): ApiResponse {
val parser = JsonParser()
val rootObj = parser.parse(rawJson).asJsonObject
var ratesObj = JsonObject()
var ratesKeys: Set<String> = HashSet()
val ratesArrayList: ArrayList<Currency> = ArrayList()
val rootKeys = rootObj.keySet();
var baseValue = ""
var dateValue = ""
for (key in rootKeys) {
if (key == "base")
baseValue = rootObj.get(key).asString
if (key == "date")
dateValue = rootObj.get(key).asString
if (key == "rates") {
ratesObj = rootObj.get(key).asJsonObject
ratesKeys = ratesObj.keySet()
}
}
for (key2 in ratesKeys) {
Log.e("ratesKey", key2)
Log.e("ratesValue", ratesObj.get(key2).asFloat.toString())
ratesArrayList.add(Currency(key2, ratesObj.get(key2).asFloat))
}
saveRawJsonIntoSp(rawJson, dateValue)
return ApiResponse(baseValue, dateValue, ratesArrayList, false)
}
override fun passResponseToView(apiResponse: ApiResponse?) {
view.hideProgressDialog()
view.assignResponseToRecyclerview(apiResponse)
}
RestModel.kt
override fun fetchApiResponse(presenter: MainPresenter, date: String) {
job = CoroutineScope(Dispatchers.IO).launch {
val response = userService.getCurrenciesForDate(date)
withContext(Dispatchers.Main) {
if (response.isSuccessful) {
val rawJson = response.body()
val apiResponse = presenter.processRawJson(rawJson)
presenter.passResponseToView(apiResponse)
}
}
}
}
Any help will be really appreciated. Thank you in advance!
Try out the SnapHelper, it might slow layout manager to make more callbacks and stop overloading

Print all items in Recyclerview to pdf file

I have been stuck on this for over 2 weeks. I tried everything and search everywhere but nothing worked.
I have an android app with sqlite database.
I made a recyclerview with a custom adapter because every item in the recyclerview consists of 80 Textviews.
I want to print every row of the recyclerview in a seperate page but in the same document. when I try to print the rows of recyclerview, I get only the visible rows on the screen which is the first and the second row only while my recyclerview consists of at least 10 to 20 rows. I'm using the latest version of android studio and Kotlin.
here is what I have so far
this is my custom Adapter
class BianProductsAdapter(mCtx: Context,val bianproducts: ArrayList<LV_BProducts>) : RecyclerView.Adapter<BianProductsAdapter.ViewHolder>() {
val mCtx = mCtx
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val lbpid = itemView.bianproductid
val lbpproductname = itemView.bianproductname
val lbpproductunit = itemView.bianproductunit
val lbpproductquantity = itemView.bianproductquantity
val lbpproductoriginalprice = itemView.bianproductoriginalprice
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BianProductsAdapter.ViewHolder {
val v : View= LayoutInflater.from(parent.context).inflate(R.layout.lo_b_products,parent,false)
return BianProductsAdapter.ViewHolder(v)
}
override fun onBindViewHolder(holder: BianProductsAdapter.ViewHolder, position: Int) {
val df = DecimalFormat("###,###,##0.00")
val bianproduct : LV_BProducts = bianproducts[position]
holder.lbpid.text = bianproduct.lvbp_id.toString()
holder.lbpproductname.text = bianproduct.lvbp_product_name.toString()
holder.lbpproductunit.text = bianproduct.lvbp_unit.toString()
holder.lbpproductquantity.text = bianproduct.lvbp_quantity.toString()
holder.lbpproductoriginalprice.text = "$"+ df.format(bianproduct.lvbp_original_price.toFloat())
}
override fun getItemCount(): Int {
return bianproducts.size
}
}
and this is Activity.kt`
class BProductsActivity : AppCompatActivity() {
inner class MyPrintDocumentAdapter(private var context: Context)
: PrintDocumentAdapter() {
private var pageHeight: Int = 0
private var pageWidth: Int = 0
private var myPdfDocument: PdfDocument? = null
private fun drawPage(
page: PdfDocument.Page,
pagenumber: Int
) {
var pagenum = pagenumber
val canvas = page.canvas
pagenum++
val titleBaseLine = 72
val leftMargin = 54
val paint = Paint()
paint.color = Color.BLACK
val pageInfo = page.info
}
private fun pageInRange(pageRanges: Array<PageRange>, page: Int): Boolean {
for (i in pageRanges.indices) {
if (page >= pageRanges[i].start && page <= pageRanges[i].end)
return true
}
return false
}
override fun onLayout(
oldAttributes: PrintAttributes?,
newAttributes: PrintAttributes?,
cancellationSignal: android.os.CancellationSignal?,
callback: LayoutResultCallback?,
extras: Bundle?
) {
myPdfDocument = newAttributes?.let { PrintedPdfDocument(context, it) }
val height = newAttributes?.mediaSize?.heightMils
val width = newAttributes?.mediaSize?.heightMils
height?.let {
pageHeight = it / 1000 * 72
}
width?.let {
pageWidth = it / 1000 * 72
}
if (cancellationSignal != null) {
if (cancellationSignal.isCanceled) {
if (callback != null) {
callback.onLayoutCancelled()
}
return
}
}
if (totalpages > 0) {
val builder =
PrintDocumentInfo.Builder("print_output.pdf").setContentType(
PrintDocumentInfo.CONTENT_TYPE_DOCUMENT
)
.setPageCount(totalpages)
val info = builder.build()
if (callback != null) {
callback.onLayoutFinished(info, true)
}
} else {
if (callback != null) {
callback.onLayoutFailed("Page count is zero.")
}
}
}
override fun onWrite(
pages: Array<out PageRange>?,
destination: ParcelFileDescriptor?,
cancellationSignal: android.os.CancellationSignal?,
callback: WriteResultCallback?
) {
for (i in 0 until totalpages) {
if (pageInRange(pages as Array<PageRange>, i)) {
val newPage = PdfDocument.PageInfo.Builder(
pageWidth,
pageHeight, i
).create()
if (cancellationSignal != null) {
if (cancellationSignal.isCanceled) {
if (callback != null) {
callback.onWriteCancelled()
}
myPdfDocument?.close()
myPdfDocument = null
return
}
}
val page = myPdfDocument?.startPage(newPage)
val content: View = mybprv.get(i) //mybprv is the ID of my recyclerview
val measureWidth = View.MeasureSpec.makeMeasureSpec(
page!!.canvas.width,
View.MeasureSpec.EXACTLY
)
val measuredHeight = View.MeasureSpec.makeMeasureSpec(
page.canvas.height,
View.MeasureSpec.EXACTLY
)
content.measure(measureWidth, measuredHeight)
content.layout(0, 0, page.canvas.width, page.canvas.height)
if (page != null) {
content.draw(page.canvas)
}
myPdfDocument?.finishPage(page)
}
}
try {
if (destination != null) {
myPdfDocument?.writeTo(
FileOutputStream(
destination.fileDescriptor
)
)
}
} catch (e: IOException) {
if (callback != null) {
callback.onWriteFailed(e.toString())
}
return
} finally {
myPdfDocument?.close()
myPdfDocument = null
}
if (callback != null) {
callback.onWriteFinished(pages)
}
}
}
fun printDocument(view: View) {
val printManager = this.getSystemService(Context.PRINT_SERVICE) as PrintManager
val jobName = this.getString(R.string.app_name) + " Document"
printManager.print(jobName, MyPrintDocumentAdapter(this), null)
}
companion object{
lateinit var bpdbHandler: DBHandler
private var totalpages =0
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_b_products)
bpdbHandler = DBHandler(this,null,null,1)
populateList()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
//return super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.addbianproduct,menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId==R.id.bainproductpage){
printDocument(mybprv) // mybprv is the id of my recyclerview
}
return super.onOptionsItemSelected(item)
}
override fun onResume() {
super.onResume()
populateList()
}
private fun populateList() {
val productslist : ArrayList<LV_BProducts>? = intent.getStringExtra("bid")?.let { bpdbHandler.getBianProducts(this, it) }
val adapter = productslist?.let { BianProductsAdapter(this, it) }
val rv : RecyclerView = findViewById(R.id.mybprv)
rv.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL,false)
rv.adapter = adapter
rv.isNestedScrollingEnabled = false
if (productslist != null) {
totalpages = productslist.size
}
}
}
I get the exact records I want from the query and I can show all these records data in the recyclerview. My only problem is printing the recyclerview.
the number of pages printed = the number of rows returned by my query = the number of rows in my recyclerview
However, only visible rows which are row 1 and 2 get printed and the remaining pages are either a repetation of row 2 or empty
All your help is highly appreciated.
P.S: I know my code looks messy because it is a mix of two weeks searching and applying solutions from multiple sources until I got stuck where I am now.

Resetting values each day to 0 in Kotlin, Android Studio?

I'm having problem with my step counter, I want it to reset to 0 every time the date changes.
I tried doing something like this:
if (currentDate != savedDate) {
previousSteps = totalSteps
tv_totalSteps.text = 0.toString()
saveData()
}
but I just couldn't seem to get it to work for some reason. I'm sure the answer is obvious somewhere in my code, but I've been trying different things for about 2 hours now. So any help would be very much appreciated here. Here's my whole code:
private var sensorManager: SensorManager? = null
private var running = false
private var totalSteps = 0f
private var previousSteps = 0f
var currentSteps = 0
var goalSteps = 5000
private var cal = Calendar.getInstance()
private var currentDate = cal.get(Calendar.DAY_OF_YEAR)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//needs to be called later
loadData()
resetSteps()
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
}
override fun onResume() {
super.onResume()
running = true
val stepsSensor = sensorManager?.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
if (stepsSensor == null) {
Toast.makeText(this, "No sensor detected", Toast.LENGTH_SHORT).show()
} else {
sensorManager?.registerListener(this, stepsSensor, SensorManager.SENSOR_DELAY_UI)
}
}
override fun onAccuracyChanged(p0: Sensor?, p1: Int) {
}
override fun onSensorChanged(event: SensorEvent) {
if (running) {
totalSteps = event.values[0]
currentSteps = totalSteps.toInt() - previousSteps.toInt()
tv_totalSteps.text = ("$currentSteps")
progress_circular.apply {
setProgressWithAnimation(currentSteps.toFloat())
}
progress_circular_outer_ring.apply {
setProgressWithAnimation(totalSteps)
}
val caloriesBurned = totalSteps * .0228f
tv_calories.text = "${caloriesBurned.toInt()} calories"
tv_distance_walked.text = "${currentSteps} steps"
tv_totalDistanceWalked.text = "${(totalSteps* 0.00076f).toInt()} km"
tv_totalStepsTaken.text = "${totalSteps.toInt()} steps"
progress_circular_calories.apply {
setProgressWithAnimation(caloriesBurned)
}
}
}
private fun resetSteps() {
tv_totalSteps.setOnClickListener {
Toast.makeText(this, "Long hold to reset steps", Toast.LENGTH_SHORT).show()
}
tv_totalSteps.setOnLongClickListener {
previousSteps = totalSteps
tv_totalSteps.text = 0.toString()
saveData()
true
}
tv_totalStepsMax.setOnClickListener {
tv_totalStepsMax.visibility = View.GONE
et_totalStepsMax.visibility = View.VISIBLE
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(et_totalStepsMax, 0)
}
rL_wrapper.setOnClickListener {
tv_totalStepsMax.visibility = View.VISIBLE
et_totalStepsMax.visibility = View.GONE
if (et_totalStepsMax.text != null && et_totalStepsMax.text.toString().isNotEmpty()) {
goalSteps = Integer.parseInt(et_totalStepsMax.text.toString())
tv_totalStepsMax.text = goalSteps.toString()
progress_circular.progressMax = goalSteps.toFloat()
saveData()
} else {
return#setOnClickListener
}
val inputMethodManager =
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(et_totalStepsMax.windowToken, 0)
}
}
override fun onPause() {
super.onPause()
saveData()
}
private fun saveData() {
val sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putFloat("key1", previousSteps)
editor.putInt("goalKey", goalSteps)
editor.putInt("DATE_KEY", currentDate)
Log.d("MainActivity", "Today is $currentDate")
editor.apply()
}
private fun loadData() {
val sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
val savedNumber = sharedPreferences.getFloat("key1", 0f)
val goalNumber = sharedPreferences.getInt("goalKey", 0)
val savedDate = sharedPreferences.getInt("DATE_KEY", 0)
Log.d("MainActivity", "Saved date is $savedDate")
if (currentDate != savedDate) {
previousSteps = totalSteps
tv_totalSteps.text = 0.toString()
saveData()
}
Log.d("MainActivity", "$savedNumber")
goalSteps = goalNumber
tv_totalStepsMax.text = goalSteps.toString()
previousSteps = savedNumber
}
}
You are just rewriting tv_totalStepsMax.text = goalSteps.toString() after resetting the value tv_totalSteps.text = 0.toString().
The code should look like:
if (currentDate != savedDate) {
tv_totalSteps.text = 0.toString()
...
saveData()
} else {
tv_totalStepsMax.text = goalSteps.toString()
...
}

How to remove the logic from ViewModel and move to Repository

I have this piece of code which is checking if it is close to the start time and if no repeats until it is started
I want to have less logic in ViewModel how can I refactor this piece of code?
uiScope.launch {
when (val unixTimeMillisecond = serverTimeFetcher.fetchUnixTime()) {
is Response.Success<Long> -> {
var title = "Play"
val startTimeMillis = FULL_DATE_FORMAT.parse(startTime).time
if (startTimeMillis > unixTimeMillisecond.data) {
val difference = startTimeMillis - unixTimeMillisecond.data
title = DURATION_FORMAT.format(Duration.millis(difference))
liveEventActionTitleMutableData.postValue(title)
delay(UPDATE_INTERVAL)
checkLiveEventStatus(startTime)
} else {
liveEventActionTitleMutableData.postValue(title)
}
}
is Response.Failure -> errorMessageMutableData.postValue(unixTimeMillisecond.message)
}
}
}
override suspend fun fetchUnixTime(): Response<Long> {
var timeDifference = apiPreferences.getLong("PREF_TIME_DIFFERENCE", -1)
val currentTimeMillis = System.currentTimeMillis()
return if (timeDifference == -1L) {
when (val serverTimeResult = fetchServerTime()) {
is Response.Success<ServerTime> -> {
val epochMillis = serverTimeResult.data.epochMillis
timeDifference = currentTimeMillis - epochMillis
apiPreferences.edit().putLong("PREF_TIME_DIFFERENCE", timeDifference).apply()
(Response.Success((epochMillis)))
}
else -> Response.Failure("error message")
}
} else {
val epochMillis = currentTimeMillis - timeDifference
Response.Success(epochMillis)
}
}

Categories

Resources