From d71c50150efab0fb4350d1919ae3941c4e4b0e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sat, 28 Sep 2024 16:40:38 +0100 Subject: [PATCH] Dashboard: Show widgets preview in preferences --- .../activities/DashboardFragment.java | 1 + .../DashboardPreferencesActivity.java | 15 ++ .../dashboard/AbstractDashboardWidget.java | 10 +- .../dashboard/DashboardGoalsWidget.java | 14 +- .../dashboard/DashboardTodayWidget.java | 23 +-- .../DashboardWidgetPreviewPreference.java | 97 +++++++++++++ .../layout/dashboard_widget_preview_empty.xml | 7 + .../dashboard_widget_preview_preference.xml | 14 ++ app/src/main/res/values/attrs.xml | 4 + app/src/main/res/values/strings.xml | 1 + .../main/res/xml/dashboard_preferences.xml | 134 +++++++++++------- 11 files changed, 252 insertions(+), 68 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/preferences/DashboardWidgetPreviewPreference.java create mode 100644 app/src/main/res/layout/dashboard_widget_preview_empty.xml create mode 100644 app/src/main/res/layout/dashboard_widget_preview_preference.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DashboardFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DashboardFragment.java index 397100c4d..560bd7bc3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DashboardFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DashboardFragment.java @@ -238,6 +238,7 @@ public class DashboardFragment extends Fragment implements MenuProvider { if (widget == null) { continue; } + widget.reloadPreferences(); if ("today".equals(widgetName) || "goals".equals(widgetName)) { columnSpan = prefs.getBoolean("dashboard_widget_" + widgetName + "_2columns", true) ? 2 : 1; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DashboardPreferencesActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DashboardPreferencesActivity.java index cf2744761..fdd85f96e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DashboardPreferencesActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DashboardPreferencesActivity.java @@ -18,6 +18,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.content.Intent; import android.os.Bundle; +import android.os.Handler; import android.text.InputType; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -31,6 +32,7 @@ import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.preferences.DashboardWidgetPreviewPreference; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; public class DashboardPreferencesActivity extends AbstractSettingsActivityV2 { @@ -51,6 +53,9 @@ public class DashboardPreferencesActivity extends AbstractSettingsActivityV2 { public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { setPreferencesFromResource(R.xml.dashboard_preferences, rootKey); + final DashboardWidgetPreviewPreference previewToday = findPreference("dashboard_widget_preview_today"); + final DashboardWidgetPreviewPreference previewGoals = findPreference("dashboard_widget_preview_goals"); + setInputTypeFor("dashboard_widget_today_hr_interval", InputType.TYPE_CLASS_NUMBER); final MultiSelectListPreference dashboardDevices = findPreference("dashboard_devices_multiselect"); @@ -78,11 +83,21 @@ public class DashboardPreferencesActivity extends AbstractSettingsActivityV2 { "dashboard_devices_multiselect" ); Preference pref; + final Handler handler = new Handler(requireContext().getMainLooper()); for (String dashboardPref : dashboardPrefs) { pref = findPreference(dashboardPref); if (pref != null) { pref.setOnPreferenceChangeListener((preference, autoExportEnabled) -> { sendDashboardConfigChangedIntent(); + // Delay so preferences are persisted + handler.postDelayed(() -> { + if (previewToday != null) { + previewToday.refresh(); + } + if (previewGoals != null) { + previewGoals.refresh(); + } + }, 500); return true; }); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/AbstractDashboardWidget.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/AbstractDashboardWidget.java index f7652caa0..b813b734f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/AbstractDashboardWidget.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/AbstractDashboardWidget.java @@ -28,9 +28,6 @@ import androidx.fragment.app.Fragment; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.List; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -43,8 +40,6 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.GB; public abstract class AbstractDashboardWidget extends Fragment { - private static final Logger LOG = LoggerFactory.getLogger(AbstractDashboardWidget.class); - protected static String ARG_DASHBOARD_DATA = "dashboard_widget_argument_data"; protected DashboardData dashboardData; @@ -70,9 +65,14 @@ public abstract class AbstractDashboardWidget extends Fragment { } public void update() { + reloadPreferences(); fillData(); } + public void reloadPreferences() { + + } + protected abstract void fillData(); protected boolean isSupportedBy(final GBDevice device) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardGoalsWidget.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardGoalsWidget.java index 76b2b9090..65270272a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardGoalsWidget.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardGoalsWidget.java @@ -49,6 +49,7 @@ public class DashboardGoalsWidget extends AbstractDashboardWidget { private static final Logger LOG = LoggerFactory.getLogger(DashboardGoalsWidget.class); private View goalsView; private ImageView goalsChart; + private TextView legend; public DashboardGoalsWidget() { // Required empty public constructor @@ -75,7 +76,7 @@ public class DashboardGoalsWidget extends AbstractDashboardWidget { goalsChart = goalsView.findViewById(R.id.dashboard_goals_chart); // Initialize legend - TextView legend = goalsView.findViewById(R.id.dashboard_goals_legend); + legend = goalsView.findViewById(R.id.dashboard_goals_legend); SpannableString l_steps = new SpannableString("■ " + getString(R.string.steps)); l_steps.setSpan(new ForegroundColorSpan(color_activity), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); SpannableString l_distance = new SpannableString("■ " + getString(R.string.distance)); @@ -87,9 +88,6 @@ public class DashboardGoalsWidget extends AbstractDashboardWidget { SpannableStringBuilder legendBuilder = new SpannableStringBuilder(); legend.setText(legendBuilder.append(l_steps).append(" ").append(l_distance).append("\n").append(l_active_time).append(" ").append(l_sleep)); - Prefs prefs = GBApplication.getPrefs(); - legend.setVisibility(prefs.getBoolean("dashboard_widget_goals_legend", true) ? View.VISIBLE : View.GONE); - return goalsView; } @@ -99,6 +97,14 @@ public class DashboardGoalsWidget extends AbstractDashboardWidget { if (goalsChart != null) fillData(); } + @Override + public void reloadPreferences() { + super.reloadPreferences(); + + final Prefs prefs = GBApplication.getPrefs(); + legend.setVisibility(prefs.getBoolean("dashboard_widget_goals_legend", true) ? View.VISIBLE : View.GONE); + } + @Override protected void fillData() { if (goalsView == null) return; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardTodayWidget.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardTodayWidget.java index a25de6bb7..99100d7f1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardTodayWidget.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardTodayWidget.java @@ -70,6 +70,7 @@ public class DashboardTodayWidget extends AbstractDashboardWidget { private View todayView; private ImageView todayChart; + private TextView legend; private boolean mode_24h; @@ -92,18 +93,26 @@ public class DashboardTodayWidget extends AbstractDashboardWidget { return fragment; } + @Override + public void reloadPreferences() { + super.reloadPreferences(); + + final Prefs prefs = GBApplication.getPrefs(); + + // Determine whether to draw a single or a double chart. In case 24h mode is selected, + // use just the outer chart (chart_12_24) for all data. + mode_24h = prefs.getBoolean("dashboard_widget_today_24h", false); + + legend.setVisibility(prefs.getBoolean("dashboard_widget_today_legend", true) ? View.VISIBLE : View.GONE); + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { todayView = inflater.inflate(R.layout.dashboard_widget_today, container, false); todayChart = todayView.findViewById(R.id.dashboard_today_chart); - // Determine whether to draw a single or a double chart. In case 24h mode is selected, - // use just the outer chart (chart_12_24) for all data. - Prefs prefs = GBApplication.getPrefs(); - mode_24h = prefs.getBoolean("dashboard_widget_today_24h", false); - // Initialize legend - TextView legend = todayView.findViewById(R.id.dashboard_piechart_legend); + legend = todayView.findViewById(R.id.dashboard_piechart_legend); SpannableString l_not_worn = new SpannableString("■ " + getString(R.string.abstract_chart_fragment_kind_not_worn)); l_not_worn.setSpan(new ForegroundColorSpan(color_not_worn), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); SpannableString l_worn = new SpannableString("■ " + getString(R.string.activity_type_worn)); @@ -121,8 +130,6 @@ public class DashboardTodayWidget extends AbstractDashboardWidget { SpannableStringBuilder legendBuilder = new SpannableStringBuilder(); legend.setText(legendBuilder.append(l_not_worn).append(" ").append(l_worn).append("\n").append(l_activity).append(" ").append(l_exercise).append("\n").append(l_light_sleep).append(" ").append(l_deep_sleep).append(" ").append(l_rem_sleep)); - legend.setVisibility(prefs.getBoolean("dashboard_widget_today_legend", true) ? View.VISIBLE : View.GONE); - if (!dashboardData.generalizedActivities.isEmpty()) { draw(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/preferences/DashboardWidgetPreviewPreference.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/preferences/DashboardWidgetPreviewPreference.java new file mode 100644 index 000000000..e13d0111d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/preferences/DashboardWidgetPreviewPreference.java @@ -0,0 +1,97 @@ +package nodomain.freeyourgadget.gadgetbridge.activities.dashboard.preferences; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentContainerView; +import androidx.gridlayout.widget.GridLayout; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + +import java.util.GregorianCalendar; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.AbstractDashboardWidget; +import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.data.DashboardData; +import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.widgets.DashboardWidgetFactory; + +public class DashboardWidgetPreviewPreference extends Preference { + private final String widgetName; + private AbstractDashboardWidget widget; + private DashboardData dashboardData; + + public DashboardWidgetPreviewPreference(@NonNull final Context context, + @Nullable final AttributeSet attrs) { + super(context, attrs); + setPersistent(false); + + // Obtain custom attributes + try (TypedArray a = context.getTheme().obtainStyledAttributes( + attrs, + R.styleable.DashboardWidgetPreviewPreference, + 0, 0)) { + if (attrs != null) { + widgetName = a.getString(R.styleable.DashboardWidgetPreviewPreference_widgetName); + } else { + widgetName = null; + } + } + setLayoutResource(R.layout.dashboard_widget_preview_preference); + setWidgetLayoutResource(R.layout.dashboard_widget_preview_empty); + } + + @Override + public void onBindViewHolder(@NonNull final PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + + dashboardData = new DashboardData(); + dashboardData.reloadPreferences(GregorianCalendar.getInstance()); + + if (widget == null) { + widget = DashboardWidgetFactory.createWidget(widgetName, dashboardData); + if (widget == null) { + return; + } + } + + final FragmentActivity activity = (FragmentActivity) getContext(); + + final int columnSpan = 1; + + final GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams( + GridLayout.spec(GridLayout.UNDEFINED, GridLayout.FILL, 1f), + GridLayout.spec(GridLayout.UNDEFINED, columnSpan, GridLayout.FILL, 1f) + ); + final float scale = activity.getResources().getDisplayMetrics().density; + layoutParams.width = 0; + final int pixels_8dp = (int) (8 * scale + 0.5f); + layoutParams.setMargins(pixels_8dp, pixels_8dp, pixels_8dp, pixels_8dp); + + final FragmentContainerView fragment = new FragmentContainerView(activity); + int fragmentId = View.generateViewId(); + fragment.setId(fragmentId); + fragment.setLayoutParams(layoutParams); + + activity.getSupportFragmentManager() + .beginTransaction() + .replace(fragmentId, widget) + .commitAllowingStateLoss(); + + final GridLayout gridlayout = (GridLayout) holder.findViewById(R.id.widget_preview_gridlayout); + gridlayout.addView(fragment); + } + + public void refresh() { + if (dashboardData != null) { + dashboardData.reloadPreferences(GregorianCalendar.getInstance()); + } + if (widget != null) { + widget.update(); + } + } +} diff --git a/app/src/main/res/layout/dashboard_widget_preview_empty.xml b/app/src/main/res/layout/dashboard_widget_preview_empty.xml new file mode 100644 index 000000000..f92ac88f8 --- /dev/null +++ b/app/src/main/res/layout/dashboard_widget_preview_empty.xml @@ -0,0 +1,7 @@ + + + + diff --git a/app/src/main/res/layout/dashboard_widget_preview_preference.xml b/app/src/main/res/layout/dashboard_widget_preview_preference.xml new file mode 100644 index 000000000..e503e23c9 --- /dev/null +++ b/app/src/main/res/layout/dashboard_widget_preview_preference.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 4b2f6715e..83068890a 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -22,4 +22,8 @@ + + + + \ 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 0d9b7be65..604c90254 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2916,6 +2916,7 @@ Title Description Preview image + Preview Status icon Changelog More… diff --git a/app/src/main/res/xml/dashboard_preferences.xml b/app/src/main/res/xml/dashboard_preferences.xml index dc8add63b..331e27e94 100644 --- a/app/src/main/res/xml/dashboard_preferences.xml +++ b/app/src/main/res/xml/dashboard_preferences.xml @@ -39,62 +39,94 @@ android:key="pref_key_dashboard_today" android:title="@string/pref_dashboard_widget_today_title" app:iconSpaceReserved="false"> - - - - - + + + + + + + + + + + - - + + + + + + + +