ObjectivesExamDialog fine tunning

This commit is contained in:
Milos Kozak 2019-09-05 20:26:23 +02:00
parent 6b388b3bd2
commit 91ebc11d9b
8 changed files with 235 additions and 41 deletions

View file

@ -18,17 +18,23 @@ import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.objectives_fragment.* import kotlinx.android.synthetic.main.objectives_fragment.*
class ObjectivesFragment : Fragment() { class ObjectivesFragment : Fragment() {
private val objectivesAdapter = ObjectivesAdapter() private val objectivesAdapter = ObjectivesAdapter()
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private var disposable: CompositeDisposable = CompositeDisposable()
private val objectiveUpdater = object : Runnable { private val objectiveUpdater = object : Runnable {
override fun run() { override fun run() {
handler.postDelayed(this, (60 * 1000).toLong()) handler.postDelayed(this, (60 * 1000).toLong())
@ -56,6 +62,26 @@ class ObjectivesFragment : Fragment() {
startUpdateTimer() startUpdateTimer()
} }
@Synchronized
override fun onResume() {
super.onResume()
disposable.add(RxBus
.toObservable(EventObjectivesUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
objectives_recyclerview.adapter?.notifyDataSetChanged()
}, {
FabricPrivacy.logException(it)
})
)
}
@Synchronized
override fun onPause() {
super.onPause()
disposable.clear()
}
@Synchronized @Synchronized
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
@ -154,7 +180,11 @@ class ObjectivesFragment : Fragment() {
holder.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) holder.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
if (task is ExamTask) { if (task is ExamTask) {
state.setOnClickListener { state.setOnClickListener {
val dialog = ObjectivesExamDialog(); val dialog = ObjectivesExamDialog()
val bundle = Bundle()
val position = objective.tasks.indexOf(task)
bundle.putInt("currentTask", position)
dialog.arguments = bundle
ObjectivesExamDialog.objective = objective ObjectivesExamDialog.objective = objective
fragmentManager?.let { dialog.show(it, "ObjectivesFragment") } fragmentManager?.let { dialog.show(it, "ObjectivesFragment") }
} }

View file

@ -5,15 +5,23 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.* import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.*
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.OKDialog
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import kotlinx.android.synthetic.main.objectives_exam_fragment.* import kotlinx.android.synthetic.main.objectives_exam_fragment.*
class ObjectivesExamDialog : DialogFragment() { class ObjectivesExamDialog : DialogFragment() {
companion object { companion object {
var objective: Objective? = null var objective: Objective? = null
} }
var currentTask = 0 var currentTask = 0
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
@ -23,20 +31,31 @@ class ObjectivesExamDialog : DialogFragment() {
currentTask = bundle.getInt("currentTask", 0) currentTask = bundle.getInt("currentTask", 0)
} }
dialog.setCanceledOnTouchOutside(false)
return inflater.inflate(R.layout.objectives_exam_fragment, container, false) return inflater.inflate(R.layout.objectives_exam_fragment, container, false)
} }
override fun onStart() {
super.onStart()
dialog.setCanceledOnTouchOutside(false)
dialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
updateGui() updateGui()
} }
override fun onSaveInstanceState(bundle: Bundle) {
super.onSaveInstanceState(bundle)
bundle.putInt("currentTask", currentTask)
}
fun updateGui() { fun updateGui() {
objective?.let { objective -> objective?.let { objective ->
val task: ExamTask = objective.tasks[currentTask] as ExamTask val task: ExamTask = objective.tasks[currentTask] as ExamTask
objectives_exam_name.setText(task.task) objectives_exam_name.setText(task.task)
objectives_exam_question.setText(task.question) objectives_exam_question.setText(task.question)
// Options
objectives_exam_options.removeAllViews() objectives_exam_options.removeAllViews()
for (o in task.options) { for (o in task.options) {
val option: Option = o as Option; val option: Option = o as Option;
@ -48,11 +67,17 @@ class ObjectivesExamDialog : DialogFragment() {
} }
objectives_exam_options.addView(cb) objectives_exam_options.addView(cb)
} }
// Hints
objectives_exam_hints.removeAllViews() objectives_exam_hints.removeAllViews()
for (h in task.hints) { for (h in task.hints) {
val hint: Hint = h as Hint; val hint: Hint = h as Hint;
objectives_exam_hints.addView(hint.generate(context)) objectives_exam_hints.addView(hint.generate(context))
} }
// Disabled to
objectives_exam_disabledto.text = MainApp.gs(R.string.answerdisabledto, DateUtil.timeString(task.disabledTo))
objectives_exam_disabledto.visibility = if (task.isEnabledAnswer) View.GONE else View.VISIBLE
// Buttons
objectives_exam_verify.isEnabled = !task.answered && task.isEnabledAnswer
objectives_exam_verify.setOnClickListener { objectives_exam_verify.setOnClickListener {
var result = true var result = true
for (o in task.options) { for (o in task.options) {
@ -60,18 +85,48 @@ class ObjectivesExamDialog : DialogFragment() {
result = result && option.evaluate() result = result && option.evaluate()
} }
task.setAnswered(result); task.setAnswered(result);
if (!result) {
task.disabledTo = DateUtil.now() + T.hours(1).msecs()
ToastUtils.showToastInUiThread(context, R.string.wronganswer)
} else task.disabledTo = 0
updateGui() updateGui()
RxBus.send(EventObjectivesUpdateGui())
} }
cancel.setOnClickListener { dismiss() } close.setOnClickListener { dismiss() }
objectives_exam_reset.setOnClickListener { objectives_exam_reset.setOnClickListener {
task.answered = false task.answered = false
//task.disabledTo = 0
updateGui()
RxBus.send(EventObjectivesUpdateGui())
}
objectives_back_button.isEnabled = currentTask != 0
objectives_back_button.setOnClickListener {
currentTask--
updateGui() updateGui()
} }
} objectives_next_button.isEnabled = currentTask != objective.tasks.size - 1
objectives_next_button.setOnClickListener {
currentTask++
updateGui()
} }
override fun onSaveInstanceState(bundle: Bundle) { objectives_next_unanswered_button.isEnabled = !objective.isCompleted
super.onSaveInstanceState(bundle) objectives_next_unanswered_button.setOnClickListener {
bundle.putInt("currentTask", currentTask) for (i in (currentTask + 1)..(objective.tasks.size - 1)) {
if (!objective.tasks[i].isCompleted) {
currentTask = i
updateGui()
return@setOnClickListener
}
}
for (i in 0..currentTask) {
if (!objective.tasks[i].isCompleted) {
currentTask = i
updateGui()
return@setOnClickListener
}
}
}
}
} }
} }

View file

@ -0,0 +1,5 @@
package info.nightscout.androidaps.plugins.constraints.objectives.events
import info.nightscout.androidaps.events.EventUpdateGui
class EventObjectivesUpdateGui : EventUpdateGui()

View file

@ -14,6 +14,7 @@ import java.util.List;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T; import info.nightscout.androidaps.utils.T;
@ -160,12 +161,27 @@ public abstract class Objective {
List options = new ArrayList<>(); List options = new ArrayList<>();
private String spIdentifier; private String spIdentifier;
private boolean answered; private boolean answered;
private long disabledTo;
ExamTask(@StringRes int task, @StringRes int question, String spIdentifier) { ExamTask(@StringRes int task, @StringRes int question, String spIdentifier) {
super(task); super(task);
this.question = question; this.question = question;
this.spIdentifier = spIdentifier; this.spIdentifier = spIdentifier;
answered = SP.getBoolean("ExamTask_" + spIdentifier, false); answered = SP.getBoolean("ExamTask_" + spIdentifier, false);
disabledTo = SP.getLong("DisabledTo_" + spIdentifier, 0L);
}
public void setDisabledTo(long newState) {
disabledTo = newState;
SP.putLong("DisabledTo_" + spIdentifier, disabledTo);
}
public long getDisabledTo() {
return disabledTo;
}
public boolean isEnabledAnswer() {
return disabledTo < DateUtil.now();
} }
public void setAnswered(boolean newState) { public void setAnswered(boolean newState) {

View file

@ -3,9 +3,6 @@ package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin;
import info.nightscout.androidaps.utils.SP;
public class Objective2 extends Objective { public class Objective2 extends Objective {
@ -16,12 +13,25 @@ public class Objective2 extends Objective {
@Override @Override
protected void setupTasks(List<Task> tasks) { protected void setupTasks(List<Task> tasks) {
tasks.add(new ExamTask(R.string.meaningofdia, R.string.whatmeansdia,"dia") tasks.add(new ExamTask(R.string.dia_meaningofdia, R.string.dia_whatmeansdia,"dia")
.option(new Option(R.string.minimumis3h, false)) .option(new Option(R.string.dia_minimumis3h, false))
.option(new Option(R.string.minimumis5h, true)) .option(new Option(R.string.dia_minimumis5h, true))
.option(new Option(R.string.meaningisequaltodiapump, false)) .option(new Option(R.string.dia_meaningisequaltodiapump, false))
.option(new Option(R.string.valuemustbedetermined, true)) .option(new Option(R.string.dia_valuemustbedetermined, true))
.hint(new Hint(R.string.diahint1)) .hint(new Hint(R.string.dia_hint1))
);
tasks.add(new ExamTask(R.string.hypott, R.string.hypott_whenhypott,"hypott")
.option(new Option(R.string.hypott_goinglow, true))
.option(new Option(R.string.hypott_havinglow, true))
.option(new Option(R.string.hypott_notlowanymorebutrising, false))
.option(new Option(R.string.hypott_havehadalowbg, false))
.hint(new Hint(R.string.hypott_hint1))
);
tasks.add(new ExamTask(R.string.offlineprofile, R.string.offlineprofile_whatprofile,"offlineprofile")
.option(new Option(R.string.localprofile, true))
.option(new Option(R.string.nsprofile, false))
.option(new Option(R.string.offlineprofile_nsprofile, true))
.hint(new Hint(R.string.offlineprofile_hint1))
); );
} }
} }

View file

@ -4,12 +4,12 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="15dp"
tools:context=".plugins.constraints.objectives.activities.ObjectivesExamDialog"> tools:context=".plugins.constraints.objectives.activities.ObjectivesExamDialog">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:layout_margin="10dp">
<LinearLayout <LinearLayout
android:id="@+id/objectives_exam_options" android:id="@+id/objectives_exam_options"
@ -27,24 +27,20 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginBottom="10dp"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@+id/objectives_exam_options" app:layout_constraintTop_toBottomOf="@+id/objectives_exam_options"
tools:layout_editor_absoluteX="3dp"> tools:layout_editor_absoluteX="3dp" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/objectives_buttons"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="#3C3C3C"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/objectives_exam_hints"> android:padding="4dp"
app:layout_constraintTop_toBottomOf="@+id/objectives_exam_disabledto">
<Button
android:id="@+id/cancel"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel" />
<Button <Button
android:id="@+id/objectives_exam_reset" android:id="@+id/objectives_exam_reset"
@ -53,12 +49,26 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/reset" /> android:text="@string/reset" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="" />
<Button
android:id="@+id/close"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/close" />
<Button <Button
android:id="@+id/objectives_exam_verify" android:id="@+id/objectives_exam_verify"
style="@style/Widget.AppCompat.Button.Borderless.Colored" style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/objectives_button_verify" /> android:text="@string/objectives_button_verify" />
</LinearLayout> </LinearLayout>
<TextView <TextView
@ -69,17 +79,69 @@
android:text="Question" android:text="Question"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/objectives_exam_name" /> app:layout_constraintTop_toBottomOf="@id/objectives_exam_name" />
<TextView <TextView
android:id="@+id/objectives_exam_name" android:id="@+id/objectives_exam_name"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Name" android:text="Name"
android:textAppearance="@style/TextAppearance.AppCompat.Large" android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/objectives_exam_disabledto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Disabled to:"
android:textColor="#FF5722"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/objectives_exam_hints" />
<LinearLayout
android:id="@+id/objectives_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:background="#3C3C3C"
android:orientation="horizontal"
android:padding="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/objectives_buttons">
<Button
android:id="@+id/objectives_back_button"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/previous_button" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="" />
<Button
android:id="@+id/objectives_next_button"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next_button" />
<Button
android:id="@+id/objectives_next_unanswered_button"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/unfinshed_button" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView> </ScrollView>

View file

@ -1,11 +1,23 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="whatmeansdia">What is true about DIA?</string> <string name="dia_whatmeansdia">What is true about DIA?</string>
<string name="meaningofdia">Meaning of DIA</string> <string name="dia_meaningofdia">Meaning of DIA</string>
<string name="minimumis3h">minimum is 3 hours</string> <string name="dia_minimumis3h">minimum is 3 hours</string>
<string name="minimumis5h">minimum is 5 hours</string> <string name="dia_minimumis5h">minimum is 5 hours</string>
<string name="diahint1">https://androidaps.readthedocs.io/en/latest/CROWDIN/he/Configuration/Config-Builder.html?#insulin</string> <string name="dia_hint1">https://androidaps.readthedocs.io/en/latest/EN/Configuration/Config-Builder.html?#insulin</string>
<string name="meaningisequaltodiapump">meaning is equal to DIA parameter used in pumps</string> <string name="dia_meaningisequaltodiapump">meaning is equal to DIA parameter used in pumps</string>
<string name="valuemustbedetermined">correct value must be determined</string> <string name="dia_valuemustbedetermined">correct value must be determined</string>
<string name="hypott">Hypo temp target</string>
<string name="hypott_whenhypott">When should you do a hypo TT?</string>
<string name="hypott_goinglow">you are going low</string>
<string name="hypott_havinglow">your already have a low bg</string>
<string name="hypott_notlowanymorebutrising">your not low anymore, but your BG is rising because of the (right!) amount of hypo treatments</string>
<string name="hypott_bgisrising">your bg is rising, has just reached the target BG but there is still too much IOB left</string>
<string name="hypott_havehadalowbg">you have had a low bg a while ago, but it got you in a hyper</string>
<string name="hypott_hint1">https://androidaps.readthedocs.io/en/latest/EN/Usage/temptarget.html</string>
<string name="offlineprofile_whatprofile">Which profile can be used and configured offline</string>
<string name="offlineprofile">Offline profile</string>
<string name="offlineprofile_nsprofile">NS Profile can be used but not configured</string>
<string name="offlineprofile_hint1">https://androidaps.readthedocs.io/en/latest/EN/Configuration/Config-Builder.html#profile</string>
</resources> </resources>

View file

@ -1631,6 +1631,10 @@
<string name="key_ObjectivesmanualEnacts" translatable="false">ObjectivesmanualEnacts</string> <string name="key_ObjectivesmanualEnacts" translatable="false">ObjectivesmanualEnacts</string>
<string name="objectives_exam_objective">Prove your knowledge</string> <string name="objectives_exam_objective">Prove your knowledge</string>
<string name="objectives_exam_gate">Study and answer questions correctly</string> <string name="objectives_exam_gate">Study and answer questions correctly</string>
<string name="answerdisabledto">Answering disabled to: %1$s</string>
<string name="wronganswer">Wrong answer!</string>
<string name="unfinshed_button">Next unfinished</string>
<string name="close">Close</string>
<plurals name="objective_days"> <plurals name="objective_days">
<item quantity="one">%1$d day</item> <item quantity="one">%1$d day</item>