From a6418678a42749d569cab950bc3a55100bd7c34a Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Tue, 19 May 2026 18:29:03 +0200 Subject: [PATCH 1/3] Remove DotsEntryActivity manifest entry Drops the activity declaration and the org.commcare.dalvik.action.DotsEntry intent-filter so the DOTS tracker is no longer launchable. This is the first step in retiring the unused DOTS feature; the Java sources and resources are removed in follow-up commits. Co-Authored-By: Claude Opus 4.7 --- app/AndroidManifest.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml index e224e61447..9f69804ccf 100644 --- a/app/AndroidManifest.xml +++ b/app/AndroidManifest.xml @@ -239,15 +239,6 @@ - - - - - - - Date: Tue, 19 May 2026 18:29:49 +0200 Subject: [PATCH 2/3] Delete DOTS tracker Java sources Removes DotsEntryActivity, DotsHomeView, DotsDetailView, DotsData, and DotsEditListener. The activity is no longer registered in the manifest, and no other code in app/ or commcare-core references these classes. The orphaned DOTS layouts/drawables/colors are cleaned up in the next commit. Co-Authored-By: Claude Opus 4.7 --- .../activities/DotsEntryActivity.java | 520 ------------------ app/src/org/commcare/utils/DotsData.java | 417 -------------- .../org/commcare/utils/DotsEditListener.java | 24 - .../org/commcare/views/DotsDetailView.java | 278 ---------- app/src/org/commcare/views/DotsHomeView.java | 148 ----- 5 files changed, 1387 deletions(-) delete mode 100644 app/src/org/commcare/activities/DotsEntryActivity.java delete mode 100644 app/src/org/commcare/utils/DotsData.java delete mode 100644 app/src/org/commcare/utils/DotsEditListener.java delete mode 100644 app/src/org/commcare/views/DotsDetailView.java delete mode 100755 app/src/org/commcare/views/DotsHomeView.java diff --git a/app/src/org/commcare/activities/DotsEntryActivity.java b/app/src/org/commcare/activities/DotsEntryActivity.java deleted file mode 100644 index 41717f7233..0000000000 --- a/app/src/org/commcare/activities/DotsEntryActivity.java +++ /dev/null @@ -1,520 +0,0 @@ -package org.commcare.activities; - -import android.content.Context; -import android.content.Intent; -import android.graphics.Rect; -import android.os.Bundle; -import android.text.format.DateFormat; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.Animation; -import android.view.animation.Animation.AnimationListener; -import android.view.animation.AnimationUtils; -import android.view.animation.ScaleAnimation; -import android.view.inputmethod.InputMethodManager; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TableLayout; -import android.widget.TableRow; -import android.widget.TextView; - -import org.commcare.dalvik.R; -import org.commcare.utils.DotsData; -import org.commcare.utils.DotsData.DotsBox; -import org.commcare.utils.DotsData.DotsDay; -import org.commcare.utils.DotsEditListener; -import org.commcare.utils.GestureDetector; -import org.commcare.views.DotsDetailView; -import org.commcare.views.DotsHomeView; -import org.javarosa.core.model.utils.DateUtils; -import org.json.JSONArray; -import org.json.JSONException; - -import java.util.Calendar; -import java.util.Date; - -/** - * @author ctsims - */ -public class DotsEntryActivity extends CommonBaseActivity implements DotsEditListener, AnimationListener { - - private DotsData dotsData; - - enum AnimationType { - zoomin, - zoomout, - fade, - right, - left - } - - private static final String DOTS_DATA = "odk_intent_data"; - private static final String DOTS_EDITING = "dots_editing"; - private static final String DOTS_DAY = "dots_day"; - private static final String DOTS_BOX = "dots_box"; - private static final String CURRENT_FOCUS = "dots_focus"; - - private int curday = -1; - private int curdose = -1; - private DotsDay d; - private DotsDetailView ddv; - private GestureDetector mGestureDetector; - - int zX = -1; - int zY = -1; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if(savedInstanceState == null) { - String regimen = getIntent().getStringExtra("regimen"); - int[] regimens = new int[2]; - - try { - JSONArray array = new JSONArray(regimen); - for(int i = 0; i < array.length(); ++i) { - regimens[i] = array.getInt(i); - } - } - catch(JSONException e) { - throw new RuntimeException(e); - } - - String data = getIntent().getStringExtra(DOTS_DATA); - boolean populateAnchor = false; - - Date anchorDate = new Date(); - String anchor = getIntent().getStringExtra("anchor"); - if(anchor != null) { - anchorDate = DateUtils.parseDate(anchor); - } - - if(data != null) { - dotsData = DotsData.DeserializeDotsData(data); - - //If the regimen is new for today, or if the current values for the last day are all - //the default - if(dotsData.recenter(regimens, anchorDate) != 0 || - dotsData.days()[dotsData.days().length -1].isDefault()) { - populateAnchor = true; - } - } else { - dotsData = DotsData.CreateDotsData(regimens, anchorDate); - populateAnchor = true; - } - - String currentDoseCheck = getIntent().getStringExtra("currentdose"); - if(populateAnchor && currentDoseCheck != null) { - int box = Integer.parseInt(getIntent().getStringExtra("currentbox")); - - // now fill in the box specified - DotsDay day = dotsData.days()[dotsData.days().length - 1]; - DotsBox[][] boxes = day.boxes(); - boxes[0][box] = boxes[0][box].update(DotsBox.deserialize(currentDoseCheck)); - - dotsData.days()[dotsData.days().length - 1] = new DotsDay(boxes); - } - - String currentDoseCheckTwo = getIntent().getStringExtra("currentdosetwo"); - if(populateAnchor && currentDoseCheckTwo != null && !"".equals(currentDoseCheckTwo)) { - int box = Integer.parseInt(getIntent().getStringExtra("currentboxtwo")); - - // now fill in the box specified - DotsDay day = dotsData.days()[dotsData.days().length - 1]; - DotsBox[][] boxes = day.boxes(); - boxes[1][box] = boxes[1][box].update(DotsBox.deserialize(currentDoseCheckTwo)); - - dotsData.days()[dotsData.days().length - 1] = new DotsDay(boxes); - } - - showView(home(), AnimationType.fade); - } - setTitle(getString(R.string.application_name) + " > " + " DOTS"); - mGestureDetector = new GestureDetector(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString(DOTS_DATA,dotsData.SerializeDotsData()); - outState.putInt(DOTS_EDITING, curday); - outState.putInt(DOTS_BOX, curdose); - if(curdose != -1) { - outState.putString(DOTS_DAY, ddv.getDay().serialize().toString()); - } - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - dotsData = DotsData.DeserializeDotsData(savedInstanceState.getString(DOTS_DATA)); - curday = savedInstanceState.getInt(DOTS_EDITING); - curdose = savedInstanceState.getInt(DOTS_BOX); - if(curdose != -1) { - d = DotsDay.deserialize(savedInstanceState.getString(DOTS_DAY)); - } - } - - private DotsHomeView home() { - setTitle(getString(R.string.application_name) + " > " + " DOTS"); - return new DotsHomeView(this, dotsData, this); - } - - - @Override - public void dayEdited(int i, DotsDay day) { - dotsData.days()[i] = day; - curdose = -1; - showView(curday(), AnimationType.fade); - } - - @Override - public void cancelDoseEdit() { - curdose = -1; - showView(curday(), AnimationType.fade); - } - - @Override - public void doneWithDOTS() { - Intent i = new Intent(this.getIntent()); - i.putExtra(DOTS_DATA, dotsData.SerializeDotsData()); - setResult(RESULT_OK, i); - finish(); - } - - @Override - public void editDotsDay(int i, Rect rect) { - zX = rect.centerX(); - zY = rect.centerY(); - - edit(i, AnimationType.zoomin); - } - - private void edit(int i, AnimationType anim) { - curday = i; - //ddv = new DotsDetailView(); - Date date = DateUtils.dateAdd(dotsData.anchor(), i - dotsData.days().length + 1); - //View view = ddv.LoadDotsDetailView(this, day, i, date, boxes, this); - View view = curday(); - - //DateFormat df = DateFormat.getDateFormat(this); - - setTitle(getString(R.string.application_name) + " > " + "DOTS Details for " + DateFormat.format("MM/dd/yyyy", date)); - showView(view, anim); - } - - Animation mInAnimation; - Animation mOutAnimation; - View mCurrentView; - - private void showView(View next, AnimationType anim) { - showView(next,anim, null); - } - - private void showView(View next, AnimationType anim, View target) { - if(target != null) { - next.buildDrawingCache(); - Rect targetRect = new Rect(0,0,target.getWidth(), target.getHeight()); - ((ViewGroup)next).offsetDescendantRectToMyCoords(target, targetRect); - zX = targetRect.centerX(); - zY = targetRect.centerY(); - next.destroyDrawingCache(); - } - - switch (anim) { - case zoomin: - mInAnimation = AnimationUtils.loadAnimation(this, R.anim.zoom_in); - if(zX != -1 && zY != -1) { - long duration = mInAnimation.getDuration(); - mInAnimation = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, zX, zY); - mInAnimation.setDuration(duration); - } - mOutAnimation= AnimationUtils.loadAnimation(this, R.anim.fade_out); - break; - case zoomout: - mInAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_in_delay); - mOutAnimation = AnimationUtils.loadAnimation(this, R.anim.zoom_out); - if(zX != -1 && zY != -1) { - long duration = mOutAnimation.getDuration(); - mOutAnimation = new ScaleAnimation(1.0f, 0.0f, 1.0f, 0.0f, zX, zY); - mOutAnimation.setDuration(duration); - } - break; - case fade: - mInAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_in); - mOutAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_out); - break; - case left: - mInAnimation = AnimationUtils.loadAnimation(this, R.anim.push_left_in); - mOutAnimation = AnimationUtils.loadAnimation(this, R.anim.push_left_out); - break; - case right: - mInAnimation = AnimationUtils.loadAnimation(this, R.anim.push_right_in); - mOutAnimation = AnimationUtils.loadAnimation(this, R.anim.push_right_out); - break; - - } - - if (mCurrentView != null && mOutAnimation != null) { - mCurrentView.startAnimation(mOutAnimation); - } - - if(mInAnimation != null) { - mInAnimation.setAnimationListener(this); - } - - mCurrentView = next; - this.setContentView(next); - - if(mInAnimation != null) { - mCurrentView.startAnimation(mInAnimation); - InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - inputManager.hideSoftInputFromWindow(mCurrentView.getWindowToken(), 0); - } - } - - @Override - protected void onResume() { - super.onResume(); - if(curday == -1) { - showView(home(), AnimationType.fade); - } else if(curdose == -1) { - edit(curday, AnimationType.fade); - } else { - editDose(curday, curdose, d, null); - } - } - - @Override - protected void onPause() { - super.onPause(); - //Make sure all data in UI's is in memory - if(curdose != -1) { - d = ddv.getDay(); - } - } - - @Override - public void cancelDayEdit(int editing) { - curday = -1; - d= null; - DotsHomeView home = home(); - - showView(home, AnimationType.zoomout); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_BACK: - if(curday != -1) { - if(curdose != -1) { - cancelDoseEdit(); - return true; - } else { - cancelDayEdit(curday); - return true; - } - } - - } - return super.onKeyDown(keyCode, event); - } - - @Override - public void onAnimationEnd(Animation animation) { - mBeenSwiped = false; - } - - @Override - public void onAnimationRepeat(Animation animation) { - // TODO Auto-generated method stub - - } - - @Override - public void onAnimationStart(Animation animation) { - // TODO Auto-generated method stub - - } - - boolean mBeenSwiped; - - @Override - public boolean onTouchEvent(MotionEvent motionEvent) { - /* - * constrain the user to only be able to swipe (that causes a view transition) once per - * screen with the mBeenSwiped variable. - */ - boolean handled = false; - if (!mBeenSwiped) { - switch (mGestureDetector.getGesture(motionEvent)) { - case SWIPE_RIGHT: - handled = tryMove(-1); - break; - case SWIPE_LEFT: - handled = tryMove(1); - break; - } - } - return handled; - } - - private boolean tryMove(int offsetChange) { - if(curdose != -1 || curday == -1) { - return false; - } - int maxOffset = this.dotsData.days().length - 1; - if(curday + offsetChange < 0 || curday + offsetChange > maxOffset) { - return false; - } - mBeenSwiped = true; - curday = curday + offsetChange; - edit(curday, offsetChange > 0 ? AnimationType.left : AnimationType.right); - return true; - } - - @Override - public void shiftDay(int delta) { - tryMove(-delta); - } - - - private View curday() { - final ViewGroup dayView = (ViewGroup)View.inflate(this, R.layout.dotsdoses, null); - TableRow[] rows = new TableRow[4]; - rows[0] = dayView.findViewById(R.id.dots_dose_one); - rows[1] = dayView.findViewById(R.id.dots_dose_two); - //rows[2] = (TableRow)dayView.findViewById(R.id.dots_dose_three); - //rows[3] = (TableRow)dayView.findViewById(R.id.dots_dose_four); - - DotsDay day = dotsData.days()[curday]; - - int disLen = day.getMaxReg(); - for(int i = 0 ; i < disLen ; ++i ) { - final int regIndex = i; - View doseView = getDoseView(day, curday, i); - rows[i % 2 == 0 ? 0 : 1].addView(doseView == null ? new ImageView(this): doseView); - if(doseView == null) { - continue; - } - - doseView.setOnClickListener(v -> { - Rect hitRect = new Rect(); - if(v.getParent() instanceof View) { - v.getHitRect(hitRect); - View parent = (View)v.getParent(); - dayView.offsetDescendantRectToMyCoords(parent, hitRect); - DotsEntryActivity.this.editDose(curday, regIndex, dotsData.days()[curday], hitRect); - } else{ - hitRect = new Rect(0,0,v.getWidth(), v.getHeight()); - dayView.offsetDescendantRectToMyCoords(v, hitRect); - DotsEntryActivity.this.editDose(curday, regIndex, dotsData.days()[curday], hitRect); - } - }); - } - - View next = dayView.findViewById(R.id.btn_doses_next); - if(curday == dotsData.days().length - 1) { - next.setVisibility(View.INVISIBLE); - } else{ - next.setOnClickListener(v -> tryMove(1)); - } - View prev = dayView.findViewById(R.id.btn_doses_prev); - if(curday == 0) { - prev.setVisibility(View.INVISIBLE); - } else{ - prev.setOnClickListener(v -> tryMove(-1)); - } - - Button done = dayView.findViewById(R.id.btn_dots_doses_done); - done.setOnClickListener(v -> DotsEntryActivity.this.cancelDayEdit(curday)); - return dayView; - } - - private ViewGroup getDoseView(DotsDay d, int dayIndex, int regimenIndex) { - - int[] boxes = d.getRegIndexes(regimenIndex); - boolean empty = true; - for(int i : boxes ){ - if(i!= -1) { - empty = false; - } - } - if(empty) { return null; } - - Calendar c = Calendar.getInstance(); - c.setTime(dotsData.anchor()); - c.roll(Calendar.DATE, dotsData.days().length - dayIndex + 1); - - ViewGroup doseView = (ViewGroup)View.inflate(this, R.layout.dotsdose, null); - TextView dosename = doseView.findViewById(R.id.text_dosename); - TableLayout table = doseView.findViewById(R.id.dose_table); - table.setPadding(0,0,2,0); - table.setShrinkAllColumns(true); - - TableRow doses = table.findViewById(R.id.dose_status); - TableRow selfReported = table.findViewById(R.id.self_report_row); - - dosename.setText(DotsDetailView.labels[d.getMaxReg() -1 ][regimenIndex]); - - doses.removeAllViews(); - - for(int i = 0 ; i < boxes.length ; ++i) { - if(boxes[i] == -1) { - continue; - } - DotsBox box = d.boxes()[i][boxes[i]]; - ImageView status = new ImageView(this); - status.setPadding(0,0,1,0); - switch(box.status()) { - case full: - status.setImageResource(R.drawable.redx); - break; - case partial: - status.setImageResource(R.drawable.blues); - break; - case empty: - status.setImageResource(R.drawable.checkmark); - break; - case unchecked: - status.setImageResource(R.drawable.blueq); - break; - } - - doses.addView(status); - - ImageView selfReport = new ImageView(this); - selfReport.setPadding(0,3,1,0); - switch(box.reportType()) { - case direct: - selfReport.setImageResource(R.drawable.eye); - break; - case pillbox: - selfReport.setImageResource(R.drawable.pillbox); - break; - case self: - selfReport.setImageResource(R.drawable.greencircle); - break; - } - selfReported.addView(selfReport); - } - - return doseView; - } - - @Override - public void editDose(int dayIndex, int regimenIndex, DotsDay day, Rect hitRect) { - curday = dayIndex; - curdose = regimenIndex; - Calendar c = Calendar.getInstance(); - c.setTime(dotsData.anchor()); - c.roll(Calendar.DATE, dotsData.days().length - dayIndex + 1); - - ddv = new DotsDetailView(); - showView(ddv.LoadDotsDetailView(this, day, dayIndex, regimenIndex, this), AnimationType.fade); - } -} diff --git a/app/src/org/commcare/utils/DotsData.java b/app/src/org/commcare/utils/DotsData.java deleted file mode 100644 index d42c4695ca..0000000000 --- a/app/src/org/commcare/utils/DotsData.java +++ /dev/null @@ -1,417 +0,0 @@ -package org.commcare.utils; - -import org.javarosa.core.model.utils.DateUtils; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; - -import java.util.Date; - -/** - * @author ctsims - */ -public class DotsData { - private Date anchor; - - private int[] regimens; - - private DotsDay[] days; - - //Labels within each regimen for what kind of dose new days should be - private final int[][] regLabels; - - private static final int[][] equivM = new int[][]{ - new int[]{0, -1, -1, -1}, - new int[]{0, -1, 1, -1}, - new int[]{0, 1, 2, -1}, - new int[]{0, 1, 2, 3} - }; - - public enum MedStatus { - unchecked, - full, - empty, - partial - } - - public enum ReportType { - direct, - pillbox, - self - } - - public static final class DotsBox { - - final MedStatus status; - final String missedMeds; - final ReportType type; - final int doseLabel; - - public DotsBox(MedStatus status, ReportType type, String missedMeds, int doselabel) { - this.status = status; - this.missedMeds = missedMeds; - this.type = type; - this.doseLabel = doselabel; - } - - public MedStatus status() { - return status; - } - - public String missedMeds() { - return missedMeds; - } - - public ReportType reportType() { - return type; - } - - public int getDoseLabel() { - return doseLabel; - } - - public static DotsBox deserialize(String box) { - try { - return DotsBox.deserialize(new JSONArray(new JSONTokener(box))); - } catch (JSONException e) { - throw new RuntimeException(e); - } - } - - public static DotsBox deserialize(JSONArray box) throws JSONException { - String missed = null; - if (box.length() > 2) { - missed = box.getString(2); - } - int label = -1; - if (box.length() > 3) { - label = box.getInt(3); - } - - String status = box.getString(0); - String type = box.getString(1); - return new DotsBox(MedStatus.valueOf(status), ReportType.valueOf(type), missed, label); - } - - public JSONArray serialize() { - JSONArray ser = new JSONArray(); - ser.put(status.toString()); - ser.put(type.toString()); - if (missedMeds != null) { - ser.put(missedMeds); - } else { - ser.put(""); - } - ser.put(doseLabel); - return ser; - } - - public DotsBox update(DotsBox deserialize) { - return new DotsBox(deserialize.status, deserialize.type, - deserialize.missedMeds == null ? this.missedMeds : deserialize.missedMeds, - deserialize.doseLabel == -1 ? this.doseLabel : deserialize.doseLabel); - } - } - - public static final class DotsDay { - - final DotsBox[][] boxes; - - public DotsDay(DotsBox[][] boxes) { - this.boxes = boxes; - } - - public DotsBox[][] boxes() { - return boxes; - } - - /** - * Whether this box contains the default observations for a - * new day object. - * - * @return True if the day is indistinguishable from a default day, - * false otherwise - */ - public boolean isDefault() { - for (DotsBox[] dotBoxes : boxes) { - for (int j = 0; j < dotBoxes.length; ++j) { - if (dotBoxes[j].status != MedStatus.unchecked) { - return false; - } - } - } - return true; - } - - public JSONArray serialize() { - JSONArray day = new JSONArray(); - for (DotsBox[] dotBoxes : boxes) { - JSONArray regimen = new JSONArray(); - for (int j = 0; j < dotBoxes.length; ++j) { - regimen.put(dotBoxes[j].serialize()); - } - day.put(regimen); - } - return day; - } - - public static DotsDay deserialize(String day) { - try { - return deserialize(new JSONArray(new JSONTokener(day))); - } catch (JSONException e) { - throw new RuntimeException(e); - } - } - - public static DotsDay deserialize(JSONArray day) throws JSONException { - DotsBox[][] fullDay = new DotsBox[day.length()][]; - for (int i = 0; i < day.length(); ++i) { - JSONArray regimen = day.getJSONArray(i); - DotsBox[] boxes = new DotsBox[regimen.length()]; - for (int j = 0; j < regimen.length(); ++j) { - boxes[j] = DotsBox.deserialize(regimen.getJSONArray(j)); - } - fullDay[i] = boxes; - } - return new DotsDay(fullDay); - - } - - public int getMaxReg() { - return 4; -// int max = 0; -// for(DotsBox[] reg : boxes) { -// if(reg.length > max) { -// max = reg.length; -// } -// } -// return max; - } - - /** - * Takes in a index between 0 and 3 representing a potential dose, and - * returns either an index between 0 and 3 representing the actual dose - * window (AM, Noon, etc) represented by the box at that index. - * - * @param regimenIndex the index of a potential dose (AM,noon,pm, etc) - * which may be occurring. - */ - public int[] getRegIndexes(int regimenIndex) { - int max = this.getMaxReg(); - int[] retVal = new int[boxes.length]; - //ART v. non-ART - regimen: - for (int i = 0; i < boxes.length; ++i) { - if (boxes[i].length == 0) { - retVal[i] = -1; - } else { - //See if there's an explicitly labeled index for - //this regimen - for (int j = 0; j < boxes[i].length; ++j) { - if (boxes[i][j].doseLabel == regimenIndex) { - retVal[i] = j; - continue regimen; - } - } - - //otherwise, grab what the default one should be - int defaultIndex = equivM[boxes[i].length - 1][regimenIndex]; - - //Make sure the default index is either unused (-1), or if not, isn't - //actually pointing to something already - if (defaultIndex == -1 || boxes[i][defaultIndex].doseLabel == -1) { - retVal[i] = defaultIndex; - } else { - retVal[i] = -1; - } - } - } - return retVal; - } - - public DotsDay updateDose(int dose, DotsBox[] newboxes) { - int[] indices = getRegIndexes(dose); - for (int i = 0; i < boxes.length; ++i) { - if (indices[i] == -1) { - //Nothing to do - } else { - this.boxes[i][indices[i]] = newboxes[i]; - } - } - return this; - } - - public MedStatus status() { - MedStatus ret = null; - for (DotsBox[] dotBoxes : boxes) { - for (int j = 0; j < dotBoxes.length; ++j) { - DotsBox b = dotBoxes[j]; - if (ret == null) { - if (b.status != MedStatus.unchecked) { - ret = MedStatus.empty; - } else { - ret = MedStatus.unchecked; - } - } else { - if (ret == MedStatus.unchecked) { - if (b.status != MedStatus.unchecked) { - return MedStatus.partial; - } - } else if (ret == MedStatus.empty) { - if (b.status == MedStatus.unchecked) { - return MedStatus.partial; - } - } - } - } - } - if (ret == null) { - return MedStatus.unchecked; - } else { - return ret; - } - } - } - - public DotsDay[] days() { - return days; - } - - public Date anchor() { - return anchor; - } - - - private DotsData(Date anchor, int[] regimens, DotsDay[] days, int[][] regLabels) { - this.anchor = anchor; - this.regimens = regimens; - this.days = days; - this.regLabels = regLabels; - } - - - public int recenter(int[] regimens, Date newAnchor) { - this.regimens = regimens; - int difference = DateUtils.dateDiff(anchor, newAnchor); - if (difference == 0) { - return 0; - } - DotsDay[] newDays = new DotsDay[this.days.length]; - for (int i = 0; i < newDays.length; ++i) { - if (difference + i >= 0 && difference + i < this.days.length) { - newDays[i] = this.days[difference + i]; - } else { - newDays[i] = new DotsDay(emptyBoxes(this.regimens, this.regLabels)); - } - } - this.anchor = newAnchor; - this.days = newDays; - return difference; - } - - public String SerializeDotsData() { - - try { - JSONObject object = new JSONObject(); - object.put("anchor", anchor.toGMTString()); - JSONArray jRegs = new JSONArray(); - for (int i : regimens) { - jRegs.put(i); - } - object.put("regimens", jRegs); - - JSONArray jDays = new JSONArray(); - for (DotsDay day : days) { - jDays.put(day.serialize()); - } - if (this.regLabels != null) { - JSONArray regLabelJson = new JSONArray(); - for (int[] labels : regLabels) { - JSONArray regLabelSub = new JSONArray(); - for (int j = 0; j < labels.length; ++j) { - regLabelSub.put(labels[j]); - } - regLabelJson.put(regLabelSub); - } - object.put("regimen_labels", regLabelJson); - } - - object.put("days", jDays); - - return object.toString(); - } catch (JSONException e) { - throw new RuntimeException(e); - } - } - - public static DotsData DeserializeDotsData(String dots) { - - try { - JSONObject data = new JSONObject(new JSONTokener(dots)); - - Date anchor = new Date(Date.parse(data.getString("anchor"))); - - JSONArray jRegs = data.getJSONArray("regimens"); - int[] regs = new int[jRegs.length()]; - for (int i = 0; i < regs.length; ++i) { - regs[i] = jRegs.getInt(i); - } - - int[][] regLabels = new int[regs.length][]; - if (data.has("regimen_labels")) { - JSONArray jRegLabels = data.getJSONArray("regimen_labels"); - if (jRegLabels.length() != regs.length) { - //TODO: specific exception type here - throw new RuntimeException("Invalid DOTS model! Regimens and Labels are incompatible lengths"); - } - for (int i = 0; i < jRegLabels.length(); ++i) { - JSONArray jLabels = jRegLabels.getJSONArray(i); - regLabels[i] = new int[jLabels.length()]; - for (int j = 0; j < jLabels.length(); ++j) { - regLabels[i][j] = jLabels.getInt(j); - } - } - } else { - //No default regimen labels - regLabels = null; - } - - JSONArray jDays = data.getJSONArray("days"); - DotsDay[] days = new DotsDay[jDays.length()]; - for (int i = 0; i < days.length; ++i) { - days[i] = DotsDay.deserialize(jDays.getJSONArray(i)); - } - - return new DotsData(anchor, regs, days, regLabels); - } catch (JSONException e) { - throw new RuntimeException(e); - } - - - } - - public static DotsData CreateDotsData(int[] regType, Date anchor) { - DotsDay[] days = new DotsDay[21]; - for (int j = 0; j < days.length; ++j) { - days[j] = new DotsDay(emptyBoxes(regType, null)); - } - - return new DotsData(anchor, regType, days, null); - } - - private static DotsBox[][] emptyBoxes(int[] lengths, int[][] regLabels) { - DotsBox[][] boxes = new DotsBox[lengths.length][]; - for (int i = 0; i < lengths.length; ++i) { - boxes[i] = new DotsBox[lengths[i]]; - for (int j = 0; j < boxes[i].length; ++j) { - int label = -1; - if (regLabels != null) { - label = regLabels[i][j]; - } - boxes[i][j] = new DotsBox(MedStatus.unchecked, ReportType.pillbox, null, label); - } - } - return boxes; - } -} diff --git a/app/src/org/commcare/utils/DotsEditListener.java b/app/src/org/commcare/utils/DotsEditListener.java deleted file mode 100644 index bc14fc3e27..0000000000 --- a/app/src/org/commcare/utils/DotsEditListener.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.commcare.utils; - -import android.graphics.Rect; - -import org.commcare.utils.DotsData.DotsDay; - -/** - * @author ctsims - */ -public interface DotsEditListener { - void editDotsDay(int i, Rect datRect); - - void editDose(int dayIndex, int regimenIndex, DotsDay day, Rect hitRect); - - void doneWithDOTS(); - - void cancelDayEdit(int day); - - void cancelDoseEdit(); - - void dayEdited(int i, DotsDay day); - - void shiftDay(int delta); -} diff --git a/app/src/org/commcare/views/DotsDetailView.java b/app/src/org/commcare/views/DotsDetailView.java deleted file mode 100644 index 78729e64ac..0000000000 --- a/app/src/org/commcare/views/DotsDetailView.java +++ /dev/null @@ -1,278 +0,0 @@ -/** - * - */ -package org.commcare.views; - -import android.content.Context; -import android.content.res.Configuration; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.ToggleButton; - -import org.commcare.dalvik.R; -import org.commcare.utils.DotsData.DotsBox; -import org.commcare.utils.DotsData.DotsDay; -import org.commcare.utils.DotsData.MedStatus; -import org.commcare.utils.DotsData.ReportType; -import org.commcare.utils.DotsEditListener; - -/** - * @author ctsims - * - */ -public class DotsDetailView { - - private static final String DOSE_MORNING = "Morning"; - private static final String DOSE_NOON = "Noon"; - private static final String DOSE_EVENING = "Evening"; - private static final String DOSE_BEDTIME = "Bedtime"; - private static final String DOSE_UNKNOWN = "Dose"; - - - static final String[] labelMap = new String [] {DOSE_MORNING, DOSE_NOON, DOSE_EVENING, DOSE_BEDTIME}; - - //For unnamed labels, these are the defaults. - //TODO: 90% sure that only the last one here is relevant. - public final static String[][] labels = new String[][] { - new String[] {DOSE_UNKNOWN}, - new String[] {DOSE_MORNING, DOSE_EVENING}, - new String[] {DOSE_MORNING, DOSE_NOON, DOSE_EVENING}, - new String[] {DOSE_MORNING, DOSE_NOON, DOSE_EVENING, DOSE_BEDTIME} - }; - - public final static String[] regimens = new String[] { "Non-ART", "ART"}; - - View[] groups; - EditText[] missedName; - DotsDay day; - int index; - int dose; - - public DotsDetailView() { - - } - - public View LoadDotsDetailView(Context context, DotsDay day, int index, int dose, final DotsEditListener listener) { - this.day = day; - this.index = index; - this.dose = dose; - - View view = View.inflate(context, R.layout.dots_detail, null); - - LinearLayout container = view.findViewById(R.id.dots_content_frame); - - container.removeAllViews(); - - //groups = new RadioGroup[day.boxes().length]; - groups = new View[day.boxes().length]; - missedName = new EditText[day.boxes().length]; - - int[] regimenIndices = day.getRegIndexes(dose); - - for(int i = 0; i < day.boxes().length; ++i) { - int subIndex = regimenIndices[i]; - if(subIndex == -1) { - continue; - } - DotsBox box = day.boxes()[i][subIndex]; - final View details = View.inflate(context, R.layout.compact_dot_entry, null); - groups[i] = details; - TextView timeView = details.findViewById(R.id.text_time); - - int doseName = box.getDoseLabel(); - String label = ""; - if(doseName == -1) { - label = labels[day.getMaxReg() -1 ][dose]; - } else { - if(doseName >= 0 && doseName < labelMap.length) { - label = labelMap[doseName]; - } else { - label = DOSE_UNKNOWN; - } - } - timeView.setText(regimens[i] + ": " + label); - - details.setPadding(0, 0, 0,0); - - final View missingDetails = details.findViewById(R.id.missed_details); - missedName[i] = details.findViewById(R.id.text_missed); - - //groups[i] = (RadioGroup)details.findViewById(R.id.dose_group); - - int type = R.id.tbt_pillbox; - - switch(box.reportType()) { - case self: - type = R.id.tbt_self; - break; - case pillbox: - type = R.id.tbt_pillbox; - break; - case direct: - type = R.id.tbt_direct; - break; - } - - ToggleButton selectedReportType = details.findViewById(type); - selectedReportType.setChecked(true); - - int checked = -1; - - switch(box.status()) { - case empty: - checked = R.id.radio_all; - break; - case partial: - checked = R.id.radio_some; - missedName[i].setText(box.missedMeds()); - missingDetails.setVisibility(View.VISIBLE); - break; - case full: - checked = R.id.radio_none; - break; - case unchecked: - checked = R.id.radio_unchecked; - break; - } - - ToggleButton checkedToggle = details.findViewById(checked); - checkedToggle.setChecked(true); - - //set up listeners - final int[] ids = new int[] {R.id.radio_all, R.id.radio_some, R.id.radio_unchecked, R.id.radio_none}; - for(int id : ids) { - ToggleButton toggle = details.findViewById(id); - toggle.setOnClickListener(v -> { - for(int id1 : ids) { - if(v.getId() == id1) { - ((ToggleButton)v).setChecked(true); - } else { - ToggleButton toggle1 = details.findViewById(id1); - toggle1.setChecked(false); - } - - if(v.getId() == R.id.radio_some) { - missingDetails.setVisibility(View.VISIBLE); - } else { - missingDetails.setVisibility(View.GONE); - } - } - }); - } - - //set up listeners - final int[] typeids = new int[] {R.id.tbt_direct, R.id.tbt_pillbox, R.id.tbt_self}; - for(int id : typeids) { - ToggleButton toggle = details.findViewById(id); - toggle.setOnClickListener(v -> { - for(int id12 : typeids) { - if(v.getId() == id12) { - ((ToggleButton)v).setChecked(true); - } else { - ToggleButton toggle12 = details.findViewById(id12); - toggle12.setChecked(false); - } - } - }); - } - - if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.FILL_PARENT); - params.leftMargin = 10; - params.rightMargin = 10; - params.weight = 1f / day.boxes().length; - container.addView(details, params); - container.setOrientation(LinearLayout.HORIZONTAL); - } else { - container.addView(details, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT)); - } - } - - Button ok = view.findViewById(R.id.btn_dots_detail_ok); - Button cancel = view.findViewById(R.id.btn_dots_detail_cancel); - - ok.setOnClickListener(v -> listener.dayEdited(DotsDetailView.this.index, DotsDetailView.this.getDay())); - - cancel.setOnClickListener(v -> listener.cancelDoseEdit()); - - return view; - } - - public DotsDay getDay() { - - int[] regIndices = day.getRegIndexes(dose); - //TODO: This is basically a shallow copy - DotsBox[] newBoxes = new DotsBox[regIndices.length]; - - - //Now go fill in the new data - for(int i =0 ; i < regIndices.length ; ++i) { - if(regIndices[i] == -1) { - newBoxes[i] = null; - continue; - } - - int checkedButton = -1; - //Retrieve the selected value - int[] ids = new int[] {R.id.radio_all, R.id.radio_some, R.id.radio_unchecked, R.id.radio_none}; - for(int id : ids) { - ToggleButton button = groups[i].findViewById(id); - if(button.isChecked()) { - checkedButton = id; - } - } - - int reportType = -1; - //Retrieve the selected value - int[] reportids = new int[] {R.id.tbt_direct, R.id.tbt_pillbox, R.id.tbt_self}; - for(int id : reportids) { - ToggleButton button = groups[i].findViewById(id); - if(button.isChecked()) { - reportType = id; - } - } - - - MedStatus status = MedStatus.unchecked; - String meds = null; - - switch(checkedButton) { - case R.id.radio_all: - status= MedStatus.empty; - break; - case R.id.radio_some: - status = MedStatus.partial; - meds = missedName[i].getText().toString(); - break; - case R.id.radio_none: - status = MedStatus.full; - break; - case R.id.radio_unchecked: - status = MedStatus.unchecked; - break; - } - - ReportType type = ReportType.pillbox; - - switch(reportType) { - case R.id.tbt_direct: - type = ReportType.direct; - break; - case R.id.tbt_pillbox: - type = ReportType.pillbox; - break; - case R.id.tbt_self: - type = ReportType.self; - break; - } - - newBoxes[i] = new DotsBox(status,type, meds, day.boxes()[i][regIndices[i]].getDoseLabel()); - } - - return day.updateDose(dose, newBoxes); - } -} diff --git a/app/src/org/commcare/views/DotsHomeView.java b/app/src/org/commcare/views/DotsHomeView.java deleted file mode 100755 index 05d53531b2..0000000000 --- a/app/src/org/commcare/views/DotsHomeView.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.commcare.views; - -import android.content.Context; -import android.graphics.Rect; -import android.view.Gravity; -import android.view.View; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TableLayout; -import android.widget.TableRow; -import android.widget.TextView; - -import com.google.android.material.button.MaterialButton; - - -import org.commcare.dalvik.R; -import org.commcare.utils.DotsData; -import org.commcare.utils.DotsData.DotsDay; -import org.commcare.utils.DotsData.MedStatus; -import org.commcare.utils.DotsEditListener; - -import java.util.Calendar; - -/** - * @author ctsims - */ -public class DotsHomeView extends RelativeLayout { - - private final DotsData data; - private final DotsEditListener listener; - private static final String[] dayArray = new String[]{"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}; - - private static final int TABLE_LENGTH = 7; - - public DotsHomeView(Context context, DotsData data, DotsEditListener listener) { - super(context); - this.data = data; - this.listener = listener; - refresh(); - } - - private void refresh() { - this.removeAllViews(); - - TableLayout table = new TableLayout(this.getContext()); - - int days = data.days().length; - int rows = (int)Math.ceil(days / TABLE_LENGTH); - - View[] dayViews = new View[days]; - - table.setShrinkAllColumns(true); - table.setStretchAllColumns(true); - - TableRow[] tRows = new TableRow[rows]; - - for (int i = 0; i < tRows.length; ++i) { - tRows[i] = new TableRow(this.getContext()); - } - - Calendar c = Calendar.getInstance(); - c.setTime(data.anchor()); - c.add(Calendar.DATE, -(data.days().length - 1)); - - int currentRow = 0; - - for (int i = 0; i < days; ++i) { - DotsDay day = data.days()[i]; - - TableRow.LayoutParams dayParams = new TableRow.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - dayParams.setMargins(1, 1, 1, 1); - - - View dayView = getDayView(c, day, i); - - tRows[currentRow].addView(dayView); - dayViews[i] = dayView; - if (i % TABLE_LENGTH == TABLE_LENGTH - 1) { - currentRow = currentRow + 1; - } - - c.add(Calendar.DATE, 1); - } - - for (TableRow row : tRows) { - table.addView(row); - } - - Button done = new MaterialButton(this.getContext()); - done.setId(666); - done.setText("Finished"); - done.setOnClickListener(v -> listener.doneWithDOTS()); - - - RelativeLayout topPane = new RelativeLayout(this.getContext()); - LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - params.addRule(RelativeLayout.ABOVE, done.getId()); - params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE); - this.addView(topPane, params); - - table.setGravity(Gravity.CENTER_VERTICAL); - params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE); - topPane.addView(table, params); - - params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); - this.addView(done, params); - } - - - private View getDayView(Calendar c, DotsDay d, final int dayIndex) { - View dayView = View.inflate(this.getContext(), R.layout.dotsday, null); - - TextView date = dayView.findViewById(R.id.text_date); - TextView dow = dayView.findViewById(R.id.text_dow); - - dow.setText(dayArray[c.get(Calendar.DAY_OF_WEEK) - 1]); - date.setText((c.get(Calendar.MONTH) + 1) + "/" + c.get(Calendar.DAY_OF_MONTH)); - - ImageView icon = dayView.findViewById(R.id.day_icon); - MedStatus s = d.status(); - if (s == MedStatus.empty) { - icon.setImageResource(R.drawable.checkmark); - } else if (s == MedStatus.partial) { - icon.setImageResource(R.drawable.blues); - } else { - icon.setVisibility(View.INVISIBLE); - } - - dayView.setOnClickListener(v -> { - Rect hitRect = new Rect(); - if (v.getParent() instanceof View) { - v.getHitRect(hitRect); - View parent = (View)v.getParent(); - DotsHomeView.this.offsetDescendantRectToMyCoords(parent, hitRect); - listener.editDotsDay(dayIndex, hitRect); - } else { - hitRect = new Rect(0, 0, v.getWidth(), v.getHeight()); - DotsHomeView.this.offsetDescendantRectToMyCoords(v, hitRect); - listener.editDotsDay(dayIndex, hitRect); - } - }); - - return dayView; - } -} From c4c5f94fba1b6fb0be2d87575bfe1a846a23aa18 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Tue, 19 May 2026 18:30:22 +0200 Subject: [PATCH 3/3] Delete DOTS tracker layout, drawable, and color resources Removes the layouts (dots_detail, dotsday, dotsdose, dotsdoses, compact_dot_entry), drawables (dots_dose_border, dots_rect_back), and the dotscolors values file that were used only by the now-deleted DOTS tracker. No remaining code references these resources. Co-Authored-By: Claude Opus 4.7 --- app/res/drawable/dots_dose_border.xml | 5 - app/res/drawable/dots_rect_back.xml | 12 -- app/res/layout/compact_dot_entry.xml | 168 -------------------------- app/res/layout/dots_detail.xml | 57 --------- app/res/layout/dotsday.xml | 52 -------- app/res/layout/dotsdose.xml | 65 ---------- app/res/layout/dotsdoses.xml | 70 ----------- app/res/values/dotscolors.xml | 20 --- 8 files changed, 449 deletions(-) delete mode 100644 app/res/drawable/dots_dose_border.xml delete mode 100644 app/res/drawable/dots_rect_back.xml delete mode 100644 app/res/layout/compact_dot_entry.xml delete mode 100644 app/res/layout/dots_detail.xml delete mode 100644 app/res/layout/dotsday.xml delete mode 100644 app/res/layout/dotsdose.xml delete mode 100644 app/res/layout/dotsdoses.xml delete mode 100644 app/res/values/dotscolors.xml diff --git a/app/res/drawable/dots_dose_border.xml b/app/res/drawable/dots_dose_border.xml deleted file mode 100644 index 01fedced2e..0000000000 --- a/app/res/drawable/dots_dose_border.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - \ No newline at end of file diff --git a/app/res/drawable/dots_rect_back.xml b/app/res/drawable/dots_rect_back.xml deleted file mode 100644 index e065242988..0000000000 --- a/app/res/drawable/dots_rect_back.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/res/layout/compact_dot_entry.xml b/app/res/layout/compact_dot_entry.xml deleted file mode 100644 index 377ef1e3ff..0000000000 --- a/app/res/layout/compact_dot_entry.xml +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/res/layout/dots_detail.xml b/app/res/layout/dots_detail.xml deleted file mode 100644 index 9d1bb02a12..0000000000 --- a/app/res/layout/dots_detail.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/app/res/layout/dotsday.xml b/app/res/layout/dotsday.xml deleted file mode 100644 index f05fcd1c4a..0000000000 --- a/app/res/layout/dotsday.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - diff --git a/app/res/layout/dotsdose.xml b/app/res/layout/dotsdose.xml deleted file mode 100644 index 84110c34a2..0000000000 --- a/app/res/layout/dotsdose.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/app/res/layout/dotsdoses.xml b/app/res/layout/dotsdoses.xml deleted file mode 100644 index 2a84d168db..0000000000 --- a/app/res/layout/dotsdoses.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/res/values/dotscolors.xml b/app/res/values/dotscolors.xml deleted file mode 100644 index 18b0ba0f20..0000000000 --- a/app/res/values/dotscolors.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - #0000FF - #5050BF -