How to remove the logic from ViewModel and move to Repository - android

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)
}
}

Related

Why is lifecycleScope.launch not even working in the background?

First I gave the exerciseList a null value then inside the lifecycleScope I feched data from a preloaded database but why am I still getting null pointer exception on calling the exerciseList variable?
private var exerciseList: ArrayList<Exercise>? = null
lifecycleScope.launch {
exerciseList = getExerciseListBySetName(exListName!!)
setUpUiAndExerciseStatusRV()
}
private suspend fun getExerciseListBySetName(exListName: String): ArrayList<Exercise> {
val allExerciseList = Constants.getAllExerciseList()
var ans = ArrayList<Exercise>()
when (exListName) {
Constants.MISCELLANEOUS_LIST -> {
val miscellaneousExercisesDao = (application as HelloHealthyApp).miscellaneousExercisesDb.miscellaneousExercisesDao()
miscellaneousExercisesDao.fetchAllMiscellaneousExercises().collect {
val list = ArrayList(it)
for (i in list) {
ans.add(allExerciseList[i.toInt()])
}
}
}
else -> {
ans = ArrayList()
}
}
for(exercise in ans) {
exercise.setIsSelected(false)
exercise.setIsCompleted(false)
}
return ans
}
private fun setUpUiAndExerciseStatusRV() {
var i = 0
while (i < exerciseList?.size!!) {
exercisesArrStr = if (i == exerciseList?.size!! - 1) {
"$exercisesArrStr${exerciseList?.get(i)?.getId().toString()}"
} else {
"$exercisesArrStr${exerciseList?.get(i)?.getId().toString()},"
}
i++
}
exerciseRVAdapter = ExerciseStatusAdapter(exerciseList!!)
binding?.rVExerciseStatus?.layoutManager =
LinearLayoutManager(this#ExerciseActivity, LinearLayoutManager.HORIZONTAL, false)
binding?.rVExerciseStatus?.adapter = exerciseRVAdapter
exerciseRVAdapter?.notifyDataSetChanged()
binding?.exerciseImgView?.setImageResource(
exerciseList?.get(currentExercisePosition)?.getImage()!!
)
binding?.tVTitle?.text = exerciseList?.get(currentExercisePosition)?.getName()
binding?.upcomingExerciseTextView?.visibility = View.GONE
}

How to validate Material RangeDatePicker from first selection(point) in 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)

Clear button on calculator App using Kotlin

I'm basically making a simple calculator app using Kotlin. I'm very new to programming so I'm not familiar with Java either.
Basically the app runs and I'm also attaching a screenshot of the App's layout along with the code on MainActivity. Everything works fine except the clear button. Ideally, I want the clear button to reset the value on the 1st widget(results widget) and let me start a new calculation. Like how a AC button works on a regular calculator. However, all it does is clear the value. It doesn't clear the calculation. When I select the next calculation it still adds/subtracts/multiplies/divides to the previous value that's already there in the results widget. It doesn't let me start a new calculation like how I would be able to do if I pressed AC on a regular calculator.
Hope what i'm saying makes sense. Please tell me how can I make this work. And again, I'm very new to programming so would really really appreciate it if someone can help me.
package academy.learnprogramming.calculator
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
private const val TAG = "MainActivity"
private const val STATE_PENDING_OPERATION = "PendingOperation"
private const val STATE_OPERAND1 = "Operand1"
private const val STATE_OPERAND1_STORED = "Operand1_Stored"
class MainActivity : AppCompatActivity() {
private var operand1: Double? = null
private var operand2: Double = 0.0
private var pendingOperation = "="
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val listener = View.OnClickListener { v ->
val b = v as Button
newNumber.append(b.text)
}
button0.setOnClickListener(listener)
button1.setOnClickListener(listener)
button2.setOnClickListener(listener)
button3.setOnClickListener(listener)
button4.setOnClickListener(listener)
button5.setOnClickListener(listener)
button6.setOnClickListener(listener)
button7.setOnClickListener(listener)
button8.setOnClickListener(listener)
button9.setOnClickListener(listener)
buttonDot.setOnClickListener(listener)
val opListener = View.OnClickListener { v ->
val op = (v as Button).text.toString()
try {
val value = newNumber.text.toString().toDouble()
performOperation(value, op)
} catch (e: NumberFormatException) {
newNumber.setText("")
}
pendingOperation = op
operation.text = pendingOperation
}
buttonEquals.setOnClickListener(opListener)
buttonDivide.setOnClickListener(opListener)
buttonMultiply.setOnClickListener(opListener)
buttonMinus.setOnClickListener(opListener)
buttonPlus.setOnClickListener(opListener)
buttonNegative.setOnClickListener { view ->
val value = newNumber.text.toString()
if (value.isEmpty()) {
newNumber.setText("-")
} else {
try {
var doubleValue = value.toDouble()
doubleValue *= -1
newNumber.setText(doubleValue.toString())
} catch (e: NumberFormatException) {
newNumber.setText("")
}
}
}
val value = newNumber.text.toString()
buttonClear.setOnClickListener { view ->
val value = 0
if (value == 0){
result.setText("")
}
}
}
private fun performOperation(value: Double, operation: String) {
if (operand1 == null) {
operand1 = value
} else {
operand2 = value
if (pendingOperation == "=") {
pendingOperation = operation
}
when (pendingOperation) {
"=" -> operand1 =
operand2
"/" -> if (operand2 == 0.0) {
operand1 = Double.NaN
} else {
operand1 =
operand1!! / operand2
}
"*" -> operand1 = operand1!! * operand2
"-" -> operand1 = operand1!! - operand2
"+" -> operand1 = operand1!! + operand2
}
}
result.setText(operand1.toString())
newNumber.setText("")
}
override fun onSaveInstanceState(outState: Bundle) {
Log.d(TAG, "onSaveInstanceState: Called")
super.onSaveInstanceState(outState)
if (operand1 != null) {
outState.putDouble(
STATE_OPERAND1,
operand1!!
)
outState.putBoolean(
STATE_OPERAND1_STORED,
true
)
}
outState.putString(STATE_PENDING_OPERATION, pendingOperation)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
if (savedInstanceState.getBoolean(
STATE_OPERAND1_STORED,
false
)
) {
operand1 = savedInstanceState.getDouble(STATE_OPERAND1)
} else {
operand1 = null
}
pendingOperation = savedInstanceState.getString(STATE_PENDING_OPERATION, "=")
operation.text = pendingOperation
}
}
Try resetting the values of operand1 and operand2
buttonClear.setOnClickListener { view ->
val value = 0
operand1 = null
operand2 = 0.0
if (value == 0){
result.setText("")
}
}

WorkManager beginUniqueWork queue not getting called after first work

I'm using WorkManager 1.0.0-alpha02
I've created my worker class like:
class PrintWorker: Worker(){
override fun doWork(): WorkerResult {
try {
val label: String = inputData.getString(LABEL_ARG_CONTENIDO, null)
val isLastLabel: Boolean = inputData.getBoolean(LABEL_ARG_IS_LAST,false)
var result = Printer(applicationContext).print(label)
var outPut: Data = Data.Builder().putString("PrinterResponse",result.printerResponse).putBoolean(LABEL_ARG_IS_LAST,isLastLabel).build()
outputData = outPut
return result.workResult
}catch (e: Exception){
return WorkerResult.FAILURE
}
}
companion object {
const val LABEL_ARG_CONTENIDO = "Label"
const val LABEL_ARG_IS_LAST = "Position"
}
}
and then in my viewmodel I've schedulled the work chain like:
var myQueue: WorkContinuation? = null
for (label in labelEntities){
val newPrintWork = OneTimeWorkRequest.Builder(PrintWorker::class.java)
val builder = Data.Builder()
var data: Data
builder.putString(PrintWorker.LABEL_ARG_CONTENIDO, label.contenido)
if(myQueue == null){
data = builder.build()
newPrintWork.setInputData(data)
myQueue = WorkManager.getInstance().beginUniqueWork(printWorkId,ExistingWorkPolicy.REPLACE,newPrintWork.build())
}
else{
if(labelEntities.indexOf(label) == labelEntities.size - 1)
builder.putBoolean(PrintWorker.LABEL_ARG_IS_LAST, true)
data = builder.build()
newPrintWork.setInputData(data)
myQueue.then(newPrintWork.build())
}
}
myQueue?.enqueue()
finally in another piece of code I'm observing it with:
viewmodel.printStatus.observe(this, Observer { works ->
if(works!= null){
if(works.filter { it.state == State.FAILED}.isNotEmpty()){
MyWorkManager().cancelPrinting()
context?.let { showDialog(MyAlertDialogManager(it).noMacAddressErrorDialog()) }
}
if(works.filter { it.state == State.SUCCEEDED }.size == works.size &&
works.isNotEmpty() &&
works.filter { it.outputData.getBoolean(LABEL_ARG_IS_LAST,false) }.isNotEmpty()){
context?.let { showDialog(MyAlertDialogManager(it).confirmPrintedCorrectly(factura,this)) }
}
}
})
The first work gets done right after enqueueing and returns Worker.WorkerResult.SUCCESS but the rest of the chain doesnt gets called

String request in Kotlin class

I m new in Kotlin and I'm trying to do a string request (with volley library and PHP)
I did this (like a Java)
val addUrl = "myurl"
val queue = Volley.newRequestQueue(this)
val postRequest = object : StringRequest(Request.Method.POST, addUrl,
Response.Listener<String> { response ->
//Toast.makeText(this, response, Toast.LENGTH_SHORT).show()
}, Response.ErrorListener {
//Toast.makeText(this, "Something wrong", Toast.LENGTH_SHORT).show()
}) {
override fun getParams(): Map<String, String> {
val params = HashMap<String, String>()
params.put("uid", uid.toString())
return params
}
}
queue.add(postRequest)
and I have error at this point
val queue = Volley.newRequestQueue(this)
Because say that I can't use "this"
Type mismatch: inferred type is DataContainer but Context! was
expected
My data container don't extend AppCompatActivity(): so I can't use a "this#Activity" as another suggestion find online
This is the companion object
class DataContainer {
val noH = 32
val TAG = "DataContainer"
private var mDb : GlucoseDataBase
private val lock = java.lang.Object()
private var lastTimeStamp : Int = 0
private val user = FirebaseAuth.getInstance().currentUser
var uid:String? = null.toString()
//private var raw_data : ByteArray = byteArrayOf()
private var readings : MutableList<ByteArray> = mutableListOf()
constructor(context : Context) {
mDb = GlucoseDataBase.getInstance(context)
}
fun append(raw_data: ByteArray, readingTime: Long, sensorId : Long) {
user?.let {
// Name, email address, and profile photo Url
//val name = user.displayName
//val email = user.email
//val photoUrl = user.photoUrl
// Check if user's email is verified
//val emailVerified = user.isEmailVerified
// The user's ID, unique to the Firebase project. Do NOT use this value to
// authenticate with your backend server, if you have one. Use
// FirebaseUser.getToken() instead.
uid = user.uid
}
synchronized(lock) {
readings.add(raw_data.copyOf())
val timestamp = RawParser.timestamp(raw_data)
if (timestamp == 0) {
mDb.sensorContactDao().insert(SensorContact(0, readingTime, sensorId, 0, 0))
return
}
// Timestamp is 2 mod 15 every time a new reading to history is done.
val minutesSinceLast = (timestamp + 12) % 15
val start = readingTime - Time.MINUTE * (15 * (noH - 1) + minutesSinceLast)
val now_history = RawParser.history(raw_data)
val now_recent = RawParser.recent(raw_data)
Log.i("UID", uid.toString());
val history_prepared = prepare(now_history, sensorId, 15 * Time.MINUTE, start, minutesSinceLast != 14 && timestamp < Time.DURATION_MINUTES, true)
val data = history_prepared.toList();
// val data2= data[0] //primo elemento più vecchio (di timestamp) //proviamo con history[0]??
//val data2 = data[0].value // elemento valore dell più vecchio
Log.i("Data History full p", data.toString());
//Log.i("Data history prepared",data2.toString());
val start_recent =
if (history_prepared.isEmpty()) {
val last = mDb.glucoseEntryDao().getLast(sensorId, true)
if (last != null) {
min(last.utcTimeStamp, readingTime - 16 * Time.MINUTE)
} else {
readingTime - 16 * Time.MINUTE
}
} else {
min(readingTime - 16 * Time.MINUTE, history_prepared.last().utcTimeStamp)
}
val recent_prepared = prepare(now_recent, sensorId, 1 * Time.MINUTE, start_recent, true, false)
val added = extend(recent_prepared) + extend(history_prepared)
mDb.sensorContactDao().insert(SensorContact(0, sensorId, readingTime, timestamp, added))
Log.i("Data recent prepared",recent_prepared.toString());
//creating volley string request
lastTimeStamp = timestamp
}
val addUrl = "myrurl"
val queue = Volley.newRequestQueue()
val postRequest = object : StringRequest(Request.Method.POST, addUrl,
Response.Listener<String> { response ->
//Toast.makeText(this, response, Toast.LENGTH_SHORT).show()
}, Response.ErrorListener {
//Toast.makeText(this, "Something wrong", Toast.LENGTH_SHORT).show()
}) {
override fun getParams(): Map<String, String> {
val params = HashMap<String, String>()
params.put("uid", uid.toString())
return params
}
}
queue.add(postRequest)
}
fun get_sz_raw_data() : Int {
return readings.size
}
fun get_raw_data(i: Int) : ByteArray{
synchronized(lock){
if(0<= i && i < readings.size)
return readings[i]
else
return byteArrayOf()
}
}
fun insert(v: List<GlucoseEntry>) {
synchronized(lock){
if(size() != 0) return
for(g in v) {
mDb.glucoseEntryDao().insert(g)
}
}
Log.d(TAG, String.format("inserted %d vales into database", v.size))
}
private fun extend(v: List<GlucoseReading>) : Int {
synchronized(lock) {
val toExtend = v.filter { g: GlucoseReading -> g.status != 0 && g.value > 10 }
.map { g: GlucoseReading -> GlucoseEntry(g, 0) }
for (r: GlucoseEntry in toExtend) {
mDb.glucoseEntryDao().insert(r)
}
Log.d(TAG, "Inserted into db!")
return toExtend.size
}
}
// Inspects last entry from the same sensor and filters out all that are already logged.
private fun prepare(chunks : List<SensorChunk>,
sensorId : Long,
dt : Long,
start : Long,
certain : Boolean,
isHistory: Boolean) : List<GlucoseReading> {
val lastRecent = mDb.glucoseEntryDao().getLast(sensorId, isHistory)
if(lastRecent != null) {
var match = -1
for (i in 0 until chunks.size) {
if (lastRecent.eq(chunks[i])) {
match = i
}
}
if(match > -1) {
val range = IntRange(match + 1, chunks.size - 1)
if(!certain)
return chunks.slice(range)
.mapIndexed { i: Int, chunk: SensorChunk ->
GlucoseReading(chunk,
lastRecent.utcTimeStamp + (i + 1) * dt, sensorId)
}
else {
return chunks.mapIndexed { i: Int, chunk: SensorChunk ->
GlucoseReading(chunk,
start + i * dt, sensorId)
}.slice(range)
}
}
}
return chunks.mapIndexed { i: Int, chunk: SensorChunk ->
GlucoseReading(chunk, start + i * dt, sensorId)
}
}
fun nice(g : GlucoseEntry) : Boolean = g.status == 200 && (g.value < 5000 && g.value > 10)
fun get(after: Long, before : Long) : List<GlucoseEntry> {
return get(after, before, true)
}
fun get(after: Long, before : Long, nice : Boolean) : List<GlucoseEntry> {
synchronized(lock) {
val v = mDb.glucoseEntryDao().getBetween(after, before).orEmpty().sortedBy{ g -> g.utcTimeStamp }
if(!nice) return v
else return v.filter{g -> nice(g)}
}
}
private fun last() : GlucoseEntry? {
return mDb.glucoseEntryDao().getLast(false)
}
fun guess() : Pair<GlucoseReading, GlucoseReading>? {
synchronized(lock){
val last = last()
if(last == null || !nice(last)) return null
val last_as_reading = GlucoseReading(last.value, last.utcTimeStamp, last.sensorId, last.status, false, 0)
val candidates = get(last.utcTimeStamp - Time.MINUTE*5, last.utcTimeStamp)
val real = candidates.filter{g -> g.history == false && g.sensorId == last.sensorId}
if(real.isEmpty()) return null
val entry = real.first()
val guess = last.value * 2 - entry.value
val time = last.utcTimeStamp * 2 - entry.utcTimeStamp
return Pair(last_as_reading, GlucoseReading(guess,
time,
last.sensorId, last.status, false, 0))
}
}
fun lastTimeStamp() : Int {
synchronized(lock){return lastTimeStamp}
}
fun size() : Int {
synchronized(lock) {
val sz = mDb.glucoseEntryDao().getSize()
return sz
}
}
fun insertManual(manual : ManualGlucoseEntry) {
synchronized(lock) {
mDb.manualEntryDao().insert(manual)
}
}
companion object {
private var INSTANCE : DataContainer? = null
fun getInstance(context : Context) : DataContainer {
if (INSTANCE == null) {
synchronized(DataContainer::class) {
if(INSTANCE == null)
INSTANCE = DataContainer(context)
}
}
return this.INSTANCE!!
}
/* fun applicationContext() : Context {
return INSTANCE!!.applicationContext
}*/
fun destroyInstance(){
synchronized(DataContainer::class){
GlucoseDataBase.destroyInstance()
if(INSTANCE != null){
INSTANCE = null
}
}
}
}
}
Any suggestion?
Try to change your DataContainer implementation like below and use context
class DataContainer(val context : Context) {
....
init {
mDb = GlucoseDataBase.getInstance(context)
}
....
val queue = Volley.newRequestQueue(context)
}

Categories

Resources