diff --git a/gradle.properties b/gradle.properties index 6c710543..a411b230 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=0.1.5-SNAPSHOT +VERSION_NAME=0.2.0-alpha-SNAPSHOT VERSION_CODE=1 GROUP=org.smartregister POM_SETTING_DESCRIPTION=OpenSRP Client Reporting Library diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/contract/ReportContract.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/contract/ReportContract.java index c637b3f6..d0c5b149 100644 --- a/opensrp-reporting/src/main/java/org/smartregister/reporting/contract/ReportContract.java +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/contract/ReportContract.java @@ -54,6 +54,8 @@ interface Model { List> getIndicatorsDailyTallies(); + List> getLatestIndicatorTallies(); + } interface IndicatorView { diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/dao/ReportIndicatorDaoImpl.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/dao/ReportIndicatorDaoImpl.java index ea45a78f..30bf7333 100644 --- a/opensrp-reporting/src/main/java/org/smartregister/reporting/dao/ReportIndicatorDaoImpl.java +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/dao/ReportIndicatorDaoImpl.java @@ -84,6 +84,10 @@ public List> getIndicatorsDailyTallies() { return dailyIndicatorCountRepository.getAllDailyTallies(); } + public List> getLatestIndicatorTallies() { + return dailyIndicatorCountRepository.getLatestIndicatorTallies(); + } + @Override public void generateDailyIndicatorTallies(String lastProcessedDate) { SQLiteDatabase database = getReportingLibrary().getRepository().getWritableDatabase(); diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/BaseReportIndicatorsModel.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/BaseReportIndicatorsModel.java index 420f4605..1d9dafa1 100644 --- a/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/BaseReportIndicatorsModel.java +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/BaseReportIndicatorsModel.java @@ -29,4 +29,10 @@ public List> getIndicatorsDailyTallies() { dao.setDailyIndicatorCountRepository(reportingLibrary.dailyIndicatorCountRepository()); return dao.getIndicatorsDailyTallies(); } + + @Override + public List> getLatestIndicatorTallies() { + dao.setDailyIndicatorCountRepository(reportingLibrary.dailyIndicatorCountRepository()); + return dao.getLatestIndicatorTallies(); + } } diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/MultiValueIndicatorTally.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/MultiValueIndicatorTally.java new file mode 100644 index 00000000..63aeeb26 --- /dev/null +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/MultiValueIndicatorTally.java @@ -0,0 +1,25 @@ +package org.smartregister.reporting.domain; + +import java.util.Date; +import java.util.Map; + +public class MultiValueIndicatorTally extends IndicatorTally { + + private Map multiValuesMap; + + public MultiValueIndicatorTally(Long id, int count, String indicatorCode, Date createdAt, Map multiResults) { + super(id, count, indicatorCode, createdAt); + this.multiValuesMap = multiResults; + } + + public MultiValueIndicatorTally() { + } + + public Map getMultiValuesMap() { + return multiValuesMap; + } + + public void setMultiValuesMap(Map multiValuesMap) { + this.multiValuesMap = multiValuesMap; + } +} diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/TabularVisualization.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/TabularVisualization.java new file mode 100644 index 00000000..2a72540c --- /dev/null +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/domain/TabularVisualization.java @@ -0,0 +1,50 @@ +package org.smartregister.reporting.domain; + +import java.util.List; + +public class TabularVisualization extends ReportingIndicatorVisualization { + + private int titleLabelStringResource; + private List tableHeaderList; + private List tableDataList; + private boolean tableHeaderHidden; + + public TabularVisualization(int titleLabelStringResource, List tableHeaderList, List tableDataList, boolean tableHeaderHidden) { + this.titleLabelStringResource = titleLabelStringResource; + this.tableHeaderList = tableHeaderList; + this.tableDataList = tableDataList; + this.tableHeaderHidden = tableHeaderHidden; + } + + public int getTitleLabelStringResource() { + return titleLabelStringResource; + } + + public void setTitleLabelStringResource(int titleLabelStringResource) { + this.titleLabelStringResource = titleLabelStringResource; + } + + public List getTableHeaderList() { + return tableHeaderList; + } + + public void setTableHeaderList(List tableHeaderList) { + this.tableHeaderList = tableHeaderList; + } + + public List getTableDataList() { + return tableDataList; + } + + public void setTableDataList(List tableDataList) { + this.tableDataList = tableDataList; + } + + public boolean isTableHeaderHidden() { + return tableHeaderHidden; + } + + public void setTableHeaderHidden(boolean tableHeaderHidden) { + this.tableHeaderHidden = tableHeaderHidden; + } +} diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/factory/TableDisplayFactory.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/factory/TableDisplayFactory.java new file mode 100644 index 00000000..1085b0ee --- /dev/null +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/factory/TableDisplayFactory.java @@ -0,0 +1,37 @@ +package org.smartregister.reporting.factory; + +import android.content.Context; +import android.graphics.Typeface; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import org.smartregister.reporting.R; +import org.smartregister.reporting.domain.ReportingIndicatorVisualization; +import org.smartregister.reporting.domain.TabularVisualization; +import org.smartregister.reporting.view.TableView; + +import java.util.ArrayList; + +public class TableDisplayFactory implements IndicatorVisualisationFactory { + + @Override + public View getIndicatorView(ReportingIndicatorVisualization visualization, Context context) { + LinearLayout rootLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.table_view_layout, null); + TextView tableTitle = rootLayout.findViewById(R.id.tableViewTitle); + TableView tableView = rootLayout.findViewById(R.id.tableView); + + TabularVisualization tabularVisualization = (TabularVisualization) visualization; + + tableTitle.setText(tabularVisualization.getTitleLabelStringResource()); + tableView.setTableData(tabularVisualization.getTableHeaderList(), tabularVisualization.getTableDataList(), new ArrayList<>(), null); + tableView.setHeaderTextStyle(Typeface.BOLD); + tableView.setRowBorderHidden(false); + tableView.setBorderColor(ContextCompat.getColor(context, R.color.light_grey)); // Default + tableView.setTableHeaderHidden(tabularVisualization.isTableHeaderHidden()); + return rootLayout; + } +} diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/repository/DailyIndicatorCountRepository.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/repository/DailyIndicatorCountRepository.java index 4afb4a6f..cb8069b1 100644 --- a/opensrp-reporting/src/main/java/org/smartregister/reporting/repository/DailyIndicatorCountRepository.java +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/repository/DailyIndicatorCountRepository.java @@ -54,11 +54,26 @@ public class DailyIndicatorCountRepository extends BaseRepository { + Constants.DailyIndicatorCountRepository.INDICATOR_VALUE_SET_FLAG + " BOOLEAN NOT NULL default 0, " + Constants.DailyIndicatorCountRepository.DAY + " DATETIME NOT NULL DEFAULT (DATETIME('now')))"; - private static String CREATE_UNIQUE_CONSTRAINT = "CREATE UNIQUE INDEX indicator_daily_tally_ix ON " + + private static final String CREATE_UNIQUE_CONSTRAINT = "CREATE UNIQUE INDEX indicator_daily_tally_ix ON " + Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE + " ( " + Constants.DailyIndicatorCountRepository.INDICATOR_CODE + " , " + Constants.DailyIndicatorCountRepository.DAY + " ) "; + private static final Object[] dailyIndicatorQueryArgs = { + Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.ID + , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_CODE + , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_VALUE + , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_VALUE_SET + , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_GROUPING + , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_VALUE_SET_FLAG + , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.DAY + , Constants.IndicatorQueryRepository.INDICATOR_QUERY_TABLE, Constants.IndicatorQueryRepository.INDICATOR_QUERY_EXPECTED_INDICATORS + , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE + , Constants.IndicatorQueryRepository.INDICATOR_QUERY_TABLE + , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_CODE + , Constants.IndicatorQueryRepository.INDICATOR_QUERY_TABLE, Constants.IndicatorQueryRepository.INDICATOR_CODE + }; + public static void performMigrations(@NonNull SQLiteDatabase database) { // Perform migrations if (ReportingUtils.isTableExists(database, Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE) @@ -109,15 +124,13 @@ public void add(@Nullable CompositeIndicatorTally indicatorTally) { database.insert(Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, null, createContentValues(indicatorTally)); } - public void updateIndicatorValue(String id, String Value) - { + public void updateIndicatorValue(String id, String Value) { SQLiteDatabase database = getWritableDatabase(); Cursor cursor = null; - try{ - cursor = database.rawQuery("UPDATE "+Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE+" SET "+ Constants.DailyIndicatorCountRepository.INDICATOR_VALUE+" = ? WHERE "+ Constants.DailyIndicatorCountRepository.ID+" = ?",new Object[]{Value,id}); + try { + cursor = database.rawQuery("UPDATE " + Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE + " SET " + Constants.DailyIndicatorCountRepository.INDICATOR_VALUE + " = ? WHERE " + Constants.DailyIndicatorCountRepository.ID + " = ?", new Object[]{Value, id}); cursor.moveToFirst(); - } - catch (Exception ex) { + } catch (Exception ex) { Timber.e(ex.toString()); } finally { if (cursor != null) { @@ -129,49 +142,33 @@ public void updateIndicatorValue(String id, String Value) public List> getAllDailyTallies() { List> indicatorTallies = new ArrayList<>(); - Map tallyMap; - SQLiteDatabase database = getReadableDatabase(); - Object[] queryArgs = { - Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.ID - , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_CODE - , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_VALUE - , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_VALUE_SET - , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_GROUPING - , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_VALUE_SET_FLAG - , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.DAY - , Constants.IndicatorQueryRepository.INDICATOR_QUERY_TABLE, Constants.IndicatorQueryRepository.INDICATOR_QUERY_EXPECTED_INDICATORS - , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE - , Constants.IndicatorQueryRepository.INDICATOR_QUERY_TABLE - , Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE, Constants.DailyIndicatorCountRepository.INDICATOR_CODE - , Constants.IndicatorQueryRepository.INDICATOR_QUERY_TABLE, Constants.IndicatorQueryRepository.INDICATOR_CODE - }; Cursor cursor = null; try { - cursor = database.rawQuery(String.format("SELECT %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, %s.%s FROM %s INNER JOIN %s ON %s.%s = %s.%s", queryArgs) + cursor = database.rawQuery(String.format("SELECT %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, %s.%s FROM %s INNER JOIN %s ON %s.%s = %s.%s", dailyIndicatorQueryArgs) , null); - if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) { - MultiResultProcessor defaultMultiResultProcessor = ReportingLibrary.getInstance().getDefaultMultiResultProcessor(); - ArrayList multiResultProcessors = ReportingLibrary.getInstance().getMultiResultProcessors(); - - while (!cursor.isAfterLast()) { - tallyMap = new HashMap<>(); - CompositeIndicatorTally compositeIndicatorTally = processCursorRow(cursor); - - if (compositeIndicatorTally.isValueSet()) { - extractIndicatorTalliesFromMultiResult(tallyMap, defaultMultiResultProcessor, multiResultProcessors, compositeIndicatorTally); - } else { - tallyMap.put(compositeIndicatorTally.getIndicatorCode(), compositeIndicatorTally); - } + indicatorTallies = processDailyTalliesQueryResults(cursor); + } catch (Exception ex) { + Timber.e(ex.toString()); + } finally { + if (cursor != null) { + cursor.close(); + } + } + return indicatorTallies; + } - if (tallyMap.size() > 0) { - indicatorTallies.add(tallyMap); - } + public List> getLatestIndicatorTallies() { + List> indicatorTallies = new ArrayList<>(); + SQLiteDatabase database = getReadableDatabase(); - cursor.moveToNext(); - } - } + Cursor cursor = null; + try { + cursor = database.rawQuery(String.format("SELECT %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, %s.%s, max(" + Constants.DailyIndicatorCountRepository.DAY + ") as newest_date FROM %s INNER JOIN %s ON %s.%s = %s.%s " + + "GROUP BY " + Constants.DailyIndicatorCountRepository.INDICATOR_DAILY_TALLY_TABLE + "." + Constants.DailyIndicatorCountRepository.INDICATOR_CODE, dailyIndicatorQueryArgs) + , null); + indicatorTallies = processDailyTalliesQueryResults(cursor); } catch (Exception ex) { Timber.e(ex.toString()); } finally { @@ -182,6 +179,32 @@ public List> getAllDailyTallies() { return indicatorTallies; } + private List> processDailyTalliesQueryResults(Cursor cursor) { + List> indicatorTallies = new ArrayList<>(); + Map tallyMap; + if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) { + MultiResultProcessor defaultMultiResultProcessor = ReportingLibrary.getInstance().getDefaultMultiResultProcessor(); + ArrayList multiResultProcessors = ReportingLibrary.getInstance().getMultiResultProcessors(); + + while (!cursor.isAfterLast()) { + tallyMap = new HashMap<>(); + CompositeIndicatorTally compositeIndicatorTally = processCursorRow(cursor); + + if (compositeIndicatorTally.isValueSet()) { + extractIndicatorTalliesFromMultiResult(tallyMap, defaultMultiResultProcessor, multiResultProcessors, compositeIndicatorTally); + } else { + tallyMap.put(compositeIndicatorTally.getIndicatorCode(), compositeIndicatorTally); + } + + if (tallyMap.size() > 0) { + indicatorTallies.add(tallyMap); + } + + cursor.moveToNext(); + } + } + return indicatorTallies; + } @NonNull public ArrayList findDaysWithIndicatorCounts(@NonNull SimpleDateFormat dateFormat, @NonNull Date minDate, @NonNull Date maxDate) { diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/util/AggregationUtil.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/util/AggregationUtil.java index 7f515b22..dfdebfec 100644 --- a/opensrp-reporting/src/main/java/org/smartregister/reporting/util/AggregationUtil.java +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/util/AggregationUtil.java @@ -11,7 +11,7 @@ */ public class AggregationUtil { public static float getTotalIndicatorCount(List> indicatorTallies, - String indicatorKey) { + String indicatorKey) { float count = 0; if (indicatorTallies != null && !indicatorTallies.isEmpty()) { for (Map indicatorTallyMap : indicatorTallies) { @@ -27,7 +27,7 @@ public static float getTotalIndicatorCount(List> ind } public static float getLatestIndicatorCount(List> indicatorTallies, - String indicatorKey) { + String indicatorKey) { float count = 0; //Back date Date currentDate = new Date(Long.MIN_VALUE); diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/util/ReportingUtil.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/util/ReportingUtil.java index 92c7099e..a65bddef 100644 --- a/opensrp-reporting/src/main/java/org/smartregister/reporting/util/ReportingUtil.java +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/util/ReportingUtil.java @@ -62,12 +62,12 @@ public static PieChartDisplayModel getPieChartDisplayModel(List p public static PieChartSlice getPieChartSlice(CountType countType, String indicatorCode, String label, int color, List> indicatorTallies, String key) { - return new PieChartSlice((float) getCount(countType, indicatorCode, indicatorTallies), label, color, key); + return new PieChartSlice(getCount(countType, indicatorCode, indicatorTallies), label, color, key); } public static PieChartSlice getPieChartSlice(CountType countType, String indicatorCode, String label, int color, List> indicatorTallies) { - return new PieChartSlice((float) getCount(countType, indicatorCode, indicatorTallies), label, color, indicatorCode); + return new PieChartSlice(getCount(countType, indicatorCode, indicatorTallies), label, color, indicatorCode); } public static List addPieChartSlices(PieChartSlice... chartSlices) { diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/view/ReportingTableView.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/view/ReportingTableView.java new file mode 100644 index 00000000..d0087058 --- /dev/null +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/view/ReportingTableView.java @@ -0,0 +1,32 @@ +package org.smartregister.reporting.view; + +import static org.smartregister.reporting.util.ReportingUtil.getIndicatorView; + +import android.content.Context; +import android.view.View; + +import androidx.annotation.Nullable; + +import org.smartregister.reporting.contract.ReportContract; +import org.smartregister.reporting.domain.TabularVisualization; +import org.smartregister.reporting.factory.TableDisplayFactory; + +public class ReportingTableView implements ReportContract.IndicatorView{ + + private Context context; + private TableDisplayFactory tableDisplayFactory; + private TabularVisualization tabularVisualization; + + public ReportingTableView(Context context, TabularVisualization visualization) { + this.context = context; + this.tabularVisualization = visualization; + tableDisplayFactory = new TableDisplayFactory(); + } + + @Nullable + @Override + public View createView() { + return getIndicatorView(this.tabularVisualization, tableDisplayFactory, context); + + } +} diff --git a/opensrp-reporting/src/main/java/org/smartregister/reporting/view/TableView.java b/opensrp-reporting/src/main/java/org/smartregister/reporting/view/TableView.java index 2a9027e7..5fed9902 100644 --- a/opensrp-reporting/src/main/java/org/smartregister/reporting/view/TableView.java +++ b/opensrp-reporting/src/main/java/org/smartregister/reporting/view/TableView.java @@ -6,16 +6,17 @@ import android.graphics.drawable.GradientDrawable; import android.os.Bundle; import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import android.util.AttributeSet; -import android.view.Gravity; -import android.widget.LinearLayout; - import org.smartregister.reporting.R; import org.smartregister.reporting.adapter.TableViewWidgetAdapter; @@ -34,7 +35,9 @@ public class TableView extends LinearLayout { private int rowTextColor; private int borderColor; private int headerTextStyle; + private int tableHeight = 0; private Boolean isRowBorderHidden; + private Boolean isTableHeaderHidden; private OnClickListener onRowClickListener; private List tableDataRowIds = new ArrayList<>(); @@ -47,6 +50,8 @@ public class TableView extends LinearLayout { private static final String TABLEVIEW_INSTANCE_STATE = "tableview_instance_state"; private static final String TABLEVIEW_ROWTEXT_COLOR = "tableview_rowtext_color"; private static final String TABLEVIEW_ROWTBORDER_HIDDEN = "tableview_rowborder_color"; + private static final String TABLEVIEW_HEADER_HIDDEN = "tableview_header_hidden"; + private static final String TABLEVIEW_HEIGHT = "tableview_height"; public TableView(Context context) { super(context); @@ -102,6 +107,8 @@ protected void setupAttributes(AttributeSet attrs) { style.rowTextColor = rowTextColor; style.headerTextStyle = headerTextStyle; style.isRowBorderHidden = isRowBorderHidden; + style.isTableHeaderHidden = isTableHeaderHidden; + style.tableHeight = tableHeight; resetHeaderLayoutParams(style); resetLayoutParams(style); @@ -119,6 +126,10 @@ protected TypedArray getStyledAttributes() { private void resetHeaderLayoutParams(TextViewStyle style) { RecyclerView recycler = findViewById(R.id.tableViewHeaderRecyclerViewGridLayout); + if (style.isTableHeaderHidden) { + recycler.setVisibility(View.GONE); + return; + } recycler.setHasFixedSize(true); if (style.headerBackgroundColor != 0) { recycler.setBackgroundColor(style.headerBackgroundColor); @@ -136,6 +147,12 @@ private void resetLayoutParams(TextViewStyle style) { RecyclerView recycler = findViewById(R.id.tableViewRecyclerViewGridLayout); recycler.setHasFixedSize(true); + if (tableHeight > 0) { + ViewGroup.LayoutParams layoutParams = recycler.getLayoutParams(); + layoutParams.height = tableHeight; + recycler.setLayoutParams(layoutParams); + } + setTableViewBorderColor(style.borderColor == 0 && style.headerBackgroundColor != 0 ? style.headerBackgroundColor : style.borderColor); RecyclerView.LayoutManager manager = new GridLayoutManager(getContext(), getColumnCount(), GridLayoutManager.VERTICAL, false); @@ -169,7 +186,8 @@ public Parcelable onSaveInstanceState() { bundle.putInt(TABLEVIEW_BORDER_COLOR, this.borderColor); bundle.putInt(TABLEVIEW_ROWTEXT_COLOR, this.rowTextColor); bundle.putBoolean(TABLEVIEW_ROWTBORDER_HIDDEN, this.isRowBorderHidden); - + bundle.putBoolean(TABLEVIEW_HEADER_HIDDEN, this.isTableHeaderHidden); + bundle.putInt(TABLEVIEW_HEIGHT, this.tableHeight); return bundle; } @@ -188,6 +206,8 @@ public void onRestoreInstanceState(Parcelable state) { this.rowTextColor = bundle.getInt(TABLEVIEW_ROWTEXT_COLOR); this.headerTextStyle = bundle.getInt(TABLEVIEW_HEADER_TEXTSTYLE); this.isRowBorderHidden = bundle.getBoolean(TABLEVIEW_ROWTBORDER_HIDDEN); + this.isTableHeaderHidden = bundle.getBoolean(TABLEVIEW_HEADER_HIDDEN); + this.tableHeight = bundle.getInt(TABLEVIEW_HEIGHT); updatedState = bundle.getParcelable(TABLEVIEW_INSTANCE_STATE);// Load base view state back } @@ -246,7 +266,8 @@ private void setResourceValues(TypedArray typedArray) { borderColor = borderColor != 0 ? borderColor : typedArray.getColor(R.styleable.TableView_borderColor, 0); headerTextStyle = headerTextStyle != 0 ? headerTextStyle : typedArray.getInteger(R.styleable.TableView_headerTextStyle, 0); isRowBorderHidden = isRowBorderHidden != null ? isRowBorderHidden : typedArray.getBoolean(R.styleable.TableView_rowBorderHidden, false); - + isTableHeaderHidden = isTableHeaderHidden != null ? isTableHeaderHidden : typedArray.getBoolean(R.styleable.TableView_headerHidden, false); + tableHeight = tableHeight != 0 ? tableHeight : typedArray.getInt(R.styleable.TableView_tableHeight, 0); } public int getHeaderTextColor() { @@ -297,12 +318,29 @@ public void setHeaderTextStyle(int headerTextStyle) { public boolean isRowBorderHidden() { return isRowBorderHidden; } + public boolean isTableHeaderHidden() { + return isTableHeaderHidden; + } public void setRowBorderHidden(boolean rowBorderHidden) { isRowBorderHidden = rowBorderHidden; refreshLayout(); } + public void setTableHeaderHidden(boolean tableHeaderHidden) { + isTableHeaderHidden = tableHeaderHidden; + refreshLayout(); + } + + public int getTableHeight() { + return tableHeight; + } + + public void setTableHeight(int tableHeight) { + this.tableHeight = tableHeight; + refreshLayout(); + } + public class TextViewStyle { public int headerTextColor; public int headerBackgroundColor; @@ -310,5 +348,7 @@ public class TextViewStyle { public int borderColor; public int headerTextStyle; public boolean isRowBorderHidden; + public boolean isTableHeaderHidden; + public int tableHeight; } } diff --git a/opensrp-reporting/src/main/res/layout/table_view_layout.xml b/opensrp-reporting/src/main/res/layout/table_view_layout.xml new file mode 100644 index 00000000..4318c442 --- /dev/null +++ b/opensrp-reporting/src/main/res/layout/table_view_layout.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/opensrp-reporting/src/main/res/values/attrs_table_view.xml b/opensrp-reporting/src/main/res/values/attrs_table_view.xml index bda9c2d3..acc31c23 100644 --- a/opensrp-reporting/src/main/res/values/attrs_table_view.xml +++ b/opensrp-reporting/src/main/res/values/attrs_table_view.xml @@ -11,5 +11,7 @@ + + \ No newline at end of file diff --git a/opensrp-reporting/src/main/res/values/strings.xml b/opensrp-reporting/src/main/res/values/strings.xml index ce4805fe..660aad57 100644 --- a/opensrp-reporting/src/main/res/values/strings.xml +++ b/opensrp-reporting/src/main/res/values/strings.xml @@ -3,4 +3,5 @@ Dashboard Some reports might be inaccurate Currently generating in-app reporting indicators + Table data diff --git a/opensrp-reporting/src/test/java/org/smartregister/reporting/dao/ReportIndicatorDaoImplTest.java b/opensrp-reporting/src/test/java/org/smartregister/reporting/dao/ReportIndicatorDaoImplTest.java index 76005a5d..0a7729ec 100644 --- a/opensrp-reporting/src/test/java/org/smartregister/reporting/dao/ReportIndicatorDaoImplTest.java +++ b/opensrp-reporting/src/test/java/org/smartregister/reporting/dao/ReportIndicatorDaoImplTest.java @@ -166,8 +166,6 @@ public void testGenerateDailyIndicatorTalliesCallsSaveTalliesEqualToNumberOfRepo @Test public void saveTalliesGeneratesTallyObject() { - - SQLiteDatabase database = Mockito.mock(SQLiteDatabase.class); Map indicatorQueries = new HashMap<>(); Map.Entry dates = new Map.Entry() { @@ -212,24 +210,29 @@ public Date setValue(Date value) { } @Test - public void testAddReportIndicator() { + public void testCanAddReportIndicator() { reportIndicatorDao.addReportIndicator(reportIndicator); - Assert.assertNotNull(indicatorRepository); + Mockito.verify(indicatorRepository).add(Mockito.any(ReportIndicator.class)); } @Test - public void testAddIndicatorQuery() { + public void testCanAddIndicatorQuery() { @Nullable List expectedIndicators = new ArrayList<>(); expectedIndicators.add(0, "indicator1"); IndicatorQuery indicatorQuery = new IndicatorQuery(); indicatorQuery.setDbVersion(2); indicatorQuery.setExpectedIndicators(expectedIndicators); - indicatorQuery.setId(Mockito.anyLong()); + indicatorQuery.setId(2L); indicatorQuery.setIndicatorCode("indicatorCode"); reportIndicatorDao.addIndicatorQuery(indicatorQuery); - Assert.assertNotNull(indicatorQueryRepository); + Mockito.verify(indicatorQueryRepository).add(Mockito.any(IndicatorQuery.class)); } + @Test + public void canGetLatestIndicatorTallies() { + reportIndicatorDao.getLatestIndicatorTallies(); + Mockito.verify(dailyIndicatorCountRepository).getLatestIndicatorTallies(); + } } \ No newline at end of file diff --git a/opensrp-reporting/src/test/java/org/smartregister/reporting/view/NumericDisplayFactoryTest.java b/opensrp-reporting/src/test/java/org/smartregister/reporting/factory/NumericDisplayFactoryTest.java similarity index 95% rename from opensrp-reporting/src/test/java/org/smartregister/reporting/view/NumericDisplayFactoryTest.java rename to opensrp-reporting/src/test/java/org/smartregister/reporting/factory/NumericDisplayFactoryTest.java index 387d3391..4e74bcba 100644 --- a/opensrp-reporting/src/test/java/org/smartregister/reporting/view/NumericDisplayFactoryTest.java +++ b/opensrp-reporting/src/test/java/org/smartregister/reporting/factory/NumericDisplayFactoryTest.java @@ -1,4 +1,4 @@ -package org.smartregister.reporting.view; +package org.smartregister.reporting.factory; import android.content.Context; import android.view.LayoutInflater; @@ -21,7 +21,6 @@ import org.smartregister.reporting.BaseUnitTest; import org.smartregister.reporting.R; import org.smartregister.reporting.domain.NumericIndicatorVisualization; -import org.smartregister.reporting.factory.NumericDisplayFactory; @PrepareForTest(LayoutInflater.class) public class NumericDisplayFactoryTest extends BaseUnitTest { diff --git a/opensrp-reporting/src/test/java/org/smartregister/reporting/view/PieChartFactoryTest.java b/opensrp-reporting/src/test/java/org/smartregister/reporting/factory/PieChartFactoryTest.java similarity index 96% rename from opensrp-reporting/src/test/java/org/smartregister/reporting/view/PieChartFactoryTest.java rename to opensrp-reporting/src/test/java/org/smartregister/reporting/factory/PieChartFactoryTest.java index 0ad4eeb1..d18e7cdf 100644 --- a/opensrp-reporting/src/test/java/org/smartregister/reporting/view/PieChartFactoryTest.java +++ b/opensrp-reporting/src/test/java/org/smartregister/reporting/factory/PieChartFactoryTest.java @@ -1,4 +1,4 @@ -package org.smartregister.reporting.view; +package org.smartregister.reporting.factory; import android.content.Context; import android.view.LayoutInflater; @@ -21,7 +21,6 @@ import org.smartregister.reporting.R; import org.smartregister.reporting.domain.PieChartIndicatorData; import org.smartregister.reporting.domain.PieChartIndicatorVisualization; -import org.smartregister.reporting.factory.PieChartFactory; import lecho.lib.hellocharts.view.PieChartView; diff --git a/opensrp-reporting/src/test/java/org/smartregister/reporting/factory/TableDisplayFactoryTest.java b/opensrp-reporting/src/test/java/org/smartregister/reporting/factory/TableDisplayFactoryTest.java new file mode 100644 index 00000000..dfe13519 --- /dev/null +++ b/opensrp-reporting/src/test/java/org/smartregister/reporting/factory/TableDisplayFactoryTest.java @@ -0,0 +1,64 @@ +package org.smartregister.reporting.factory; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.robolectric.RuntimeEnvironment; +import org.smartregister.reporting.BaseUnitTest; +import org.smartregister.reporting.R; +import org.smartregister.reporting.domain.TabularVisualization; +import org.smartregister.reporting.view.TableView; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@PrepareForTest(LayoutInflater.class) +public class TableDisplayFactoryTest extends BaseUnitTest { + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + private Context context; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + context = RuntimeEnvironment.application; + } + + @Test + public void getTableDisplayIndicatorViewReturnsCorrectView() { + List tableHeaderList = Arrays.asList("Vaccine Name", "Gender", "Value"); + TabularVisualization tabularVisualization = new TabularVisualization(R.string.table_data_title, tableHeaderList, getDummyData(), true); + + TableDisplayFactory displayFactory = new TableDisplayFactory(); + View view = displayFactory.getIndicatorView(tabularVisualization, context); + + Assert.assertNotNull(view); + TextView tableTitle = view.findViewById(R.id.tableViewTitle); + TableView tableView = view.findViewById(R.id.tableView); + + Assert.assertNotNull(tableTitle); + Assert.assertNotNull(tableView); + Assert.assertEquals(context.getString(R.string.table_data_title), tableTitle.getText()); + } + + private List getDummyData() { + List list = new ArrayList<>(); + list.add("BCG"); + list.add("Female"); + list.add(String.valueOf(2500)); + return list; + } +} diff --git a/opensrp-reporting/src/test/java/org/smartregister/reporting/repository/DailyIndicatorCountRepositoryTest.java b/opensrp-reporting/src/test/java/org/smartregister/reporting/repository/DailyIndicatorCountRepositoryTest.java index 68d2a55d..80809472 100644 --- a/opensrp-reporting/src/test/java/org/smartregister/reporting/repository/DailyIndicatorCountRepositoryTest.java +++ b/opensrp-reporting/src/test/java/org/smartregister/reporting/repository/DailyIndicatorCountRepositoryTest.java @@ -133,6 +133,12 @@ public void getAllDailyTalliesInvokesReadableDBQuery() { .rawQuery(ArgumentMatchers.anyString(), ArgumentMatchers.isNull(String[].class)); } + @Test + public void getLatestIndicatorTalliesInvokesReadableDBQuery() { + dailyIndicatorCountRepositorySpy.getLatestIndicatorTallies(); + Mockito.verify(sqLiteDatabase, Mockito.times(1)).rawQuery(ArgumentMatchers.anyString(), ArgumentMatchers.isNull()); + } + @Test public void getAllDailyTalliesShouldProcessAndReturnIndicatorTallies() { MatrixCursor matrixCursor = new MatrixCursor(new String[]{"_id", "indicator_code", "indicator_value" diff --git a/opensrp-reporting/src/test/java/org/smartregister/reporting/view/ProgressIndicatorViewTest.java b/opensrp-reporting/src/test/java/org/smartregister/reporting/view/ProgressIndicatorViewTest.java index e5f2ff2b..363c5d47 100644 --- a/opensrp-reporting/src/test/java/org/smartregister/reporting/view/ProgressIndicatorViewTest.java +++ b/opensrp-reporting/src/test/java/org/smartregister/reporting/view/ProgressIndicatorViewTest.java @@ -34,7 +34,7 @@ public void setUp() { } @Test - public void testConstructorsInstantiateSuccesfully() { + public void testConstructorsInstantiateSuccessfully() { ProgressIndicatorView view = new ProgressIndicatorView(RuntimeEnvironment.application); Assert.assertNotNull(view); diff --git a/opensrp-reporting/src/test/java/org/smartregister/reporting/view/ReportingTableViewTest.java b/opensrp-reporting/src/test/java/org/smartregister/reporting/view/ReportingTableViewTest.java new file mode 100644 index 00000000..e60d422a --- /dev/null +++ b/opensrp-reporting/src/test/java/org/smartregister/reporting/view/ReportingTableViewTest.java @@ -0,0 +1,32 @@ +package org.smartregister.reporting.view; + +import android.content.Context; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.smartregister.reporting.BaseUnitTest; +import org.smartregister.reporting.domain.TabularVisualization; + +public class ReportingTableViewTest extends BaseUnitTest { + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + private Context context; + + @Before + public void setUp() { + context = Mockito.mock(Context.class); + } + + @Test + public void reportingTableViewInstanceInitializesCorrectly() { + ReportingTableView tableView = new ReportingTableView(context, Mockito.mock(TabularVisualization.class)); + Assert.assertNotNull(tableView); + } +} diff --git a/opensrp-reporting/src/test/java/org/smartregister/reporting/view/TableViewTest.java b/opensrp-reporting/src/test/java/org/smartregister/reporting/view/TableViewTest.java index 0fa3db50..e669a806 100644 --- a/opensrp-reporting/src/test/java/org/smartregister/reporting/view/TableViewTest.java +++ b/opensrp-reporting/src/test/java/org/smartregister/reporting/view/TableViewTest.java @@ -28,7 +28,6 @@ public class TableViewTest extends BaseUnitTest { @Before public void setUp() { - MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this); attributeSet = Robolectric.buildAttributeSet() .addAttribute(R.attr.subtitle, "subtitle") diff --git a/sample/src/main/java/org/smartregister/sample/view/DashboardFragment.java b/sample/src/main/java/org/smartregister/sample/view/DashboardFragment.java index 38d2f06d..253cc88e 100644 --- a/sample/src/main/java/org/smartregister/sample/view/DashboardFragment.java +++ b/sample/src/main/java/org/smartregister/sample/view/DashboardFragment.java @@ -16,15 +16,21 @@ import org.smartregister.reporting.contract.ReportContract; import org.smartregister.reporting.domain.IndicatorTally; import org.smartregister.reporting.domain.PieChartSlice; +import org.smartregister.reporting.domain.TabularVisualization; import org.smartregister.reporting.model.NumericDisplayModel; import org.smartregister.reporting.view.NumericIndicatorView; import org.smartregister.reporting.view.PieChartIndicatorView; +import org.smartregister.reporting.view.ReportingTableView; import org.smartregister.sample.R; import org.smartregister.sample.presenter.SamplePresenter; import org.smartregister.sample.utils.ChartUtil; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.UUID; import static org.smartregister.reporting.contract.ReportContract.IndicatorView.CountType.LATEST_COUNT; import static org.smartregister.reporting.contract.ReportContract.IndicatorView.CountType.TOTAL_COUNT; @@ -38,6 +44,7 @@ public class DashboardFragment extends Fragment implements ReportContract.View, private static ReportContract.Presenter presenter; private ViewGroup visualizationsViewGroup; private List> indicatorTallies; + Random random = new Random(); public DashboardFragment() { // Required empty public constructor @@ -113,6 +120,33 @@ private void createSampleReportViews(ViewGroup mainLayout) { NumericDisplayModel floatIndicatorCount = getIndicatorDisplayModel(TOTAL_COUNT, "S_IND_005", R.string.float_count, indicatorTallies); mainLayout.addView(new NumericIndicatorView(getContext(), floatIndicatorCount).createView()); + + int tableTitleStringResource = R.string.table_data_title; + List tableHeaderList = Arrays.asList("Vaccine Name", "Gender", "Value"); + TabularVisualization tabularVisualization = new TabularVisualization(tableTitleStringResource, tableHeaderList, getDummyData(), true); + mainLayout.addView(new ReportingTableView(getContext(), tabularVisualization).createView()); + } + + private List getDummyData() { + List list = new ArrayList<>(); + for (Integer i = 0; i < 10; i++) { + list.add((i < 3 ? "BCG " : i > 6 ? "OPV " : "PENTA ") + i); + list.add(getRange(1, 2) == 2 ? "Female" : "Male"); + list.add(String.valueOf(getRange(500, 3000))); + } + return list; + } + + private List getDummyDataIds() { + List list = new ArrayList<>(); + for (Integer i = 0; i < 10; i++) { + list.add(UUID.randomUUID().toString()); + } + return list; + } + + private int getRange(int min, int max) { + return random.nextInt((max - min) + 1) + min; } @NonNull diff --git a/sample/src/main/res/layout/fragment_dashboard.xml b/sample/src/main/res/layout/fragment_dashboard.xml index 5cfa8fc8..429d3abf 100644 --- a/sample/src/main/res/layout/fragment_dashboard.xml +++ b/sample/src/main/res/layout/fragment_dashboard.xml @@ -4,10 +4,15 @@ android:layout_height="match_parent" tools:context=".view.DashboardFragment"> - + + + + diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index b386066c..d9e063eb 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -10,4 +10,6 @@ Hello blank fragment + + Table data