From e848a7cb71e2fd47f08e80319c36cf4ebe93e863 Mon Sep 17 00:00:00 2001 From: vanous Date: Wed, 3 Mar 2021 19:03:02 +0100 Subject: [PATCH] Add Activity list dashboard summary calculations Accessible via FAB in Activity list Adds DebugActivity checkbox to show large date range --- .../activities/DebugActivity.java | 16 + .../charts/AbstractChartFragment.java | 5 + .../charts/ActivityListingAdapter.java | 16 + .../charts/ActivityListingChartFragment.java | 30 +- .../charts/ActivityListingDashboard.java | 327 ++++++++++++++++++ .../activities/charts/StepAnalysis.java | 11 +- .../AbstractActivityListingAdapter.java | 12 + .../adapter/ActivitySummariesAdapter.java | 3 + .../gadgetbridge/database/DBAccess.java | 3 + .../gadgetbridge/model/ActivitySession.java | 11 + app/src/main/res/drawable/ic_insights.xml | 4 + .../main/res/layout/activity_battery_info.xml | 162 +-------- app/src/main/res/layout/activity_debug.xml | 19 +- .../layout/activity_list_total_dashboard.xml | 87 +++++ .../main/res/layout/fragment_steps_list.xml | 7 +- .../layout_widget_duration_selector.xml | 161 +++++++++ app/src/main/res/values/strings.xml | 3 +- 17 files changed, 697 insertions(+), 180 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingDashboard.java create mode 100644 app/src/main/res/drawable/ic_insights.xml create mode 100644 app/src/main/res/layout/activity_list_total_dashboard.xml create mode 100644 app/src/main/res/layout/layout_widget_duration_selector.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index b6ba06589..094aee773 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -37,6 +37,8 @@ import android.view.MenuItem; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.DatePicker; import android.widget.EditText; import android.widget.Spinner; @@ -371,6 +373,20 @@ public class DebugActivity extends AbstractGBActivity { } }); + CheckBox activity_list_debug_extra_time_range = findViewById(R.id.activity_list_debug_extra_time_range); + activity_list_debug_extra_time_range.setAllCaps(true); + boolean activity_list_debug_extra_time_range_value = GBApplication.getPrefs().getPreferences().getBoolean("activity_list_debug_extra_time_range", false); + activity_list_debug_extra_time_range.setChecked(activity_list_debug_extra_time_range_value); + + activity_list_debug_extra_time_range.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + GBApplication.getPrefs().getPreferences().getBoolean("activity_list_debug_extra_time_range", false); + SharedPreferences.Editor editor = GBApplication.getPrefs().getPreferences().edit(); + editor.putBoolean("activity_list_debug_extra_time_range", b).apply(); + } + }); + } private void deleteWidgetsPrefs() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index 5f98a2d36..68e67b08b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -661,6 +661,11 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } } + @Override + protected void onPreExecute() { + + } + @Override protected void onPostExecute(Object o) { super.onPostExecute(o); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingAdapter.java index 6a6f524a3..e0a4b094a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingAdapter.java @@ -38,6 +38,7 @@ public class ActivityListingAdapter extends AbstractActivityListingAdapter 999000) { + distanceFormatted = distanceMeters / 1000; + unit = "###km"; + } + String units = GBApplication.getPrefs().getString(SettingsActivity.PREF_MEASUREMENT_SYSTEM, GBApplication.getContext().getString(R.string.p_unit_metric)); if (units.equals(GBApplication.getContext().getString(R.string.p_unit_imperial))) { unit = "###ft"; @@ -265,6 +271,10 @@ public class ActivityListingAdapter extends AbstractActivityListingAdapter 5274721) { + distanceFormatted = distanceFeet * 0.0001893939f; + unit = "###mi"; + } } DecimalFormat df = new DecimalFormat(unit); return df.format(distanceFormatted); @@ -339,6 +349,12 @@ public class ActivityListingAdapter extends AbstractActivityListingAdapter stepSessions; private final ActivitySession ongoingSession; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingDashboard.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingDashboard.java new file mode 100644 index 000000000..1425a8566 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingDashboard.java @@ -0,0 +1,327 @@ +package nodomain.freeyourgadget.gadgetbridge.activities.charts; + +import android.app.DatePickerDialog; +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.DatePicker; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.SeekBar; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentActivity; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.database.DBAccess; +import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession; +import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; +import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; + +public class ActivityListingDashboard extends DialogFragment { + protected static final Logger LOG = LoggerFactory.getLogger(AbstractWeekChartFragment.class); + GBDevice gbDevice; + ActivityListingAdapter stepListAdapter; + ActivitySession stepSessionsSummary; + private int timeFrom; + private int timeTo; + private View fragmentView; + + public ActivityListingDashboard() { + + } + + public static ActivityListingDashboard newInstance(int timestamp, GBDevice device) { + + ActivityListingDashboard frag = new ActivityListingDashboard(); + + Bundle args = new Bundle(); + args.putInt("time", timestamp); + args.putParcelable(GBDevice.EXTRA_DEVICE, device); + frag.setArguments(args); + return frag; + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + + Bundle savedInstanceState) { + + return inflater.inflate(R.layout.activity_list_total_dashboard, container); + + } + + @Override + + public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) { + + super.onViewCreated(view, savedInstanceState); + + int time = getArguments().getInt("time", 1); + Calendar day = Calendar.getInstance(); + day.setTimeInMillis(time * 1000L); + day.set(Calendar.HOUR_OF_DAY, 23); + day.set(Calendar.MINUTE, 59); + day.set(Calendar.SECOND, 59); + timeTo = (int) (day.getTimeInMillis() / 1000); + + + gbDevice = getArguments().getParcelable(GBDevice.EXTRA_DEVICE); + if (gbDevice == null) { + throw new IllegalArgumentException("Must provide a device when invoking this activity"); + } + stepListAdapter = new ActivityListingAdapter(getContext()); + fragmentView = view; + + final TextView battery_status_date_from_text = (TextView) view.findViewById(R.id.battery_status_date_from_text); + final TextView battery_status_date_to_text = (TextView) view.findViewById(R.id.battery_status_date_to_text); + LinearLayout battery_status_date_to_layout = (LinearLayout) view.findViewById(R.id.battery_status_date_to_layout); + final SeekBar battery_status_time_span_seekbar = (SeekBar) view.findViewById(R.id.battery_status_time_span_seekbar); + + boolean activity_list_debug_extra_time_range_value = GBApplication.getPrefs().getPreferences().getBoolean("activity_list_debug_extra_time_range", false); + + if (!activity_list_debug_extra_time_range_value) { + battery_status_time_span_seekbar.setMax(3); + } + final TextView battery_status_time_span_text = (TextView) view.findViewById(R.id.battery_status_time_span_text); + + battery_status_time_span_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) { + String text; + switch (i) { + case 0: + text = getString(R.string.calendar_day); + timeFrom = shiftDateBackDays(timeTo, 1); + break; + case 1: + text = getString(R.string.calendar_week); + timeFrom = shiftDateBackDays(timeTo, 7); + break; + case 2: + text = getString(R.string.calendar_two_weeks); + timeFrom = shiftDateBackDays(timeTo, 14); + break; + case 3: + text = getString(R.string.calendar_month); + timeFrom = subtractMonths(timeTo, -1); + break; + case 4: + text = getString(R.string.calendar_three_months); + timeFrom = subtractMonths(timeTo, -3); + break; + case 5: + text = getString(R.string.calendar_six_months); + timeFrom = subtractMonths(timeTo, -6); + break; + case 6: + text = getString(R.string.calendar_year); + timeFrom = subtractMonths(timeTo, -12); + break; + default: + text = getString(R.string.calendar_two_weeks); + timeFrom = shiftDateBackDays(timeTo, 14); + + } + + battery_status_time_span_text.setText(text); + battery_status_date_from_text.setText(DateTimeUtils.formatDate(new Date(timeFrom * 1000L))); + battery_status_date_to_text.setText(DateTimeUtils.formatDate(new Date(timeTo * 1000L))); + createRefreshTask("Visualizing data", getActivity()).execute(); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + + } + }); + battery_status_date_to_layout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final Calendar currentDate = Calendar.getInstance(); + currentDate.setTimeInMillis(timeTo * 1000L); + + new DatePickerDialog(getContext(), new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { + + Calendar date = Calendar.getInstance(); + date.set(year, monthOfYear, dayOfMonth); + int time = (int) (date.getTimeInMillis() / 1000); + Calendar day = Calendar.getInstance(); + day.setTimeInMillis(time * 1000L); + day.set(Calendar.HOUR_OF_DAY, 23); + day.set(Calendar.MINUTE, 59); + day.set(Calendar.SECOND, 59); + timeTo = (int) (day.getTimeInMillis() / 1000); + + battery_status_date_to_text.setText(DateTimeUtils.formatDate(new Date(timeTo * 1000L))); + battery_status_time_span_seekbar.setProgress(0); + battery_status_time_span_seekbar.setProgress(1); + } + }, currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE)).show(); + } + }); + battery_status_time_span_seekbar.setProgress(2); + } + + private int subtractMonths(int timeTo, int month) { + Calendar day = Calendar.getInstance(); + day.setTimeInMillis(timeTo * 1000L); + day.add(Calendar.MONTH, month); + return (int) (day.getTimeInMillis() / 1000); + } + + private int daysBetweenTimes(int time1, int time2) { + return (int) TimeUnit.MILLISECONDS.toDays((time2 - time1) * 1000L); + } + + private int shiftDateBackDays(int timeTo, int days) { + int time = timeTo - ((24 * 3600) - 1) * days; + Calendar day = Calendar.getInstance(); + day.setTimeInMillis(time * 1000L); + day.set(Calendar.HOUR_OF_DAY, 0); + day.set(Calendar.MINUTE, 0); + day.set(Calendar.SECOND, 0); + return (int) (day.getTimeInMillis() / 1000); + } + + protected RefreshTask createRefreshTask(String task, Context context) { + return new RefreshTask(task, context); + } + + private ActivitySession get_data(GBDevice gbDevice, DBHandler db, int timeFrom, int timeTo) { + + List stepSessions; + List activitySamples = getAllSamples(db, gbDevice, timeFrom, timeTo); + StepAnalysis stepAnalysis = new StepAnalysis(); + + boolean isEmptySummary = false; + if (activitySamples != null) { + stepSessions = stepAnalysis.calculateStepSessions(activitySamples); + if (stepSessions.toArray().length == 0) { + isEmptySummary = true; + } + stepSessionsSummary = stepAnalysis.calculateSummary(stepSessions, isEmptySummary); + } + return stepSessionsSummary; + } + + SampleProvider getProvider(DBHandler db, GBDevice device) { + DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(device); + return coordinator.getSampleProvider(device, db.getDaoSession()); + } + + protected List getAllSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) { + SampleProvider provider = getProvider(db, device); + return provider.getAllActivitySamples(tsFrom, tsTo); + } + + void indicate_progress(boolean inProgress) { + LinearLayout activity_list_dashboard_results_layout = fragmentView.findViewById(R.id.activity_list_dashboard_results_layout); + RelativeLayout activity_list_dashboard_loading_layout = fragmentView.findViewById(R.id.activity_list_dashboard_loading_layout); + if (inProgress) { + activity_list_dashboard_results_layout.setVisibility(View.GONE); + activity_list_dashboard_loading_layout.setVisibility(View.VISIBLE); + } else { + activity_list_dashboard_results_layout.setVisibility(View.VISIBLE); + activity_list_dashboard_loading_layout.setVisibility(View.GONE); + } + } + + void populateData(ActivitySession item) { + TextView stepLabel = fragmentView.findViewById(R.id.line_layout_step_label); + TextView stepTotalLabel = fragmentView.findViewById(R.id.line_layout_total_step_label); + TextView distanceLabel = fragmentView.findViewById(R.id.line_layout_distance_label); + TextView durationLabel = fragmentView.findViewById(R.id.line_layout_duration_label); + TextView sessionCountLabel = fragmentView.findViewById(R.id.line_layout_count_label); + LinearLayout durationLayout = fragmentView.findViewById(R.id.line_layout_duration); + LinearLayout countLayout = fragmentView.findViewById(R.id.line_layout_count); + LinearLayout stepsLayout = fragmentView.findViewById(R.id.line_layout_step); + LinearLayout stepsTotalLayout = fragmentView.findViewById(R.id.line_layout_total_step); + LinearLayout distanceLayout = fragmentView.findViewById(R.id.line_layout_distance); + + stepLabel.setText(stepListAdapter.getStepLabel(item)); + stepTotalLabel.setText(stepListAdapter.getStepTotalLabel(item)); + distanceLabel.setText(stepListAdapter.getDistanceLabel(item)); + durationLabel.setText(stepListAdapter.getDurationLabel(item)); + sessionCountLabel.setText(stepListAdapter.getSessionCountLabel(item)); + + if (!stepListAdapter.hasDistance(item)) { + distanceLayout.setVisibility(View.GONE); + } else { + distanceLayout.setVisibility(View.VISIBLE); + } + + if (!stepListAdapter.hasSteps(item)) { + stepsLayout.setVisibility(View.GONE); + } else { + stepsLayout.setVisibility(View.VISIBLE); + } + + if (!stepListAdapter.hasTotalSteps(item)) { + stepsTotalLayout.setVisibility(View.GONE); + countLayout.setVisibility(View.GONE); + durationLayout.setVisibility(View.GONE); + } else { + stepsTotalLayout.setVisibility(View.VISIBLE); + countLayout.setVisibility(View.VISIBLE); + durationLayout.setVisibility(View.VISIBLE); + } + } + + public class RefreshTask extends DBAccess { + + public RefreshTask(String task, Context context) { + super(task, context); + } + + @Override + protected void doInBackground(DBHandler db) { + stepSessionsSummary = get_data(gbDevice, db, timeFrom, timeTo); + } + + @Override + protected void onPreExecute() { + indicate_progress(true); + } + + @Override + protected void onPostExecute(Object o) { + super.onPostExecute(o); + FragmentActivity activity = getActivity(); + if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { + populateData(stepSessionsSummary); + indicate_progress(false); + } else { + LOG.info("Not filling data because activity is not available anymore"); + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepAnalysis.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepAnalysis.java index f5986ad92..ca5cfde97 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepAnalysis.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepAnalysis.java @@ -35,6 +35,7 @@ public class StepAnalysis { private int totalDailySteps = 0; public List calculateStepSessions(List samples) { + LOG.debug("get all samples activitysessions: " + samples.toArray().length); List result = new ArrayList<>(); ActivityUser activityUser = new ActivityUser(); double STEP_LENGTH_M; @@ -154,7 +155,7 @@ public class StepAnalysis { return result; } - public List calculateSummary(List sessions, boolean empty) { + public ActivitySession calculateSummary(List sessions, boolean empty) { Date startTime = null; Date endTime = null; @@ -164,7 +165,7 @@ public class StepAnalysis { int distanceSum = 0; float intensitySum = 0; int sessionCount; - int durationSum = 0; + long durationSum = 0; for (ActivitySession session : sessions) { startTime = session.getStartTime(); @@ -192,11 +193,7 @@ public class StepAnalysis { stepSessionSummary.setTotalDaySteps(totalDailySteps); - - List newList = new ArrayList<>(); - newList.add(stepSessionSummary); - newList.addAll(sessions); - return newList; + return stepSessionSummary; } public ActivitySession getOngoingSessions(List sessions) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/AbstractActivityListingAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/AbstractActivityListingAdapter.java index 018d5f1bb..a14d752ef 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/AbstractActivityListingAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/AbstractActivityListingAdapter.java @@ -76,6 +76,8 @@ public abstract class AbstractActivityListingAdapter extends ArrayAdapter if (isSummary(item, position)) { view = fill_dashboard(item, position, view, parent, context); + } else if (isEmptySession(item, position)) { + view = fill_empty(item, position, view, parent); } else { view = fill_item(item, position, view, parent); } @@ -174,6 +176,14 @@ public abstract class AbstractActivityListingAdapter extends ArrayAdapter return view; } + private View fill_empty(T item, int position, View view, ViewGroup parent) { + view = null; + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + view = inflater.inflate(R.layout.activity_list_item, parent, false); + view.setVisibility(View.GONE); + return view; + } protected abstract View fill_dashboard(T item, int position, View view, ViewGroup parent, Context context); @@ -215,6 +225,8 @@ public abstract class AbstractActivityListingAdapter extends ArrayAdapter protected abstract boolean isSummary(T item, int position); + protected abstract boolean isEmptySession(T item, int position); + protected abstract boolean isEmptySummary(T item); protected abstract String getStepTotalLabel(T item); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ActivitySummariesAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ActivitySummariesAdapter.java index 85b972265..0e608040e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ActivitySummariesAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ActivitySummariesAdapter.java @@ -397,6 +397,9 @@ public class ActivitySummariesAdapter extends AbstractActivityListingAdapter + + + diff --git a/app/src/main/res/layout/activity_battery_info.xml b/app/src/main/res/layout/activity_battery_info.xml index 087f6a2f7..5f38221cb 100644 --- a/app/src/main/res/layout/activity_battery_info.xml +++ b/app/src/main/res/layout/activity_battery_info.xml @@ -84,167 +84,7 @@ android:layout_height="350dp" /> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_debug.xml b/app/src/main/res/layout/activity_debug.xml index 6452547a1..f7a5683e1 100644 --- a/app/src/main/res/layout/activity_debug.xml +++ b/app/src/main/res/layout/activity_debug.xml @@ -1,4 +1,5 @@ - + + diff --git a/app/src/main/res/layout/activity_list_total_dashboard.xml b/app/src/main/res/layout/activity_list_total_dashboard.xml new file mode 100644 index 000000000..2ce1edb9b --- /dev/null +++ b/app/src/main/res/layout/activity_list_total_dashboard.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_steps_list.xml b/app/src/main/res/layout/fragment_steps_list.xml index 10a798c2b..609d41321 100644 --- a/app/src/main/res/layout/fragment_steps_list.xml +++ b/app/src/main/res/layout/fragment_steps_list.xml @@ -22,9 +22,8 @@ android:layout_height="wrap_content" android:layout_below="@id/stepsDateView" android:layout_alignParentBottom="false" + android:layout_marginBottom="0dp" android:layout_marginTop="0dp"> - - + android:layout_marginBottom="9dp" + app:srcCompat="@drawable/ic_insights" /> diff --git a/app/src/main/res/layout/layout_widget_duration_selector.xml b/app/src/main/res/layout/layout_widget_duration_selector.xml new file mode 100644 index 000000000..ac697059f --- /dev/null +++ b/app/src/main/res/layout/layout_widget_duration_selector.xml @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 26e915c2a..ca9597aae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,7 +32,8 @@ Week Two weeks Month - Six months + 3 months + 6 months Year Debug