Exam objective

This commit is contained in:
Milos Kozak 2019-09-04 00:00:52 +02:00
parent 702ca21459
commit 37d10fbcbf
15 changed files with 390 additions and 76 deletions

View file

@ -18,6 +18,9 @@ import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
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.objectives.Objective.ExamTask
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper
import kotlinx.android.synthetic.main.objectives_fragment.*
@ -149,6 +152,13 @@ class ObjectivesFragment : Fragment() {
state.text = HtmlHelper.fromHtml(formattedHTML)
state.gravity = Gravity.END
holder.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
if (task is ExamTask) {
state.setOnClickListener {
val dialog = ObjectivesExamDialog();
ObjectivesExamDialog.objective = objective
fragmentManager?.let { dialog.show(it, "ObjectivesFragment") }
}
}
val separator = View(holder.progress.context)
separator.setBackgroundColor(Color.DKGRAY)
holder.progress.addView(separator, LinearLayout.LayoutParams.MATCH_PARENT, 2)

View file

@ -31,13 +31,14 @@ object ObjectivesPlugin : PluginBase(PluginDescription()
val FIRST_OBJECTIVE = 0
val USAGE_OBJECTIVE = 1
val OPENLOOP_OBJECTIVE = 2
val MAXBASAL_OBJECTIVE = 3
val MAXIOB_ZERO_CL_OBJECTIVE = 4
val MAXIOB_OBJECTIVE = 5
val AUTOSENS_OBJECTIVE = 6
val AMA_OBJECTIVE = 7
val SMB_OBJECTIVE = 8
val EXAM_OBJECTIVE = 2
val OPENLOOP_OBJECTIVE = 3
val MAXBASAL_OBJECTIVE = 4
val MAXIOB_ZERO_CL_OBJECTIVE = 5
val MAXIOB_OBJECTIVE = 6
val AUTOSENS_OBJECTIVE = 7
val AMA_OBJECTIVE = 8
val SMB_OBJECTIVE = 9
init {
convertSP()
@ -80,6 +81,7 @@ object ObjectivesPlugin : PluginBase(PluginDescription()
objectives.add(Objective6())
objectives.add(Objective7())
objectives.add(Objective8())
objectives.add(Objective9())
}
fun reset() {

View file

@ -0,0 +1,77 @@
package info.nightscout.androidaps.plugins.constraints.objectives.activities
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.*
import kotlinx.android.synthetic.main.objectives_exam_fragment.*
class ObjectivesExamDialog : DialogFragment() {
companion object {
var objective: Objective? = null
}
var currentTask = 0
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// load data from bundle
(savedInstanceState ?: arguments)?.let { bundle ->
currentTask = bundle.getInt("currentTask", 0)
}
dialog.setCanceledOnTouchOutside(false)
return inflater.inflate(R.layout.objectives_exam_fragment, container, false)
}
override fun onResume() {
super.onResume()
updateGui()
}
fun updateGui() {
objective?.let { objective ->
val task: ExamTask = objective.tasks[currentTask] as ExamTask
objectives_exam_name.setText(task.task)
objectives_exam_question.setText(task.question)
objectives_exam_options.removeAllViews()
for (o in task.options) {
val option: Option = o as Option;
val cb = option.generate(context)
if (task.answered) {
cb.isEnabled = false
if (option.isCorrect)
cb.isChecked = true
}
objectives_exam_options.addView(cb)
}
objectives_exam_hints.removeAllViews()
for (h in task.hints) {
val hint: Hint = h as Hint;
objectives_exam_hints.addView(hint.generate(context))
}
objectives_exam_verify.setOnClickListener {
var result = true
for (o in task.options) {
val option: Option = o as Option;
result = result && option.evaluate()
}
task.setAnswered(result);
updateGui()
}
cancel.setOnClickListener { dismiss() }
objectives_exam_reset.setOnClickListener {
task.answered = false
updateGui()
}
}
}
override fun onSaveInstanceState(bundle: Bundle) {
super.onSaveInstanceState(bundle)
bundle.putInt("currentTask", currentTask)
}
}

View file

@ -1,6 +1,11 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.text.util.Linkify;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.StringRes;
@ -99,7 +104,7 @@ public abstract class Objective {
this.task = task;
}
public int getTask() {
public @StringRes int getTask() {
return task;
}
@ -148,4 +153,102 @@ public abstract class Objective {
}
}
public class ExamTask extends Task {
@StringRes
int question;
List hints = new ArrayList<>();
List options = new ArrayList<>();
private String spIdentifier;
private boolean answered;
ExamTask(@StringRes int task, @StringRes int question, String spIdentifier) {
super(task);
this.question = question;
this.spIdentifier = spIdentifier;
answered = SP.getBoolean("ExamTask_" + spIdentifier, false);
}
public void setAnswered(boolean newState) {
answered = newState;
SP.putBoolean("ExamTask_" + spIdentifier, answered);
}
public boolean getAnswered() {
return answered;
}
ExamTask option(Option option) {
options.add(option);
return this;
}
ExamTask hint(Hint hint) {
hints.add(hint);
return this;
}
public @StringRes int getQuestion() {
return question;
}
public List getOptions() {
return options;
}
public List getHints() {
return hints;
}
@Override
public boolean isCompleted() {
return answered;
}
}
public class Option {
@StringRes int option;
boolean isCorrect;
CheckBox cb; // TODO: change it, this will block releasing memeory
Option(@StringRes int option, boolean isCorrect) {
this.option = option;
this.isCorrect = isCorrect;
}
public boolean isCorrect() {
return isCorrect;
}
public CheckBox generate(Context context) {
cb = new CheckBox(context);
cb.setText(option);
return cb;
}
public boolean evaluate() {
boolean selection = cb.isChecked();
if (selection && isCorrect) return true;
if (!selection && !isCorrect) return true;
return false;
}
}
public class Hint {
@StringRes int hint;
Hint(@StringRes int hint) {
this.hint = hint;
}
public TextView generate(Context context) {
TextView textView = new TextView(context);
textView.setText(hint);
textView.setAutoLinkMask(Linkify.WEB_URLS);
textView.setLinksClickable(true);
textView.setLinkTextColor(Color.YELLOW);
Linkify.addLinks(textView, Linkify.WEB_URLS);
return textView;
}
}
}

View file

@ -1,45 +1,27 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import android.app.Activity;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
public class Objective2 extends Objective {
public final int MANUAL_ENACTS_NEEDED = 20;
public Objective2() {
super("openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate);
hasSpecialInput = true;
super("exam", R.string.objectives_exam_objective, R.string.objectives_exam_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
tasks.add(new Task(R.string.objectives_manualenacts) {
@Override
public boolean isCompleted() {
return SP.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED;
}
@Override
public String getProgress() {
if (SP.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED)
return MainApp.gs(R.string.completed_well_done);
else
return SP.getInt(R.string.key_ObjectivesmanualEnacts, 0) + " / " + MANUAL_ENACTS_NEEDED;
}
});
}
@Override
public void specialAction(Activity activity, String input) {
ObjectivesPlugin.INSTANCE.completeObjectives(activity, input);
}
tasks.add(new ExamTask(R.string.meaningofdia, R.string.whatmeansdia,"dia")
.option(new Option(R.string.minimumis3h, false))
.option(new Option(R.string.minimumis5h, true))
.option(new Option(R.string.meaningisequaltodiapump, false))
.option(new Option(R.string.valuemustbedetermined, true))
.hint(new Hint(R.string.diahint1))
);
}
}

View file

@ -1,11 +1,45 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import android.app.Activity;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
public class Objective3 extends Objective {
public final int MANUAL_ENACTS_NEEDED = 20;
public Objective3() {
super("maxbasal", R.string.objectives_maxbasal_objective, R.string.objectives_maxbasal_gate);
super("openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate);
hasSpecialInput = true;
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
tasks.add(new Task(R.string.objectives_manualenacts) {
@Override
public boolean isCompleted() {
return SP.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED;
}
@Override
public String getProgress() {
if (SP.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED)
return MainApp.gs(R.string.completed_well_done);
else
return SP.getInt(R.string.key_ObjectivesmanualEnacts, 0) + " / " + MANUAL_ENACTS_NEEDED;
}
});
}
@Override
public void specialAction(Activity activity, String input) {
ObjectivesPlugin.INSTANCE.completeObjectives(activity, input);
}
}

View file

@ -1,34 +1,10 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import java.util.List;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
import info.nightscout.androidaps.utils.T;
public class Objective4 extends Objective {
public Objective4() {
super("maxiobzero", R.string.objectives_maxiobzero_objective, R.string.objectives_maxiobzero_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(5).msecs()));
tasks.add(new Task(R.string.closedmodeenabled) {
@Override
public boolean isCompleted() {
Constraint<Boolean> closedLoopEnabled = new Constraint<>(true);
SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
return closedLoopEnabled.value();
}
});
}
@Override
public boolean isRevertable() {
return true;
super("maxbasal", R.string.objectives_maxbasal_objective, R.string.objectives_maxbasal_gate);
}
}

View file

@ -2,26 +2,32 @@ package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
import info.nightscout.androidaps.utils.T;
public class Objective5 extends Objective {
public Objective5() {
super("maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate);
super("maxiobzero", R.string.objectives_maxiobzero_objective, R.string.objectives_maxiobzero_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(1).msecs()));
tasks.add(new Task(R.string.maxiobset) {
tasks.add(new MinimumDurationTask(T.days(5).msecs()));
tasks.add(new Task(R.string.closedmodeenabled) {
@Override
public boolean isCompleted() {
double maxIOB = MainApp.getConstraintChecker().getMaxIOBAllowed().value();
return maxIOB > 0;
Constraint<Boolean> closedLoopEnabled = new Constraint<>(true);
SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
return closedLoopEnabled.value();
}
});
}
@Override
public boolean isRevertable() {
return true;
}
}

View file

@ -2,18 +2,25 @@ package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.utils.T;
public class Objective6 extends Objective {
public Objective6() {
super("autosens", R.string.objectives_autosens_objective, R.string.objectives_autosens_gate);
super("maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
tasks.add(new MinimumDurationTask(T.days(1).msecs()));
tasks.add(new Task(R.string.maxiobset) {
@Override
public boolean isCompleted() {
double maxIOB = MainApp.getConstraintChecker().getMaxIOBAllowed().value();
return maxIOB > 0;
}
});
}
}

View file

@ -9,11 +9,11 @@ import info.nightscout.androidaps.utils.T;
public class Objective7 extends Objective {
public Objective7() {
super("ama", R.string.objectives_ama_objective, 0);
super("autosens", R.string.objectives_autosens_objective, R.string.objectives_autosens_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
}
}

View file

@ -9,7 +9,7 @@ import info.nightscout.androidaps.utils.T;
public class Objective8 extends Objective {
public Objective8() {
super("smb", R.string.objectives_smb_objective, R.string.objectives_smb_gate);
super("ama", R.string.objectives_ama_objective, 0);
}
@Override

View file

@ -0,0 +1,18 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
import java.util.List;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.utils.T;
public class Objective9 extends Objective {
public Objective9() {
super("smb", R.string.objectives_smb_objective, R.string.objectives_smb_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
}
}

View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="15dp"
tools:context=".plugins.constraints.objectives.activities.ObjectivesExamDialog">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/objectives_exam_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@+id/objectives_exam_question"
tools:layout_editor_absoluteX="3dp">
</LinearLayout>
<LinearLayout
android:id="@+id/objectives_exam_hints"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@+id/objectives_exam_options"
tools:layout_editor_absoluteX="3dp">
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/objectives_exam_hints">
<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
android:id="@+id/objectives_exam_reset"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/reset" />
<Button
android:id="@+id/objectives_exam_verify"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/objectives_button_verify" />
</LinearLayout>
<TextView
android:id="@+id/objectives_exam_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Question"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/objectives_exam_name" />
<TextView
android:id="@+id/objectives_exam_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="whatmeansdia">What is true about DIA?</string>
<string name="meaningofdia">Meaning of DIA</string>
<string name="minimumis3h">minimum is 3 hours</string>
<string name="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="meaningisequaltodiapump">meaning is equal to DIA parameter used in pumps</string>
<string name="valuemustbedetermined">correct value must be determined</string>
</resources>

View file

@ -1629,6 +1629,8 @@
<string name="key_ObjectivesbgIsAvailableInNS" translatable="false">ObjectivesbgIsAvailableInNS</string>
<string name="key_ObjectivespumpStatusIsAvailableInNS" translatable="false">ObjectivespumpStatusIsAvailableInNS</string>
<string name="key_ObjectivesmanualEnacts" translatable="false">ObjectivesmanualEnacts</string>
<string name="objectives_exam_objective">Prove your knowledge</string>
<string name="objectives_exam_gate">Study and answer questions correctly</string>
<plurals name="objective_days">
<item quantity="one">%1$d day</item>